mirror of
https://github.com/moodle/moodle.git
synced 2025-03-14 20:50:21 +01:00
MDL-70801 core_my: Add a new courses page
This commit is contained in:
parent
c69c33b14d
commit
6ca9c2154a
@ -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: <span> without the class="multilang" and <lang>';
|
||||
$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
|
||||
);
|
||||
}
|
||||
|
58
lib/classes/event/mycourses_viewed.php
Normal file
58
lib/classes/event/mycourses_viewed.php
Normal file
@ -0,0 +1,58 @@
|
||||
<?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/');
|
||||
|
||||
|
86
my/courses.php
Normal file
86
my/courses.php
Normal file
@ -0,0 +1,86 @@
|
||||
<?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();
|
80
my/lib.php
80
my/lib.php
@ -29,41 +29,70 @@
|
||||
|
||||
define('MY_PAGE_PUBLIC', 0);
|
||||
define('MY_PAGE_PRIVATE', 1);
|
||||
define('MY_PAGE_DEFAULT', '__default');
|
||||
define('MY_PAGE_COURSES', '__courses');
|
||||
|
||||
require_once("$CFG->libdir/blocklib.php");
|
||||
|
||||
/*
|
||||
/**
|
||||
* For a given user, this returns the $page information for their My Moodle page
|
||||
*
|
||||
* @param int|null $userid the id of the user whose page should be retrieved
|
||||
* @param int|null $private either MY_PAGE_PRIVATE or MY_PAGE_PUBLIC
|
||||
* @param string|null $pagename Differentiate between standard /my or /courses pages.
|
||||
*/
|
||||
function my_get_page($userid, $private=MY_PAGE_PRIVATE) {
|
||||
function my_get_page(?int $userid, int $private = MY_PAGE_PRIVATE, string $pagename = MY_PAGE_DEFAULT) {
|
||||
global $DB, $CFG;
|
||||
|
||||
if (empty($CFG->forcedefaultmymoodle) && $userid) { // Ignore custom My Moodle pages if admin has forced them
|
||||
// Does the user have their own page defined? If so, return it.
|
||||
if ($customised = $DB->get_record('my_pages', array('userid' => $userid, 'private' => $private))) {
|
||||
if ($customised = $DB->get_record(
|
||||
'my_pages',
|
||||
array('userid' => $userid, 'private' => $private, 'name' => $pagename),
|
||||
'*',
|
||||
IGNORE_MULTIPLE
|
||||
)) {
|
||||
return $customised;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise return the system default page
|
||||
return $DB->get_record('my_pages', array('userid' => null, 'name' => '__default', 'private' => $private));
|
||||
return $DB->get_record('my_pages', array('userid' => null, 'name' => $pagename, 'private' => $private), '*', IGNORE_MULTIPLE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/**
|
||||
* This copies a system default page to the current user
|
||||
*
|
||||
* @param int $userid the id of the user whose page should be reset
|
||||
* @param int $private either MY_PAGE_PRIVATE or MY_PAGE_PUBLIC
|
||||
* @param string $pagetype either my-index or user-profile
|
||||
* @param string $pagename Differentiate between standard /my or /courses pages.
|
||||
*/
|
||||
function my_copy_page($userid, $private=MY_PAGE_PRIVATE, $pagetype='my-index') {
|
||||
function my_copy_page(
|
||||
int $userid,
|
||||
int $private = MY_PAGE_PRIVATE,
|
||||
string $pagetype = 'my-index',
|
||||
string $pagename = MY_PAGE_DEFAULT
|
||||
) {
|
||||
global $DB;
|
||||
|
||||
if ($customised = $DB->get_record('my_pages', array('userid' => $userid, 'private' => $private))) {
|
||||
if ($customised = $DB->get_record(
|
||||
'my_pages',
|
||||
array('userid' => $userid, 'name' => $pagename, 'private' => $private),
|
||||
'*',
|
||||
IGNORE_MULTIPLE
|
||||
)) {
|
||||
return $customised; // We're done!
|
||||
}
|
||||
|
||||
// Get the system default page
|
||||
if (!$systempage = $DB->get_record('my_pages', array('userid' => null, 'name' => '__default', 'private' => $private))) {
|
||||
if (!$systempage = $DB->get_record(
|
||||
'my_pages',
|
||||
array('userid' => null, 'name' => $pagename, 'private' => $private),
|
||||
'*',
|
||||
IGNORE_MULTIPLE
|
||||
)) {
|
||||
return false; // error
|
||||
}
|
||||
|
||||
@ -117,18 +146,24 @@ function my_copy_page($userid, $private=MY_PAGE_PRIVATE, $pagetype='my-index') {
|
||||
return $page;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* For a given user, this deletes their My Moodle page and returns them to the system default.
|
||||
*
|
||||
* @param int $userid the id of the user whose page should be reset
|
||||
* @param int $private either MY_PAGE_PRIVATE or MY_PAGE_PUBLIC
|
||||
* @param string $pagetype either my-index or user-profile
|
||||
* @param string $pagename Differentiate between standard /my or /courses pages.
|
||||
* @return mixed system page, or false on error
|
||||
*/
|
||||
function my_reset_page($userid, $private=MY_PAGE_PRIVATE, $pagetype='my-index') {
|
||||
function my_reset_page(
|
||||
int $userid,
|
||||
int $private = MY_PAGE_PRIVATE,
|
||||
string $pagetype='my-index',
|
||||
string $pagename = MY_PAGE_DEFAULT
|
||||
) {
|
||||
global $DB, $CFG;
|
||||
|
||||
$page = my_get_page($userid, $private);
|
||||
$page = my_get_page($userid, $private, $pagename);
|
||||
if ($page->userid == $userid) {
|
||||
$context = context_user::instance($userid);
|
||||
if ($blocks = $DB->get_records('block_instances', array('parentcontextid' => $context->id,
|
||||
@ -140,11 +175,16 @@ function my_reset_page($userid, $private=MY_PAGE_PRIVATE, $pagetype='my-index')
|
||||
}
|
||||
}
|
||||
$DB->delete_records('block_positions', ['subpage' => $page->id, 'pagetype' => $pagetype, 'contextid' => $context->id]);
|
||||
$DB->delete_records('my_pages', array('id' => $page->id));
|
||||
$DB->delete_records('my_pages', array('id' => $page->id, 'name' => $pagename));
|
||||
}
|
||||
|
||||
// Get the system default page
|
||||
if (!$systempage = $DB->get_record('my_pages', array('userid' => null, 'name' => '__default', 'private' => $private))) {
|
||||
if (!$systempage = $DB->get_record(
|
||||
'my_pages',
|
||||
array('userid' => null, 'name' => $pagename, 'private' => $private),
|
||||
'*',
|
||||
IGNORE_MULTIPLE
|
||||
)) {
|
||||
return false; // error
|
||||
}
|
||||
|
||||
@ -166,10 +206,16 @@ function my_reset_page($userid, $private=MY_PAGE_PRIVATE, $pagetype='my-index')
|
||||
*
|
||||
* @param int $private Either MY_PAGE_PRIVATE or MY_PAGE_PUBLIC.
|
||||
* @param string $pagetype Either my-index or user-profile.
|
||||
* @param progress_bar $progressbar A progress bar to update.
|
||||
* @param progress_bar|null $progressbar A progress bar to update.
|
||||
* @param string $pagename Differentiate between standard /my or /courses pages.
|
||||
* @return void
|
||||
*/
|
||||
function my_reset_page_for_all_users($private = MY_PAGE_PRIVATE, $pagetype = 'my-index', $progressbar = null) {
|
||||
function my_reset_page_for_all_users(
|
||||
int $private = MY_PAGE_PRIVATE,
|
||||
string $pagetype = 'my-index',
|
||||
?progress_bar $progressbar = null,
|
||||
string $pagename = MY_PAGE_DEFAULT
|
||||
) {
|
||||
global $DB;
|
||||
|
||||
// This may take a while. Raise the execution time limit.
|
||||
@ -199,12 +245,14 @@ function my_reset_page_for_all_users($private = MY_PAGE_PRIVATE, $pagetype = 'my
|
||||
AND bi.pagetypepattern = :pagetypepattern
|
||||
AND (bi.subpagepattern IS NULL OR bi.subpagepattern = " . $DB->sql_concat("''", 'p.id') . ")
|
||||
WHERE p.private = :private
|
||||
AND p.name = :name
|
||||
AND p.userid $infragment";
|
||||
|
||||
$params = array_merge([
|
||||
'private' => $private,
|
||||
'usercontextlevel' => CONTEXT_USER,
|
||||
'pagetypepattern' => $pagetype
|
||||
'pagetypepattern' => $pagetype,
|
||||
'name' => $pagename
|
||||
], $inparams);
|
||||
$blockids = $DB->get_fieldset_sql($sql, $params);
|
||||
|
||||
|
37
my/templates/dropdown.mustache
Normal file
37
my/templates/dropdown.mustache
Normal file
@ -0,0 +1,37 @@
|
||||
{{!
|
||||
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/>.
|
||||
}}
|
||||
{{!
|
||||
@template my/dropdown
|
||||
|
||||
Simple dropdown for the my/courses page
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"newcourseurl": "https://moodle.test/course/edit.php?category=1",
|
||||
"manageurl": "https://moodle.test/course/management.php?categoryid=1"
|
||||
}
|
||||
}}
|
||||
<div class="btn-group">
|
||||
<!-- Set as a link to appease Goutte behat. -->
|
||||
<a href="#" class="btn btn-link btn-icon icon-size-3" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" title="{{#str}}coursemanagementoptions, my{{/str}}">
|
||||
<i class="fa fa-ellipsis-v text-dark py-2" aria-hidden="true"></i>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-right">
|
||||
<a class="dropdown-item" href="{{newcourseurl}}">{{#str}}newcourse, core{{/str}}</a>
|
||||
<a class="dropdown-item" href="{{manageurl}}">{{#str}}managecourses, core{{/str}}</a>
|
||||
</div>
|
||||
</div>
|
13
my/tests/behat/my_courses.feature
Normal file
13
my/tests/behat/my_courses.feature
Normal file
@ -0,0 +1,13 @@
|
||||
@core @core_my
|
||||
Feature: Run tests over my courses.
|
||||
|
||||
Scenario: Admin can add new courses or manage them from my courses
|
||||
Given I am on the "My courses" page logged in as "admin"
|
||||
And I click on "Course management options" "link"
|
||||
And I click on "New course" "link"
|
||||
And I wait to be redirected
|
||||
Then I should see "Add a new course"
|
||||
And I am on the "My courses" page
|
||||
And I click on "Course management options" "link"
|
||||
And I click on "Manage courses" "link"
|
||||
And I should see "Course and category management"
|
4
my/upgrade.txt
Normal file
4
my/upgrade.txt
Normal file
@ -0,0 +1,4 @@
|
||||
This files describes changes in the my system.
|
||||
=== 4.0 ===
|
||||
* Introduce a new /courses page
|
||||
* Tighten up the typing within the lib file
|
@ -64,10 +64,9 @@ class boostnavbar implements \renderable {
|
||||
// Set the designated one path for courses.
|
||||
$mycoursesnode = $this->get_item('mycourses');
|
||||
if (!is_null($mycoursesnode)) {
|
||||
// TODO: Once MDL-70801 lands point this to the new page.
|
||||
$url = new \moodle_url('/course/');
|
||||
$url = new \moodle_url('/my/courses.php');
|
||||
$mycoursesnode->action = $url;
|
||||
$mycoursesnode->text = get_string('courses');
|
||||
$mycoursesnode->text = get_string('mycourses');
|
||||
}
|
||||
|
||||
$this->remove_no_link_items();
|
||||
|
@ -78,6 +78,12 @@ $THEME->layouts = [
|
||||
'regions' => array('side-pre'),
|
||||
'defaultregion' => 'side-pre',
|
||||
),
|
||||
// My courses page.
|
||||
'mycourses' => array(
|
||||
'file' => 'columns2.php',
|
||||
'regions' => array('content'),
|
||||
'defaultregion' => 'content',
|
||||
),
|
||||
// My dashboard page.
|
||||
'mydashboard' => array(
|
||||
'file' => 'columns2.php',
|
||||
|
@ -49,6 +49,7 @@ $string['rawscss_desc'] = 'Use this field to provide SCSS or CSS code which will
|
||||
$string['rawscsspre'] = 'Raw initial SCSS';
|
||||
$string['rawscsspre_desc'] = 'In this field you can provide initialising SCSS code, it will be injected before everything else. Most of the time you will use this setting to define variables.';
|
||||
$string['region-side-pre'] = 'Right';
|
||||
$string['region-content'] = 'Content';
|
||||
$string['showfooter'] = 'Show footer';
|
||||
$string['privacy:metadata:preference:draweropennav'] = 'The user\'s preference for hiding or showing the drawer menu navigation.';
|
||||
$string['privacy:drawernavclosed'] = 'The current preference for the navigation drawer is closed.';
|
||||
|
@ -2875,3 +2875,13 @@ body.dragging {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.page-mycourses {
|
||||
#region-main {
|
||||
padding: 0;
|
||||
}
|
||||
#region-main,
|
||||
.block_myoverview {
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
|
@ -12211,6 +12211,13 @@ body.dragging .dragging {
|
||||
.collapse-list .collapse-list-item-content .collapse-list-item {
|
||||
padding-left: calc(1rem * 3); }
|
||||
|
||||
.page-mycourses #region-main {
|
||||
padding: 0; }
|
||||
|
||||
.page-mycourses #region-main,
|
||||
.page-mycourses .block_myoverview {
|
||||
border: 0; }
|
||||
|
||||
.icon {
|
||||
font-size: 16px;
|
||||
width: 16px;
|
||||
|
@ -72,6 +72,12 @@ $THEME->layouts = [
|
||||
'regions' => array('side-pre'),
|
||||
'defaultregion' => 'side-pre',
|
||||
),
|
||||
// My courses page.
|
||||
'mycourses' => array(
|
||||
'file' => 'columns.php',
|
||||
'regions' => array('content'),
|
||||
'defaultregion' => 'content',
|
||||
),
|
||||
// My dashboard page.
|
||||
'mydashboard' => array(
|
||||
'file' => 'columns.php',
|
||||
|
@ -12211,6 +12211,13 @@ body.dragging .dragging {
|
||||
.collapse-list .collapse-list-item-content .collapse-list-item {
|
||||
padding-left: calc(1rem * 3); }
|
||||
|
||||
.page-mycourses #region-main {
|
||||
padding: 0; }
|
||||
|
||||
.page-mycourses #region-main,
|
||||
.page-mycourses .block_myoverview {
|
||||
border: 0; }
|
||||
|
||||
.icon {
|
||||
font-size: 16px;
|
||||
width: 16px;
|
||||
|
@ -43,7 +43,8 @@ class behat_theme_classic_behat_course extends behat_course {
|
||||
public function i_navigate_to_course_participants() {
|
||||
$coursestr = behat_context_helper::escape(get_string('courses'));
|
||||
$mycoursestr = behat_context_helper::escape(get_string('mycourses'));
|
||||
$xpath = "//div[contains(@class,'block')]//li[p/*[string(.)=$coursestr or string(.)=$mycoursestr]]";
|
||||
$xpath = "//div[contains(@class,'block')]//li[contains(@class,'contains_branch')]" .
|
||||
"[p/*[string(.)=$coursestr or string(.)=$mycoursestr]]";
|
||||
$this->execute('behat_general::i_click_on_in_the', [get_string('participants'), 'link', $xpath, 'xpath_element']);
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$version = 2021111200.00; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
$version = 2021111200.01; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
// RR = release increments - 00 in DEV branches.
|
||||
// .XX = incremental changes.
|
||||
$release = '4.0dev+ (Build: 20211112)'; // Human-friendly version name
|
||||
|
Loading…
x
Reference in New Issue
Block a user