Commit 6ca9c215 authored by Mathew May's avatar Mathew May
Browse files

MDL-70801 core_my: Add a new courses page

parent c69c33b1
......@@ -71,9 +71,9 @@ Feature: Use core page resolvers for the I am on the page steps
Then I should see "<shouldsee>"
Examples:
| description | identifier | shouldsee |
| Admin page | "Admin notifications" | Check for available updates |
| Home page | Homepage | Course overview |
| description | identifier | shouldsee |
| Admin page | "Admin notifications" | Check for available updates |
| Home page | Homepage | Calendar |
Scenario Outline: When I am on a named page logged in as
When I am on the <identifier> page logged in as admin
......@@ -82,4 +82,4 @@ Feature: Use core page resolvers for the I am on the page steps
Examples:
| description | identifier | shouldsee |
| Admin page | "Admin notifications" | Check for available updates |
| Home page | Homepage | Course overview |
| Home page | Homepage | Calendar |
......@@ -36,7 +36,7 @@ Feature: Viewing acceptances reports and accepting on behalf of other users
And I press "Next"
And I set the field "I agree to the This site policy" to "1"
And I press "Next"
And I should see "Course overview"
And I should see "Calendar"
And I log out
And I log in as "manager"
And I press "Next"
......@@ -82,7 +82,7 @@ Feature: Viewing acceptances reports and accepting on behalf of other users
And I press "Next"
And I set the field "I agree to the This site policy" to "1"
And I press "Next"
And I should see "Course overview"
And I should see "Calendar"
And I navigate to "Users > Privacy and policies > Manage policies" in site administration
And I click on "1 of 4 (25%)" "link" in the "This site policy" "table_row"
And I click on "Accept This site policy" "link" in the "User One" "table_row"
......@@ -111,7 +111,7 @@ Feature: Viewing acceptances reports and accepting on behalf of other users
And I set the field "I agree to the This site policy" to "1"
And I set the field "I agree to the This privacy policy" to "1"
And I press "Next"
And I should see "Course overview"
And I should see "Calendar"
And I log out
And I log in as "manager"
And I press "Next"
......@@ -300,7 +300,7 @@ Feature: Viewing acceptances reports and accepting on behalf of other users
And I press "Next"
And I set the field "I agree to the This site policy" to "1"
And I press "Next"
And I should see "Course overview"
And I should see "Calendar"
And I log out
And I log in as "admin"
And I navigate to "Users > Privacy and policies > Manage policies" in site administration
......@@ -311,4 +311,4 @@ Feature: Viewing acceptances reports and accepting on behalf of other users
And I press "Continue"
And I log out
When I log in as "user1"
Then I should see "Course overview"
Then I should see "Calendar"
......@@ -20,7 +20,7 @@ Feature: Add a new user tour
| Display in middle of page | Welcome | Welcome to your personal learning space. We'd like to give you a quick tour to show you some of the areas you may find helpful |
And I add steps to the "First tour" tour:
| targettype | targetvalue_block | Title | Content |
| Block | Course overview | Course overview | This area shows you what's happening in some of your courses |
| Block | Timeline | Timeline | This is the Timeline. All of your upcoming activities can be found here |
| Block | Calendar | Calendar | This is the Calendar. All of your assignments and due dates can be found here |
And I add steps to the "First tour" tour:
| targettype | targetvalue_selector | Title | Content |
......@@ -28,7 +28,7 @@ Feature: Add a new user tour
When I am on homepage
Then I should see "Welcome to your personal learning space. We'd like to give you a quick tour to show you some of the areas you may find helpful"
And I click on "Next" "button" in the "[data-role='flexitour-step']" "css_element"
And I should see "This area shows you what's happening in some of your courses"
And I should see "This is the Timeline. All of your upcoming activities can be found here"
And I should not see "This is the Calendar. All of your assignments and due dates can be found here"
And I click on "Next" "button" in the "[data-role='flexitour-step']" "css_element"
And I should see "This is the Calendar. All of your assignments and due dates can be found here"
......@@ -95,7 +95,7 @@ Feature: Add a new user tour
| Display in middle of page | Welcome | First step of the Tour |
And I add steps to the "Steps tour" tour:
| targettype | targetvalue_block | Title | Content |
| Block | Course overview | Course overview | Second step of the Tour |
| Block | Timeline | Timeline | Second step of the Tour |
| Block | Calendar | Calendar | Third step of the Tour |
When I am on homepage
Then I should see "First step of the Tour"
......@@ -129,7 +129,7 @@ Feature: Add a new user tour
| Display in middle of page | Welcome | First step of the Tour |
And I add steps to the "Steps tour" tour:
| targettype | targetvalue_block | Title | Content |
| Block | Course overview | Course overview | Second step of the Tour |
| Block | Timeline | Timeline | Second step of the Tour |
| Block | Calendar | Calendar | Third step of the Tour |
When I am on homepage
Then I should see "First step of the Tour"
......
......@@ -53,14 +53,14 @@ Feature: Steps can be navigated within a tour
| Display in middle of page | Welcome | Welcome to your personal learning space. We'd like to give you a quick tour to show you some of the areas you may find helpful |
And I add steps to the "First tour" tour:
| targettype | targetvalue_block | Title | Content |
| Block | Course overview | Course overview | This area shows you what's happening in some of your courses |
| Block | Timeline | Timeline | This is the Timeline. All of your upcoming activities can be found here |
| Block | Calendar | Calendar | This is the Calendar. All of your assignments and due dates can be found here |
When I am on homepage
Then I should see "Skip tour"
And I should see "Next (1/3)"
And I click on "Next (1/3)" "button" in the "Welcome" "dialogue"
And I should see "Skip tour"
And I click on "Next (2/3)" "button" in the "Course overview" "dialogue"
And I click on "Next (2/3)" "button" in the "Timeline" "dialogue"
And I should see "End tour"
@javascript
......
......@@ -249,7 +249,7 @@ class block_base {
$this->arialabel = $bc->arialabel;
}
if ($this->page->user_is_editing()) {
if ($this->page->user_is_editing() && $this->instance_can_be_edited()) {
$bc->controls = $this->page->blocks->edit_controls($this);
} else {
// we must not use is_empty on hidden blocks
......@@ -692,6 +692,15 @@ class block_base {
return true;
}
/**
* If overridden and set to false by the block it will not be editable.
*
* @return bool
*/
public function instance_can_be_edited() {
return true;
}
/** @callback callback functions for comments api */
public static function comment_template($options) {
$ret = <<<EOD
......
......@@ -70,4 +70,4 @@ Feature: Add and configure blocks throughout the site
| Text block title | Foo " onload="document.getElementsByTagName('body')[0].remove()" alt=" |
| Content | Example |
When I press "Save changes"
Then I should see "Course overview"
Then I should see "Example"
......@@ -327,9 +327,14 @@ class core_block_externallib_testcase extends externallib_advanced_testcase {
// Force a setting change to check the returned blocks settings.
set_config('displaycategories', 0, 'block_myoverview');
$systempage = $DB->get_record('my_pages', array('userid' => null, 'name' => MY_PAGE_DEFAULT, 'private' => true));
// Get the expected default blocks.
$alldefaultblocksordered = $DB->get_records_menu('block_instances',
array('pagetypepattern' => 'my-index'), 'defaultregion, defaultweight ASC', 'id, blockname');
$alldefaultblocksordered = $DB->get_records_menu(
'block_instances',
array('pagetypepattern' => 'my-index', 'subpagepattern' => $systempage->id),
'defaultregion, defaultweight ASC',
'id, blockname'
);
$this->setUser($user);
......@@ -368,8 +373,13 @@ class core_block_externallib_testcase extends externallib_advanced_testcase {
$user = $this->getDataGenerator()->create_user();
$PAGE->set_url('/my/index.php'); // Need this because some internal API calls require the $PAGE url to be set.
$systempage = $DB->get_record('my_pages', array('userid' => null, 'name' => MY_PAGE_DEFAULT, 'private' => true));
// Get the expected default blocks.
$alldefaultblocks = $DB->get_records_menu('block_instances', array('pagetypepattern' => 'my-index'), '', 'id, blockname');
$alldefaultblocks = $DB->get_records_menu(
'block_instances', array('pagetypepattern' => 'my-index', 'subpagepattern' => $systempage->id),
'',
'id, blockname'
);
// Now, add a sticky block.
$page = new moodle_page();
......@@ -411,8 +421,14 @@ class core_block_externallib_testcase extends externallib_advanced_testcase {
$user = $this->getDataGenerator()->create_user();
$PAGE->set_url('/my/index.php'); // Need this because some internal API calls require the $PAGE url to be set.
$systempage = $DB->get_record('my_pages', array('userid' => null, 'name' => MY_PAGE_DEFAULT, 'private' => true));
// Get the expected default blocks.
$alldefaultblocks = $DB->get_records_menu('block_instances', array('pagetypepattern' => 'my-index'), '', 'id, blockname');
$alldefaultblocks = $DB->get_records_menu(
'block_instances',
array('pagetypepattern' => 'my-index', 'subpagepattern' => $systempage->id),
'',
'id, blockname'
);
// Add a custom block.
$page = new moodle_page();
......
......@@ -38,7 +38,6 @@ Feature: We can change what we are viewing on the grader report
And I give the grade "80.00" to the user "Student 1" for the grade item "Test assignment name 1"
And I give the grade "90.00" to the user "Student 1" for the grade item "Test assignment name 2"
And I press "Save changes"
And I turn editing mode off
@javascript
Scenario: View and minimise the grader report containing hidden activities
......
......@@ -858,6 +858,7 @@ $string['modsettings'] = 'Manage activities';
$string['modulesecurity'] = 'Module security';
$string['multilangforceold'] = 'Force old multilang syntax: &lt;span&gt; without the class="multilang" and &lt;lang&gt;';
$string['mustenablestats'] = 'Statistics have not yet been enabled on this site.';
$string['mycourses'] = 'My courses';
$string['mycoursesperpage'] = 'Number of courses';
$string['mydashboard'] = 'System default dashboard';
$string['mymoodle'] = 'Dashboard';
......
......@@ -22,6 +22,7 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['coursemanagementoptions'] = 'Course management options';
$string['mymoodle'] = 'Dashboard';
$string['nocourses'] = 'No course information to show.';
$string['noguest'] = 'The Dashboard page is not available to guest users';
......
......@@ -60,6 +60,7 @@ $PAGE->blocks->add_custom_regions_for_pagetype($pagetype);
$pagetype = explode('-', $pagetype);
switch ($pagetype[0]) {
case 'my':
case 'mycourses':
$PAGE->set_blocks_editing_capability('moodle/my:manageblocks');
break;
case 'user':
......
......@@ -2647,7 +2647,30 @@ function blocks_add_default_system_blocks() {
$subpagepattern = null;
}
$newblocks = array('timeline', 'private_files', 'badges', 'calendar_month');
$newcontent = array('myoverview');
$page->blocks->add_blocks(array(BLOCK_POS_RIGHT => $newblocks, 'content' => $newcontent), 'my-index', $subpagepattern);
if ($defaultmycoursespage = $DB->get_record('my_pages', array('userid' => null, 'name' => '__courses', 'private' => 0))) {
$mycoursesubpagepattern = $defaultmycoursespage->id;
} else {
$mycoursesubpagepattern = null;
}
$page->blocks->add_blocks([
BLOCK_POS_RIGHT => [
'private_files',
'badges',
],
'content' => [
'timeline',
'calendar_month',
]],
'my-index',
$subpagepattern
);
$page->blocks->add_blocks([
'content' => [
'myoverview'
]],
'my-index',
$mycoursesubpagepattern
);
}
<?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\event;
/**
* My courses viewed event class.
*
* Class for event to be triggered when a user views their My courses page.
*
* @package core
* @copyright 2021 Mathew May <mathew.solutions>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class mycourses_viewed extends base {
/**
* Init method.
*
* @return void
*/
protected function init(): void {
$this->data['crud'] = 'r';
$this->data['edulevel'] = self::LEVEL_OTHER;
}
/**
* Returns description of what happened.
*
* @return string
*/
public function get_description(): string {
return "The user with id '$this->userid' has viewed their my courses page";
}
/**
* Return localised event name.
*
* @return string
*/
public static function get_name(): string {
return get_string('eventmycoursesviewed', 'core');
}
}
......@@ -57,8 +57,8 @@ class primary extends view {
}
}
// Add a dummy mycourse link to a mycourses page.
$this->add(get_string('mycourses'), new \moodle_url('/course/index.php'), self::TYPE_ROOTNODE, null, 'courses');
// Add the mycourses link.
$this->add(get_string('mycourses'), new \moodle_url('/my/courses.php'), self::TYPE_ROOTNODE, null, 'courses');
// Add the site admin node. We are using the settingsnav so as to avoid rechecking permissions again.
$settingsnav = $this->page->settingsnav;
......
......@@ -310,6 +310,13 @@ function xmldb_main_install() {
$mypage->private = 1;
$DB->insert_record('my_pages', $mypage);
$mycoursespage = new stdClass();
$mycoursespage->userid = null;
$mycoursespage->name = '__courses';
$mycoursespage->private = 0;
$mycoursespage->sortorder = 0;
$DB->insert_record('my_pages', $mycoursespage);
// Set a sensible default sort order for the most-used question types.
set_config('multichoice_sortorder', 1, 'question');
set_config('truefalse_sortorder', 2, 'question');
......
......@@ -3145,5 +3145,17 @@ function xmldb_main_upgrade($oldversion) {
upgrade_main_savepoint(true, 2021110800.03);
}
if ($oldversion < 2021111200.01) {
$mycoursespage = new stdClass();
$mycoursespage->userid = null;
$mycoursespage->name = '__courses';
$mycoursespage->private = 0;
$mycoursespage->sortorder = 0;
$DB->insert_record('my_pages', $mycoursespage);
upgrade_main_savepoint(true, 2021111200.01);
}
return true;
}
......@@ -1328,7 +1328,14 @@ class global_navigation extends navigation_node {
$this->rootnodes['site'] = $this->add_course($SITE);
$this->rootnodes['myprofile'] = $this->add(get_string('profile'), null, self::TYPE_USER, null, 'myprofile');
$this->rootnodes['currentcourse'] = $this->add(get_string('currentcourse'), null, self::TYPE_ROOTNODE, null, 'currentcourse');
$this->rootnodes['mycourses'] = $this->add(get_string('mycourses'), null, self::TYPE_ROOTNODE, null, 'mycourses', new pix_icon('i/course', ''));
$this->rootnodes['mycourses'] = $this->add(
get_string('mycourses'),
new moodle_url('/my/courses.php'),
self::TYPE_ROOTNODE,
null,
'mycourses',
new pix_icon('i/course', '')
);
$this->rootnodes['courses'] = $this->add(get_string('courses'), new moodle_url('/course/index.php'), self::TYPE_ROOTNODE, null, 'courses');
if (!core_course_category::user_top()) {
$this->rootnodes['courses']->hide();
......@@ -1521,7 +1528,7 @@ class global_navigation extends navigation_node {
foreach ($this->rootnodes as $node) {
// Dont remove the home node
/** @var navigation_node $node */
if (!in_array($node->key, ['home', 'myhome']) && !$node->has_children() && !$node->isactive) {
if (!in_array($node->key, ['home', 'mycourses', 'myhome']) && !$node->has_children() && !$node->isactive) {
$node->remove();
}
}
......@@ -2880,6 +2887,9 @@ class global_navigation extends navigation_node {
// This required as there are not other guaranteed nodes that may be loaded.
$coursenode->add('frontpageloaded', null, self::TYPE_CUSTOM, null, 'frontpageloaded')->display = false;
// Add My courses to the site pages within the navigation structure so the block can read it.
$coursenode->add(get_string('mycourses'), new moodle_url('/my/courses.php'), self::TYPE_CUSTOM, null, 'mycourses');
// Participants.
if ($navoptions->participants) {
$coursenode->add(get_string('participants'), new moodle_url('/user/index.php?id='.$course->id), self::TYPE_CUSTOM, get_string('participants'), 'participants');
......
......@@ -4372,7 +4372,8 @@ EOD;
$pagetype = $this->page->pagetype;
$homepage = get_home_page();
$homepagetype = null;
if ($homepage == HOMEPAGE_MY) {
// Add a special case since /my/courses is a part of the /my subsystem.
if ($homepage == HOMEPAGE_MY && $this->page->title !== get_string('mycourses')) {
$homepagetype = 'my-index';
} else if ($homepage == HOMEPAGE_SITE) {
$homepagetype = 'site-index';
......
......@@ -717,6 +717,9 @@ class behat_navigation extends behat_base {
case 'Homepage':
return new moodle_url('/');
case 'My courses':
return new moodle_url('/my/courses.php');
case 'Admin notifications':
return new moodle_url('/admin/');
......
<?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/>.
/**
* My Courses.
*
* - each user can currently have their own page (cloned from system and then customised)
* - only the user can see their own dashboard
* - users can add any blocks they want
*
* @package core
* @subpackage my
* @copyright 2021 Mathew May <mathew.solutions>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once(__DIR__ . '/../config.php');
require_once($CFG->dirroot . '/my/lib.php');
redirect_if_major_upgrade_required();
require_login();
$hassiteconfig = has_capability('moodle/site:config', context_system::instance());
if ($hassiteconfig && moodle_needs_upgrading()) {
redirect(new moodle_url('/admin/index.php'));
}
$context = context_system::instance();
// Get the My Moodle page info. Should always return something unless the database is broken.
if (!$currentpage = my_get_page(null, MY_PAGE_PUBLIC, MY_PAGE_COURSES)) {
throw new Exception('mymoodlesetup');
}
// Start setting up the page.
$PAGE->set_context($context);
$PAGE->set_url('/my/courses.php');
$PAGE->add_body_classes(['limitedwidth', 'page-mycourses']);
$PAGE->set_pagelayout('mycourses');
$PAGE->has_secondary_navigation_setter(false);
$PAGE->set_pagetype('my-index');
$PAGE->set_subpage($currentpage->id);
$PAGE->set_title(get_string('mycourses'));
$PAGE->set_heading(get_string('mycourses'));
// Force the add block out of the default area.
$PAGE->theme->addblockposition = BLOCK_ADDBLOCK_POSITION_CUSTOM;
// Add course management if the user has the capabilities for it.
$coursecat = core_course_category::user_top();
if ($coursecat->can_create_course() || $coursecat->has_manage_capability()) {
$data = [
'newcourseurl' => new moodle_url('/course/edit.php', ['category' => $coursecat->id]),
'manageurl' => new moodle_url('/course/management.php', ['categoryid' => $coursecat->id]),
];
$PAGE->add_header_action($OUTPUT->render_from_template('my/dropdown', $data));
}
echo $OUTPUT->header();
if (core_userfeedback::should_display_reminder()) {
core_userfeedback::print_reminder_block();
}
echo $OUTPUT->custom_block_region('content');
echo $OUTPUT->footer();
// Trigger dashboard has been viewed event.
$eventparams = array('context' => $context);
$event = \core\event\mycourses_viewed::create($eventparams);
$event->trigger();
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment