MDL-82503 badges: Prepare and make index.php default page

The badges/index.php and badges/view.php pages are quite similar and
have been merged into index.php.
This commit updates index.php to incorporate the missing information
previously found in view.php.
This commit is contained in:
Sara Arjona 2024-08-13 17:16:48 +02:00
parent 13c12756b4
commit 4cdeb79566
No known key found for this signature in database
12 changed files with 211 additions and 57 deletions

View File

@ -165,7 +165,7 @@ class backup_course_task extends backup_task {
// A few other key course links.
$content = self::encode_links_helper($content, 'GRADEINDEXBYID', '/grade/index.php?id=');
$content = self::encode_links_helper($content, 'GRADEREPORTINDEXBYID', '/grade/report/index.php?id=');
$content = self::encode_links_helper($content, 'BADGESVIEWBYID', '/badges/view.php?type=2&id=');
$content = self::encode_links_helper($content, 'BADGESVIEWBYID', '/badges/index.php?type=2&id=');
$content = self::encode_links_helper($content, 'USERINDEXVIEWBYID', '/user/index.php?id=');
$content = self::encode_links_helper($content, 'PLUGINFILEBYCONTEXT', '/pluginfile.php/');
$content = self::encode_links_helper($content, 'PLUGINFILEBYCONTEXTURLENCODED', '/pluginfile.php/', true);

View File

@ -164,7 +164,7 @@ class restore_course_task extends restore_task {
// A few other key course links.
$rules[] = new restore_decode_rule('GRADEINDEXBYID', '/grade/index.php?id=$1', 'course');
$rules[] = new restore_decode_rule('GRADEREPORTINDEXBYID', '/grade/report/index.php?id=$1', 'course');
$rules[] = new restore_decode_rule('BADGESVIEWBYID', '/badges/view.php?type=2&id=$1', 'course');
$rules[] = new restore_decode_rule('BADGESVIEWBYID', '/badges/index.php?type=2&id=$1', 'course');
$rules[] = new restore_decode_rule('USERINDEXVIEWBYID', '/user/index.php?id=$1', 'course');
$rules[] = new restore_decode_rule('PLUGINFILEBYCONTEXT', '/pluginfile.php/$1', 'context');
$rules[] = new restore_decode_rule('PLUGINFILEBYCONTEXTURLENCODED', '/pluginfile.php/$1', 'context', true);

View File

@ -54,7 +54,7 @@ class backup_encode_content_test extends \basic_testcase {
$httpsroot . '/course/view.php?id=123, ' .
$httpsroot . '/grade/index.php?id=123, ' .
$httpsroot . '/grade/report/index.php?id=123, ' .
$httpsroot . '/badges/view.php?type=2&id=123, ' .
$httpsroot . '/badges/index.php?type=2&id=123, ' .
$httpsroot . '/user/index.php?id=123, ' .
$httpsroot . '/pluginfile.php/123 and ' .
urlencode($httpsroot . '/pluginfile.php/123') . '.'
@ -70,7 +70,7 @@ class backup_encode_content_test extends \basic_testcase {
$httpsroot . '/course/view.php?id=123, ' .
$httproot . '/grade/index.php?id=123, ' .
$httproot . '/grade/report/index.php?id=123, ' .
$httproot . '/badges/view.php?type=2&id=123, ' .
$httproot . '/badges/index.php?type=2&id=123, ' .
$httproot . '/user/index.php?id=123, ' .
$httproot . '/pluginfile.php/123 and ' .
urlencode($httproot . '/pluginfile.php/123') . '.'

View File

@ -67,7 +67,10 @@ class manage_badge_action_bar extends base_action_bar {
$params['id'] = $this->page->context->instanceid;
}
$elements['button'] = new single_button(new moodle_url('/badges/index.php', $params), get_string('back'), 'get');
$elements['urlselect'] = new url_select($this->generate_badge_navigation(), $this->page->url->out(false), null);
$badgenav = $this->generate_badge_navigation();
if ($badgenav) {
$elements['urlselect'] = new url_select($badgenav, $this->page->url->out(false), null);
}
foreach ($elements as $key => $element) {
$elements[$key] = $element->export_for_template($output);
}
@ -132,6 +135,7 @@ class manage_badge_action_bar extends base_action_bar {
*/
protected function generate_badge_navigation(): array {
global $DB;
$params = ['id' => $this->badge->id];
$options = [];
$construct = $this->get_badge_administration_mapping_construct();
@ -168,6 +172,10 @@ class manage_badge_action_bar extends base_action_bar {
$url = new moodle_url($checks['url'], $params + ($checks['additionalparams'] ?? []));
$options[get_string($stringidentifier, 'core_badges', $content)] = $url->out(false);
}
if (count($options) <= 1) {
return [];
}
return array_flip($options);
}
}

View File

@ -20,6 +20,7 @@ namespace core_badges\reportbuilder\local\systemreports;
use core\context\{course, system};
use core_badges\reportbuilder\local\entities\badge;
use core_badges\reportbuilder\local\entities\badge_issued;
use core_reportbuilder\local\helpers\database;
use core_reportbuilder\local\report\{action, column};
use core_reportbuilder\system_report;
@ -50,6 +51,8 @@ class badges extends system_report {
* Initialise report, we need to set the main table, load our entities and set columns/filters
*/
protected function initialise(): void {
global $USER;
// Our main entity, it contains all of the column definitions that we need.
$badgeentity = new badge();
$entityalias = $badgeentity->get_table_alias('badge');
@ -69,14 +72,29 @@ class badges extends system_report {
[$paramtype => $type, $paramcourseid => $context->instanceid]);
}
if (!$this->can_view_draft_badges()) {
$this->add_base_condition_sql("({$entityalias}.status = " . BADGE_STATUS_ACTIVE .
" OR {$entityalias}.status = " . BADGE_STATUS_ACTIVE_LOCKED . ")");
}
// Any columns required by actions should be defined here to ensure they're always available.
$this->add_base_fields("{$entityalias}.id, {$entityalias}.type, {$entityalias}.courseid, {$entityalias}.status");
$badgeissuedentity = new badge_issued();
$badgeissuedalias = $badgeissuedentity->get_table_alias('badge_issued');
$this->add_entity($badgeissuedentity
->add_join("LEFT JOIN {badge_issued} {$badgeissuedalias}
ON {$entityalias}.id = {$badgeissuedalias}.badgeid AND {$badgeissuedalias}.userid = ".$USER->id)
);
$this->add_base_fields("{$badgeissuedalias}.uniquehash");
// Now we can call our helper methods to add the content we want to include in the report.
$this->add_columns();
$this->add_columns($badgeissuedalias);
$this->add_filters();
$this->add_actions();
// Set initial sorting by name.
$this->set_initial_sort_column('badge:namewithlink', SORT_ASC);
$this->set_default_no_results_notice(new lang_string('nomatchingbadges', 'core_badges'));
@ -91,6 +109,7 @@ class badges extends system_report {
*/
protected function can_view(): bool {
return has_any_capability([
'moodle/badges:viewbadges',
'moodle/badges:viewawarded',
'moodle/badges:createbadge',
'moodle/badges:awardbadge',
@ -105,47 +124,76 @@ class badges extends system_report {
*
* They are provided by the entities we previously added in the {@see initialise} method, referencing each by their
* unique identifier. If custom columns are needed just for this report, they can be defined here.
*
* @param string $badgeissuedalias
*/
protected function add_columns(): void {
$badgeentity = $this->get_entity('badge');
$this->add_columns_from_entities([
public function add_columns(string $badgeissuedalias): void {
$columns = [
'badge:image',
'badge:namewithlink',
'badge:version',
'badge:status',
'badge:criteria',
]);
];
// Issued badges column.
$tempbadgealias = database::generate_alias();
$badgeentityalias = $badgeentity->get_table_alias('badge');
$this->add_column((new column(
'issued',
new lang_string('awards', 'core_badges'),
$badgeentity->get_entity_name()
))
->add_joins($this->get_joins())
->set_type(column::TYPE_INTEGER)
->add_field("(SELECT COUNT({$tempbadgealias}.userid)
FROM {badge_issued} {$tempbadgealias}
INNER JOIN {user} u
ON {$tempbadgealias}.userid = u.id
WHERE {$tempbadgealias}.badgeid = {$badgeentityalias}.id AND u.deleted = 0)", 'issued')
->set_is_sortable(true)
->set_callback(function(int $count): string {
if (!has_capability('moodle/badges:viewawarded', $this->get_context())) {
return (string) $count;
}
return html_writer::link(new moodle_url('/badges/recipients.php', ['id' => $this->badgeid]), $count);
}));
$canviewdraftbadges = $this->can_view_draft_badges();
if (!$canviewdraftbadges) {
// Remove status and recipients column.
unset($columns[2]);
}
$this->add_columns_from_entities($columns);
// Remove title from image column.
$this->get_column('badge:image')->set_title(null);
// Change title from namewithlink column.
$this->get_column('badge:namewithlink')->set_title(new lang_string('name'));
// Recipients column.
if ($canviewdraftbadges) {
$badgeentity = $this->get_entity('badge');
$tempbadgealias = database::generate_alias();
$badgeentityalias = $badgeentity->get_table_alias('badge');
$this->add_column((new column(
'issued',
new lang_string('awards', 'core_badges'),
$badgeentity->get_entity_name()
))
->add_joins($this->get_joins())
->set_type(column::TYPE_INTEGER)
->add_field("(SELECT COUNT({$tempbadgealias}.userid)
FROM {badge_issued} {$tempbadgealias}
INNER JOIN {user} u
ON {$tempbadgealias}.userid = u.id
WHERE {$tempbadgealias}.badgeid = {$badgeentityalias}.id AND u.deleted = 0)", 'issued')
->set_is_sortable(true)
->set_callback(function(int $count): string {
if (!has_capability('moodle/badges:viewawarded', $this->get_context())) {
return (string) $count;
}
return html_writer::link(new moodle_url('/badges/recipients.php', ['id' => $this->badgeid]), $count);
}));
}
// Add the date the badge was issued at the end of the report.
$this->add_column_from_entity('badge_issued:issued');
$this->get_column('badge_issued:issued')
->set_title(new lang_string('awardedtoyou', 'core_badges'))
->add_fields("{$badgeissuedalias}.uniquehash")
->set_callback(static function(?int $value, stdClass $row) {
global $OUTPUT;
if (!$value) {
return '';
}
$format = get_string('strftimedatefullshort', 'core_langconfig');
$date = $value ? userdate($value, $format) : '';
$badgeurl = new moodle_url('/badges/badge.php', ['hash' => $row->uniquehash]);
$icon = new pix_icon('i/valid', get_string('dateearned', 'badges', $date));
return $OUTPUT->action_icon($badgeurl, $icon, null, null, true);
});
$this->set_initial_sort_column('badge:namewithlink', SORT_ASC);
}
/**
@ -155,12 +203,19 @@ class badges extends system_report {
* unique identifier
*/
protected function add_filters(): void {
$this->add_filters_from_entities([
$filters = [
'badge:name',
'badge:version',
'badge:status',
'badge:expiry',
]);
'badge_issued:issued',
];
if (!$this->can_view_draft_badges()) {
// Remove version and status filters.
unset($filters[1]);
unset($filters[2]);
}
$this->add_filters_from_entities($filters);
}
/**
@ -295,6 +350,22 @@ class badges extends system_report {
}
}
/**
* Check whether the user can view unpublished badges.
*
* @return bool True if the user can edit badges, false otherwise.
*/
private function can_view_draft_badges(): bool {
return has_any_capability([
'moodle/badges:viewawarded',
'moodle/badges:createbadge',
'moodle/badges:awardbadge',
'moodle/badges:configurecriteria',
'moodle/badges:configuremessages',
'moodle/badges:configuredetails',
'moodle/badges:deletebadge'], $this->get_context());
}
/**
* Store the ID of the badge within each row
*

View File

@ -48,13 +48,16 @@ if (empty($CFG->badges_allowcoursebadges) && ($type == BADGE_TYPE_COURSE)) {
throw new \moodle_exception('coursebadgesdisabled', 'badges');
}
if ($type == BADGE_TYPE_COURSE && !$courseid) {
throw new \moodle_exception('courseidnotfound');
}
$urlparams = ['type' => $type];
if ($course = $DB->get_record('course', ['id' => $courseid])) {
$urlparams['id'] = $course->id;
}
$hdr = get_string('managebadges', 'badges');
$returnurl = new moodle_url('/badges/index.php', $urlparams);
$PAGE->set_url($returnurl);
$PAGE->add_body_class('limitedwidth');
@ -64,31 +67,34 @@ if ($type == BADGE_TYPE_SITE) {
$PAGE->set_context(context_system::instance());
$PAGE->set_pagelayout('admin');
$PAGE->set_heading(get_string('administrationsite'));
navigation_node::override_active_url(new moodle_url('/badges/index.php', array('type' => BADGE_TYPE_SITE)), true);
navigation_node::override_active_url(new moodle_url('/badges/index.php', ['type' => BADGE_TYPE_SITE]), true);
$eventotherparams = ['badgetype' => BADGE_TYPE_SITE];
} else {
require_login($course);
$coursecontext = context_course::instance($course->id);
$title = get_string('coursebadges', 'badges');
$PAGE->set_context($coursecontext);
$PAGE->set_pagelayout('incourse');
$PAGE->set_heading(format_string($course->fullname, true, array('context' => $coursecontext)));
$PAGE->set_heading(format_string($course->fullname, true, ['context' => $coursecontext]));
navigation_node::override_active_url(
new moodle_url('/badges/index.php', array('type' => BADGE_TYPE_COURSE, 'id' => $course->id))
new moodle_url('/badges/index.php', ['type' => BADGE_TYPE_COURSE, 'id' => $course->id])
);
$eventotherparams = ['badgetype' => BADGE_TYPE_COURSE, 'courseid' => $course->id];
}
if (!has_any_capability(array(
if (!has_any_capability([
'moodle/badges:viewbadges',
'moodle/badges:viewawarded',
'moodle/badges:createbadge',
'moodle/badges:awardbadge',
'moodle/badges:configurecriteria',
'moodle/badges:configuremessages',
'moodle/badges:configuredetails',
'moodle/badges:deletebadge'), $PAGE->context)) {
'moodle/badges:deletebadge'], $PAGE->context)) {
redirect($CFG->wwwroot);
}
$PAGE->set_title($hdr);
$PAGE->set_title($title);
/** @var core_badges_renderer $output */
$output = $PAGE->get_renderer('core', 'badges');
@ -102,14 +108,14 @@ if ($delete || $archive) {
// Archive this badge?
echo $output->heading(get_string('archivebadge', 'badges', $badge->name));
$archivebutton = $output->single_button(
new moodle_url($PAGE->url, array('archive' => $badge->id, 'confirm' => 1)),
new moodle_url($PAGE->url, ['archive' => $badge->id, 'confirm' => 1]),
get_string('archiveconfirm', 'badges'));
echo $output->box(get_string('archivehelp', 'badges') . $archivebutton, 'generalbox');
// Delete this badge?
echo $output->heading(get_string('delbadge', 'badges', $badge->name));
$deletebutton = $output->single_button(
new moodle_url($PAGE->url, array('delete' => $badge->id, 'confirm' => 1)),
new moodle_url($PAGE->url, ['delete' => $badge->id, 'confirm' => 1]),
get_string('delconfirm', 'badges'));
echo $output->box(get_string('deletehelp', 'badges') . $deletebutton, 'generalbox');
@ -140,20 +146,28 @@ if ($deactivate && has_capability('moodle/badges:configuredetails', $PAGE->conte
}
echo $OUTPUT->header();
$backurl = $type == BADGE_TYPE_SITE ? null : new moodle_url('/badges/view.php', ['type' => $type, 'id' => $courseid]);
$actionbar = new \core_badges\output\standard_action_bar($PAGE, $type, false, true, $backurl);
echo $output->render_tertiary_navigation($actionbar);
echo $OUTPUT->container_start('badges-heading');
if ($type == BADGE_TYPE_SITE) {
echo $OUTPUT->heading_with_help($hdr, 'sitebadges', 'badges');
echo $OUTPUT->heading_with_help($title, 'sitebadges', 'badges');
} else {
echo $OUTPUT->heading($hdr);
echo $OUTPUT->heading($title);
}
$actionbar = new \core_badges\output\standard_action_bar(
page: $PAGE,
type: $type,
showaddbadge: true,
);
echo $output->render_tertiary_navigation($actionbar);
echo $OUTPUT->container_end();
echo $OUTPUT->box('', 'notifyproblem hide', 'check_connection');
if ($course && $course->startdate > time()) {
echo $OUTPUT->box(get_string('error:notifycoursedate', 'badges'), 'generalbox notifyproblem');
echo $OUTPUT->notification(
get_string('error:notifycoursedate', 'badges', userdate($course->startdate)),
'warning'
);
}
if ($msg !== '') {
@ -161,8 +175,13 @@ if ($msg !== '') {
}
$report = system_report_factory::create(badges::class, $PAGE->context);
echo $report->output();
echo $report->output();
$PAGE->requires->js_call_amd('core_badges/actions', 'init');
// Trigger event, badge listing viewed.
$eventparams = ['context' => $PAGE->context, 'other' => $eventotherparams];
$event = \core\event\badge_listing_viewed::create($eventparams);
$event->trigger();
echo $OUTPUT->footer();

View File

@ -323,7 +323,7 @@ $string['error:nosuchfield'] = 'Warning: This user profile field is no longer av
$string['error:nosuchmod'] = 'Warning: This activity is no longer available.';
$string['error:nosuchrole'] = 'Warning: This role is no longer available.';
$string['error:nosuchuser'] = 'User with this email address does not have an account with the current backpack provider.';
$string['error:notifycoursedate'] = 'Warning: Badges associated with course and activity completions will not be issued until the course start date.';
$string['error:notifycoursedate'] = 'Badges associated with course and activity completions will not be issued until the course start date ({$a}).';
$string['error:parameter'] = 'Warning: At least one parameter should be selected to ensure correct badge issuing workflow.';
$string['error:requesttimeout'] = 'The connection request timed out before it could complete.';
$string['error:requesterror'] = 'The connection request failed (error code {$a}).';

View File

@ -84,7 +84,7 @@ class badge_listing_viewed extends base {
} else {
$params = array('id' => $this->other['courseid'], 'type' => $this->other['badgetype']);
}
return new \moodle_url('/badges/view.php', $params );
return new \moodle_url('/badges/index.php', $params );
}
/**

View File

@ -2975,7 +2975,7 @@ class global_navigation extends navigation_node {
// Badges.
if ($navoptions->badges) {
$url = new moodle_url('/badges/view.php', array('type' => 2, 'id' => $course->id));
$url = new moodle_url('/badges/index.php', ['type' => 2, 'id' => $course->id]);
$coursenode->add(get_string('coursebadges', 'badges'), $url,
navigation_node::TYPE_SETTING, null, 'badgesview',
@ -3059,7 +3059,7 @@ class global_navigation extends navigation_node {
// Badges.
if ($navoptions->badges) {
$url = new moodle_url($CFG->wwwroot . '/badges/view.php', array('type' => 1));
$url = new moodle_url($CFG->wwwroot . '/badges/index.php', ['type' => 1]);
$coursenode->add(get_string('sitebadges', 'badges'), $url, navigation_node::TYPE_CUSTOM);
}

View File

@ -1854,6 +1854,28 @@ ul.badges {
color: map-get($theme-colors, 'warning');
}
#page-badges-index #page {
.badges-heading {
display: flex;
justify-content: space-between;
align-items: center;
}
h2 {
margin: 0; /* Removes default margins */
}
#action_bar {
margin: 0; /* Removes any default margin that might affect alignment */
}
.tertiary-navigation.container-fluid {
width: auto;
height: 50px;
padding-top: 0;
}
}
#page-badges-award .recipienttable tr td {
vertical-align: top;
}

View File

@ -24902,6 +24902,23 @@ ul.badges {
color: #f0ad4e;
}
#page-badges-index #page .badges-heading {
display: flex;
justify-content: space-between;
align-items: center;
}
#page-badges-index #page h2 {
margin: 0; /* Removes default margins */
}
#page-badges-index #page #action_bar {
margin: 0; /* Removes any default margin that might affect alignment */
}
#page-badges-index #page .tertiary-navigation.container-fluid, #page-badges-index #page .tertiary-navigation.container-sm, #page-badges-index #page .tertiary-navigation.container-md, #page-badges-index #page .tertiary-navigation.container-lg, #page-badges-index #page .tertiary-navigation.container-xl {
width: auto;
height: 50px;
padding-top: 0;
}
#page-badges-award .recipienttable tr td {
vertical-align: top;
}

View File

@ -24902,6 +24902,23 @@ ul.badges {
color: #f0ad4e;
}
#page-badges-index #page .badges-heading {
display: flex;
justify-content: space-between;
align-items: center;
}
#page-badges-index #page h2 {
margin: 0; /* Removes default margins */
}
#page-badges-index #page #action_bar {
margin: 0; /* Removes any default margin that might affect alignment */
}
#page-badges-index #page .tertiary-navigation.container-fluid, #page-badges-index #page .tertiary-navigation.container-sm, #page-badges-index #page .tertiary-navigation.container-md, #page-badges-index #page .tertiary-navigation.container-lg, #page-badges-index #page .tertiary-navigation.container-xl {
width: auto;
height: 50px;
padding-top: 0;
}
#page-badges-award .recipienttable tr td {
vertical-align: top;
}