Merge branch 'MDL-59890-master' of git://github.com/andrewnicols/moodle

This commit is contained in:
Jun Pataleta 2017-10-04 11:19:33 +08:00
commit cd7cd9d9c1
66 changed files with 1410 additions and 123 deletions

View file

@ -0,0 +1,133 @@
<?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/>.
/**
* Class for exporting summary information for a course category.
*
* @package core
* @copyright 2017 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core\external;
defined('MOODLE_INTERNAL') || die();
use renderer_base;
use moodle_url;
/**
* Class for exporting a course summary from an stdClass.
*
* @copyright 2017 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class coursecat_summary_exporter extends \core\external\exporter {
/**
* @var \coursecat $category
*/
protected $category;
public function __construct(\coursecat $category, $related) {
$this->category = $category;
$data = [];
// Specify some defaults.
foreach ($category as $key => $value) {
$data[$key] = $value;
}
return parent::__construct($data, $related);
}
protected static function define_related() {
return [
'context' => 'context',
];
}
public static function define_other_properties() {
return [
'nestedname' => [
'type' => PARAM_RAW,
],
'url' => [
'type' => PARAM_URL,
],
];
}
protected function get_other_values(renderer_base $output) {
$return = [
'nestedname' => $this->category->get_nested_name(),
'url' => (new moodle_url('/course/index.php', [
'categoryid' => $this->category->id,
]))->out(false),
];
return $return;
}
public static function define_properties() {
return [
'id' => [
'type' => PARAM_INT,
],
'name' => [
'type' => PARAM_TEXT,
'default' => '',
],
'idnumber' => [
'type' => PARAM_RAW,
'null' => NULL_ALLOWED,
],
'description' => [
'type' => PARAM_RAW,
'optional' => true,
],
'parent' => [
'type' => PARAM_INT,
],
'coursecount' => [
'type' => PARAM_INT,
'default' => 0,
],
'visible' => [
'type' => PARAM_INT,
'default' => 1,
],
'timemodified' => [
'type' => PARAM_INT,
'default' => 0,
],
'depth' => [
'type' => PARAM_INT,
'default' => 0,
],
];
}
/**
* Get the formatting parameters for the summary.
*
* @return array
*/
protected function get_format_parameters_for_description() {
return [
'component' => 'coursecat',
'filearea' => 'description',
];
}
}

View file

@ -203,6 +203,7 @@ class icon_system_fontawesome extends icon_system_font {
'core:i/completion_self' => 'fa-user-o',
'core:i/dashboard' => 'fa-tachometer',
'core:i/lock' => 'fa-lock',
'core:i/categoryevent' => 'fa-users',
'core:i/courseevent' => 'fa-calendar',
'core:i/db' => 'fa-database',
'core:i/delete' => 'fa-trash',

View file

@ -291,6 +291,48 @@ class coursecat implements renderable, cacheable_object, IteratorAggregate {
return $categories;
}
/**
* Load all coursecat objects.
*
* @param array $options Options:
* @param bool $options.returnhidden Return categories even if they are hidden
* @return coursecat[]
*/
public static function get_all($options = []) {
global $DB;
$coursecatrecordcache = cache::make('core', 'coursecatrecords');
$catcontextsql = \context_helper::get_preload_record_columns_sql('ctx');
$catsql = "SELECT cc.*, {$catcontextsql}
FROM {course_categories} cc
JOIN {context} ctx ON cc.id = ctx.instanceid";
$catsqlwhere = "WHERE ctx.contextlevel = :contextlevel";
$catsqlorder = "ORDER BY cc.depth ASC, cc.sortorder ASC";
$catrs = $DB->get_recordset_sql("{$catsql} {$catsqlwhere} {$catsqlorder}", [
'contextlevel' => CONTEXT_COURSECAT,
]);
$types['categories'] = [];
$categories = [];
$toset = [];
foreach ($catrs as $record) {
$category = new coursecat($record);
$toset[$category->id] = $category;
if (!empty($options['returnhidden']) || $category->is_uservisible()) {
$categories[$record->id] = $category;
}
}
$catrs->close();
$coursecatrecordcache->set_many($toset);
return $categories;
}
/**
* Returns the first found category
*
@ -1258,6 +1300,17 @@ class coursecat implements renderable, cacheable_object, IteratorAggregate {
array($this->id));
}
/**
* Get the link used to view this course category.
*
* @return \moodle_url
*/
public function get_view_link() {
return new \moodle_url('/course/index.php', [
'categoryid' => $this->id,
]);
}
/**
* Searches courses
*
@ -1703,6 +1756,9 @@ class coursecat implements renderable, cacheable_object, IteratorAggregate {
throw new moodle_exception('cannotdeletecategoryquestions', '', '', $this->get_formatted_name());
}
// Delete all events in the category.
$DB->delete_records('event', array('categoryid' => $this->id));
// Finally delete the category and it's context.
$DB->delete_records('course_categories', array('id' => $this->id));
@ -2158,6 +2214,32 @@ class coursecat implements renderable, cacheable_object, IteratorAggregate {
}
}
/**
* Get the nested name of this category, with all of it's parents.
*
* @param bool $includelinks Whether to wrap each name in the view link for that category.
* @param string $separator The string between each name.
* @param array $options Formatting options.
* @return string
*/
public function get_nested_name($includelinks = true, $separator = ' / ', $options = []) {
// Get the name of hierarchical name of this category.
$parents = $this->get_parents();
$categories = static::get_many($parents);
$categories[] = $this;
$names = array_map(function($category) use ($options, $includelinks) {
if ($includelinks) {
return html_writer::link($category->get_view_link(), $category->get_formatted_name($options));
} else {
return $category->get_formatted_name($options);
}
}, $categories);
return implode($separator, $names);
}
/**
* Returns ids of all parents of the category. Last element in the return array is the direct parent
*

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="lib/db" VERSION="20170904" COMMENT="XMLDB file for core Moodle tables"
<XMLDB PATH="lib/db" VERSION="20170921" COMMENT="XMLDB file for core Moodle tables"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../lib/xmldb/xmldb.xsd"
>
@ -426,6 +426,7 @@
<FIELD NAME="name" TYPE="text" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="description" TYPE="text" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="format" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="categoryid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="groupid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
@ -446,6 +447,7 @@
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
<KEY NAME="categoryid" TYPE="foreign" FIELDS="categoryid" REFTABLE="course_categories" REFFIELDS="id"/>
</KEYS>
<INDEXES>
<INDEX NAME="courseid" UNIQUE="false" FIELDS="courseid"/>
@ -453,7 +455,7 @@
<INDEX NAME="timestart" UNIQUE="false" FIELDS="timestart"/>
<INDEX NAME="timeduration" UNIQUE="false" FIELDS="timeduration"/>
<INDEX NAME="type-timesort" UNIQUE="false" FIELDS="type, timesort"/>
<INDEX NAME="groupid-courseid-visible-userid" UNIQUE="false" FIELDS="groupid, courseid, visible, userid" COMMENT="used for calendar view"/>
<INDEX NAME="groupid-courseid-categoryid-visible-userid" UNIQUE="false" FIELDS="groupid, courseid, categoryid, visible, userid" COMMENT="used for calendar view"/>
</INDEXES>
</TABLE>
<TABLE NAME="cache_filters" COMMENT="For keeping information about cached data">
@ -3719,4 +3721,4 @@
</INDEXES>
</TABLE>
</TABLES>
</XMLDB>
</XMLDB>

View file

@ -2570,5 +2570,36 @@ function xmldb_main_upgrade($oldversion) {
upgrade_main_savepoint(true, 2017092700.00);
}
if ($oldversion < 2017092900.00) {
// Define field categoryid to be added to event.
$table = new xmldb_table('event');
$field = new xmldb_field('categoryid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'format');
// Conditionally launch add field categoryid.
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
// Add the categoryid key.
$key = new xmldb_key('categoryid', XMLDB_KEY_FOREIGN, array('categoryid'), 'course_categories', array('id'));
$dbman->add_key($table, $key);
// Add a new index for groupid/courseid/categoryid/visible/userid.
// Do this before we remove the old index.
$index = new xmldb_index('groupid-courseid-categoryid-visible-userid', XMLDB_INDEX_NOTUNIQUE, array('groupid', 'courseid', 'categoryid', 'visible', 'userid'));
if (!$dbman->index_exists($table, $index)) {
$dbman->add_index($table, $index);
}
// Drop the old index.
$index = new xmldb_index('groupid-courseid-visible-userid', XMLDB_INDEX_NOTUNIQUE, array('groupid', 'courseid', 'visible', 'userid'));
if ($dbman->index_exists($table, $index)) {
$dbman->drop_index($table, $index);
}
// Main savepoint reached.
upgrade_main_savepoint(true, 2017092900.00);
}
return true;
}

View file

@ -1103,4 +1103,59 @@ EOD;
// Get the tool associated with this instance.
return $DB->get_record('enrol_lti_tools', array('enrolid' => $instanceid));
}
/**
* Helper function used to create an event.
*
* @param array $data
* @return stdClass
*/
public function create_event($data = []) {
global $CFG;
require_once($CFG->dirroot . '/calendar/lib.php');
$record = new \stdClass();
$record->name = 'event name';
$record->eventtype = 'global';
$record->repeat = 0;
$record->repeats = 0;
$record->timestart = time();
$record->timeduration = 0;
$record->timesort = 0;
$record->eventtype = 'user';
$record->courseid = 0;
foreach ($data as $key => $value) {
$record->$key = $value;
}
switch ($record->eventtype) {
case 'user':
unset($record->categoryid);
unset($record->courseid);
unset($record->groupid);
break;
case 'group':
unset($record->categoryid);
break;
case 'course':
unset($record->categoryid);
unset($record->groupid);
break;
case 'category':
unset($record->courseid);
unset($record->groupid);
break;
case 'global':
unset($record->categoryid);
unset($record->courseid);
unset($record->groupid);
break;
}
$event = new calendar_event($record);
$event->create($record);
return $event->properties();
}
}

View file

@ -174,6 +174,15 @@ class behat_data_generators extends behat_base {
'datagenerator' => 'tag',
'required' => array('name')
),
'events' => array(
'datagenerator' => 'event',
'required' => array('name', 'eventtype'),
'switchids' => array(
'user' => 'userid',
'course' => 'courseid',
'category' => 'categoryid',
)
),
);
/**
@ -218,7 +227,7 @@ class behat_data_generators extends behat_base {
$methodname = 'get_' . $element . '_id';
// Not all the switch fields are required, default vars will be assigned by data generators.
if (isset($elementdata[$element])) {
if (!empty($elementdata[$element])) {
// Temp $id var to avoid problems when $element == $field.
$id = $this->{$methodname}($elementdata[$element]);
unset($elementdata[$element]);

View file

@ -750,6 +750,22 @@ class core_coursecatlib_testcase extends advanced_testcase {
$this->assertEquals(1, count($courses[$c5->id]->get_course_overviewfiles()));
}
public function test_get_nested_name() {
$cat1name = 'Cat1';
$cat2name = 'Cat2';
$cat3name = 'Cat3';
$cat4name = 'Cat4';
$category1 = coursecat::create(array('name' => $cat1name));
$category2 = coursecat::create(array('name' => $cat2name, 'parent' => $category1->id));
$category3 = coursecat::create(array('name' => $cat3name, 'parent' => $category2->id));
$category4 = coursecat::create(array('name' => $cat4name, 'parent' => $category2->id));
$this->assertEquals($cat1name, $category1->get_nested_name(false));
$this->assertEquals("{$cat1name} / {$cat2name}", $category2->get_nested_name(false));
$this->assertEquals("{$cat1name} / {$cat2name} / {$cat3name}", $category3->get_nested_name(false));
$this->assertEquals("{$cat1name} / {$cat2name} / {$cat4name}", $category4->get_nested_name(false));
}
/**
* Creates a draft area for current user and fills it with fake files
*