mirror of
https://github.com/moodle/moodle.git
synced 2025-01-18 05:58:34 +01:00
Merge branch 'wip-MDL-38708-master' of git://github.com/marinaglancy/moodle
Conflicts: version.php
This commit is contained in:
commit
37240ce5c6
@ -200,6 +200,10 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
|
||||
new lang_string('courselistshortnames_desc', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configtext('coursesperpage', new lang_string('coursesperpage', 'admin'), new lang_string('configcoursesperpage', 'admin'), 20, PARAM_INT));
|
||||
$temp->add(new admin_setting_configtext('courseswithsummarieslimit', new lang_string('courseswithsummarieslimit', 'admin'), new lang_string('configcourseswithsummarieslimit', 'admin'), 10, PARAM_INT));
|
||||
$temp->add(new admin_setting_configtext('courseoverviewfileslimit', new lang_string('courseoverviewfileslimit'),
|
||||
new lang_string('configcourseoverviewfileslimit', 'admin'), 1, PARAM_INT));
|
||||
$temp->add(new admin_setting_configtext('courseoverviewfilesext', new lang_string('courseoverviewfilesext'),
|
||||
new lang_string('configcourseoverviewfilesext', 'admin'), '.jpg,.gif,.png'));
|
||||
$ADMIN->add('appearance', $temp);
|
||||
|
||||
$temp = new admin_settingpage('ajax', new lang_string('ajaxuse'));
|
||||
|
@ -511,6 +511,7 @@ class backup_course_structure_step extends backup_structure_step {
|
||||
$course->annotate_ids('grouping', 'defaultgroupingid');
|
||||
|
||||
$course->annotate_files('course', 'summary', null);
|
||||
$course->annotate_files('course', 'overviewfiles', null);
|
||||
$course->annotate_files('course', 'legacy', null);
|
||||
|
||||
// Return root element ($course)
|
||||
|
@ -1459,6 +1459,7 @@ class restore_course_structure_step extends restore_structure_step {
|
||||
|
||||
// Add course related files, without itemid to match
|
||||
$this->add_related_files('course', 'summary', null);
|
||||
$this->add_related_files('course', 'overviewfiles', null);
|
||||
|
||||
// Deal with legacy allowed modules.
|
||||
if ($this->legacyrestrictmodules) {
|
||||
|
@ -66,10 +66,14 @@ if ($id) { // editing course
|
||||
|
||||
// Prepare course and the editor
|
||||
$editoroptions = array('maxfiles' => EDITOR_UNLIMITED_FILES, 'maxbytes'=>$CFG->maxbytes, 'trusttext'=>false, 'noclean'=>true);
|
||||
$overviewfilesoptions = course_overviewfiles_options($course);
|
||||
if (!empty($course)) {
|
||||
//add context for editor
|
||||
$editoroptions['context'] = $coursecontext;
|
||||
$course = file_prepare_standard_editor($course, 'summary', $editoroptions, $coursecontext, 'course', 'summary', 0);
|
||||
if ($overviewfilesoptions) {
|
||||
file_prepare_standard_filemanager($course, 'overviewfiles', $overviewfilesoptions, $coursecontext, 'course', 'overviewfiles', 0);
|
||||
}
|
||||
|
||||
// Inject current aliases
|
||||
$aliases = $DB->get_records('role_names', array('contextid'=>$coursecontext->id));
|
||||
@ -81,6 +85,9 @@ if (!empty($course)) {
|
||||
//editor should respect category context if course context is not set.
|
||||
$editoroptions['context'] = $catcontext;
|
||||
$course = file_prepare_standard_editor($course, 'summary', $editoroptions, null, 'course', 'summary', null);
|
||||
if ($overviewfilesoptions) {
|
||||
file_prepare_standard_filemanager($course, 'overviewfiles', $overviewfilesoptions, null, 'course', 'overviewfiles', 0);
|
||||
}
|
||||
}
|
||||
|
||||
// first create the form
|
||||
|
@ -105,9 +105,16 @@ class course_edit_form extends moodleform {
|
||||
$mform->addElement('editor','summary_editor', get_string('coursesummary'), null, $editoroptions);
|
||||
$mform->addHelpButton('summary_editor', 'coursesummary');
|
||||
$mform->setType('summary_editor', PARAM_RAW);
|
||||
$summaryfields = 'summary_editor';
|
||||
|
||||
if ($overviewfilesoptions = course_overviewfiles_options($course)) {
|
||||
$mform->addElement('filemanager', 'overviewfiles_filemanager', get_string('courseoverviewfiles'), null, $overviewfilesoptions);
|
||||
$mform->addHelpButton('overviewfiles_filemanager', 'courseoverviewfiles');
|
||||
$summaryfields .= ',overviewfiles_filemanager';
|
||||
}
|
||||
|
||||
if (!empty($course->id) and !has_capability('moodle/course:changesummary', $coursecontext)) {
|
||||
$mform->hardFreeze('summary_editor');
|
||||
$mform->hardFreeze($summaryfields);
|
||||
}
|
||||
|
||||
$courseformats = get_sorted_course_formats(true);
|
||||
|
@ -2176,6 +2176,53 @@ function save_local_role_names($courseid, $data) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns options to use in course overviewfiles filemanager
|
||||
*
|
||||
* @param null|stdClass|course_in_list|int $course either object that has 'id' property or just the course id;
|
||||
* may be empty if course does not exist yet (course create form)
|
||||
* @return array|null array of options such as maxfiles, maxbytes, accepted_types, etc.
|
||||
* or null if overviewfiles are disabled
|
||||
*/
|
||||
function course_overviewfiles_options($course) {
|
||||
global $CFG;
|
||||
if (empty($CFG->courseoverviewfileslimit)) {
|
||||
return null;
|
||||
}
|
||||
$accepted_types = preg_split('/\s*,\s*/', trim($CFG->courseoverviewfilesext), -1, PREG_SPLIT_NO_EMPTY);
|
||||
if (in_array('*', $accepted_types) || empty($accepted_types)) {
|
||||
$accepted_types = '*';
|
||||
} else {
|
||||
// Since config for $CFG->courseoverviewfilesext is a text box, human factor must be considered.
|
||||
// Make sure extensions are prefixed with dot unless they are valid typegroups
|
||||
foreach ($accepted_types as $i => $type) {
|
||||
if (substr($type, 0, 1) !== '.') {
|
||||
require_once($CFG->libdir. '/filelib.php');
|
||||
if (!count(file_get_typegroup('extension', $type))) {
|
||||
// It does not start with dot and is not a valid typegroup, this is most likely extension.
|
||||
$accepted_types[$i] = '.'. $type;
|
||||
$corrected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($corrected)) {
|
||||
set_config('courseoverviewfilesext', join(',', $accepted_types));
|
||||
}
|
||||
}
|
||||
$options = array(
|
||||
'maxfiles' => $CFG->courseoverviewfileslimit,
|
||||
'maxbytes' => $CFG->maxbytes,
|
||||
'subdirs' => 0,
|
||||
'accepted_types' => $accepted_types
|
||||
);
|
||||
if (!empty($course->id)) {
|
||||
$options['context'] = context_course::instance($course->id);
|
||||
} else if (is_int($course) && $course > 0) {
|
||||
$options['context'] = context_course::instance($course);
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a course and either return a $course object
|
||||
*
|
||||
@ -2233,6 +2280,10 @@ function create_course($data, $editoroptions = NULL) {
|
||||
$DB->set_field('course', 'summary', $data->summary, array('id'=>$newcourseid));
|
||||
$DB->set_field('course', 'summaryformat', $data->summary_format, array('id'=>$newcourseid));
|
||||
}
|
||||
if ($overviewfilesoptions = course_overviewfiles_options($newcourseid)) {
|
||||
// Save the course overviewfiles
|
||||
$data = file_postupdate_standard_filemanager($data, 'overviewfiles', $overviewfilesoptions, $context, 'course', 'overviewfiles', 0);
|
||||
}
|
||||
|
||||
// update course format options
|
||||
course_get_format($newcourseid)->update_course_format_options($data);
|
||||
@ -2287,6 +2338,9 @@ function update_course($data, $editoroptions = NULL) {
|
||||
if ($editoroptions) {
|
||||
$data = file_postupdate_standard_editor($data, 'summary', $editoroptions, $context, 'course', 'summary', 0);
|
||||
}
|
||||
if ($overviewfilesoptions = course_overviewfiles_options($data->id)) {
|
||||
$data = file_postupdate_standard_filemanager($data, 'overviewfiles', $overviewfilesoptions, $context, 'course', 'overviewfiles', 0);
|
||||
}
|
||||
|
||||
if (!isset($data->category) or empty($data->category)) {
|
||||
// prevent nulls and 0 in category field
|
||||
|
@ -1070,7 +1070,7 @@ class core_course_renderer extends plugin_renderer_base {
|
||||
// If we display course in collapsed form but the course has summary or course contacts, display the link to the info page.
|
||||
$content .= html_writer::start_tag('div', array('class' => 'moreinfo'));
|
||||
if ($chelper->get_show_courses() < self::COURSECAT_SHOW_COURSES_EXPANDED) {
|
||||
if ($course->has_summary() || $course->has_course_contacts()) {
|
||||
if ($course->has_summary() || $course->has_course_contacts() || $course->has_course_overviewfiles()) {
|
||||
$url = new moodle_url('/course/info.php', array('id' => $course->id));
|
||||
$image = html_writer::empty_tag('img', array('src' => $this->output->pix_url('i/info'),
|
||||
'alt' => $this->strings->summary));
|
||||
@ -1126,6 +1126,23 @@ class core_course_renderer extends plugin_renderer_base {
|
||||
$content .= html_writer::end_tag('div'); // .summary
|
||||
}
|
||||
|
||||
// display course overview files
|
||||
foreach ($course->get_course_overviewfiles() as $file) {
|
||||
$isimage = $file->is_valid_image();
|
||||
$url = file_encode_url("$CFG->wwwroot/pluginfile.php",
|
||||
'/'. $file->get_contextid(). '/'. $file->get_component(). '/'.
|
||||
$file->get_filearea(). $file->get_filepath(). $file->get_filename(), !$isimage);
|
||||
if ($isimage) {
|
||||
$content .= html_writer::tag('div',
|
||||
html_writer::empty_tag('img', array('src' => $url)),
|
||||
array('class' => 'courseimage'));
|
||||
} else {
|
||||
$content .= html_writer::tag('div',
|
||||
html_writer::link($url, $file->get_filename()),
|
||||
array('class' => 'coursefile'));
|
||||
}
|
||||
}
|
||||
|
||||
// display course contacts. See course_in_list::get_course_contacts()
|
||||
if ($course->has_course_contacts()) {
|
||||
$content .= html_writer::start_tag('ul', array('class' => 'teachers'));
|
||||
|
@ -152,6 +152,8 @@ $string['configconvertformat'] = 'If <i>latex</i>, <i>dvips</i> and <i>convert</
|
||||
$string['configcookiehttponly'] = 'Enables new PHP 5.2.0 feature - browsers are instructed to send cookie with real http requests only, cookies should not be accessible by scripting languages. This is not supported in all browsers and it may not be fully compatible with current code. It helps to prevent some types of XSS attacks.';
|
||||
$string['configcookiesecure'] = 'If server is accepting only https connections it is recommended to enable sending of secure cookies. If enabled please make sure that web server is not accepting http:// or set up permanent redirection to https:// address. When <em>wwwroot</em> address does not start with https:// this setting is turned off automatically.';
|
||||
$string['configcountry'] = 'If you set a country here, then this country will be selected by default on new user accounts. To force users to choose a country, just leave this unset.';
|
||||
$string['configcourseoverviewfilesext'] = 'Comma-separated list of allowed course overview files extensions';
|
||||
$string['configcourseoverviewfileslimit'] = 'Limit the number of files course managers are allowed to add to the course. They will be accessible by anyone from outside of the course just like course name and/or summary';
|
||||
$string['configcourserequestnotify'] = 'Type username of user to be notified when new course requested.';
|
||||
$string['configcourserequestnotify2'] = 'Users who will be notified when a course is requested. Only users who can approve course requests are listed here.';
|
||||
$string['configcoursesperpage'] = 'Enter the number of courses to be displayed per page in a course listing.';
|
||||
|
@ -322,6 +322,10 @@ $string['coursehelpnewsitemsnumber'] = 'Number of recent items appearing on the
|
||||
$string['coursehelpnumberweeks'] = 'Number of sections in the course (applies to certain course formats only).';
|
||||
$string['coursehelpshowgrades'] = 'Enable the display of the gradebook. It does not prevent grades from being displayed within the individual activities.';
|
||||
$string['coursehidden'] = 'This course is currently unavailable to students';
|
||||
$string['courseoverviewfiles'] = 'Course overview files';
|
||||
$string['courseoverviewfilesext'] = 'Course overview files extensions';
|
||||
$string['courseoverviewfileslimit'] = 'Course overview files limit';
|
||||
$string['courseoverviewfiles_help'] = 'Course overview files (usually images) are displayed in the list of courses together with summary';
|
||||
$string['courseinfo'] = 'Course info';
|
||||
$string['coursemessage'] = 'Message course users';
|
||||
$string['coursenotaccessible'] = 'This course does not allow public access';
|
||||
|
@ -38,6 +38,7 @@ $string['sectionbackup'] = 'Section backups';
|
||||
$string['activitybackup'] = 'Activity backup';
|
||||
$string['areacategoryintro'] = 'Category introduction';
|
||||
$string['areacourseintro'] = 'Course introduction';
|
||||
$string['areacourseoverviewfiles'] = 'Course overview files';
|
||||
$string['arearoot'] = 'System';
|
||||
$string['areauserdraft'] = 'Drafts';
|
||||
$string['areauserbackup'] = 'User backup';
|
||||
|
@ -2058,6 +2058,53 @@ class course_in_list implements IteratorAggregate {
|
||||
return $this->coursecontacts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if course has any associated overview files
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has_course_overviewfiles() {
|
||||
global $CFG;
|
||||
if (empty($CFG->courseoverviewfileslimit)) {
|
||||
return 0;
|
||||
}
|
||||
require_once($CFG->libdir. '/filestorage/file_storage.php');
|
||||
$fs = get_file_storage();
|
||||
$context = context_course::instance($this->id);
|
||||
return $fs->is_area_empty($context->id, 'course', 'overviewfiles');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all course overview files
|
||||
*
|
||||
* @return array array of stored_file objects
|
||||
*/
|
||||
public function get_course_overviewfiles() {
|
||||
global $CFG;
|
||||
if (empty($CFG->courseoverviewfileslimit)) {
|
||||
return array();
|
||||
}
|
||||
require_once($CFG->libdir. '/filestorage/file_storage.php');
|
||||
$fs = get_file_storage();
|
||||
$context = context_course::instance($this->id);
|
||||
$files = $fs->get_area_files($context->id, 'course', 'overviewfiles', false, 'filename', false);
|
||||
if (count($files)) {
|
||||
$overviewfilesoptions = course_overviewfiles_options($this->id);
|
||||
$acceptedtypes = $overviewfilesoptions['accepted_types'];
|
||||
if ($acceptedtypes !== '*') {
|
||||
// filter only files with allowed extensions
|
||||
require_once($CFG->libdir. '/filelib.php');
|
||||
$files = array_filter($files, function ($file) use ($acceptedtypes) {
|
||||
return file_extension_in_typegroup($file->get_filename(), $acceptedtypes);} );
|
||||
}
|
||||
if (count($files) > $CFG->courseoverviewfileslimit) {
|
||||
// return no more than $CFG->courseoverviewfileslimit files
|
||||
$files = array_slice($files, 0, $CFG->courseoverviewfileslimit, true);
|
||||
}
|
||||
}
|
||||
return $files;
|
||||
}
|
||||
|
||||
// ====== magic methods =======
|
||||
|
||||
public function __isset($name) {
|
||||
|
@ -120,6 +120,40 @@ class file_info_context_course extends file_info {
|
||||
return new file_info_stored($this->browser, $this->context, $storedfile, $urlbase, get_string('areacourseintro', 'repository'), false, true, true, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a stored file for the course images filearea directory
|
||||
*
|
||||
* @param int $itemid item ID
|
||||
* @param string $filepath file path
|
||||
* @param string $filename file name
|
||||
* @return file_info|null file_info instance or null if not found or access not allowed
|
||||
*/
|
||||
protected function get_area_course_overviewfiles($itemid, $filepath, $filename) {
|
||||
global $CFG;
|
||||
|
||||
if (!has_capability('moodle/course:update', $this->context)) {
|
||||
return null;
|
||||
}
|
||||
if (is_null($itemid)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$fs = get_file_storage();
|
||||
|
||||
$filepath = is_null($filepath) ? '/' : $filepath;
|
||||
$filename = is_null($filename) ? '.' : $filename;
|
||||
if (!$storedfile = $fs->get_file($this->context->id, 'course', 'overviewfiles', 0, $filepath, $filename)) {
|
||||
if ($filepath === '/' and $filename === '.') {
|
||||
$storedfile = new virtual_root_file($this->context->id, 'course', 'overviewfiles', 0);
|
||||
} else {
|
||||
// not found
|
||||
return null;
|
||||
}
|
||||
}
|
||||
$urlbase = $CFG->wwwroot.'/pluginfile.php';
|
||||
return new file_info_stored($this->browser, $this->context, $storedfile, $urlbase, get_string('areacourseoverviewfiles', 'repository'), false, true, true, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a stored file for the course section filearea directory
|
||||
*
|
||||
@ -365,6 +399,7 @@ class file_info_context_course extends file_info {
|
||||
private function get_filtered_children($extensions = '*', $countonly = false, $returnemptyfolders = false) {
|
||||
$areas = array(
|
||||
array('course', 'summary'),
|
||||
array('course', 'overviewfiles'),
|
||||
array('course', 'section'),
|
||||
array('backup', 'section'),
|
||||
array('backup', 'course'),
|
||||
|
@ -4100,14 +4100,14 @@ function file_pluginfile($relativepath, $forcedownload, $preview = null) {
|
||||
send_file_not_found();
|
||||
}
|
||||
|
||||
if ($filearea === 'summary') {
|
||||
if ($filearea === 'summary' || $filearea === 'overviewfiles') {
|
||||
if ($CFG->forcelogin) {
|
||||
require_login();
|
||||
}
|
||||
|
||||
$filename = array_pop($args);
|
||||
$filepath = $args ? '/'.implode('/', $args).'/' : '/';
|
||||
if (!$file = $fs->get_file($context->id, 'course', 'summary', 0, $filepath, $filename) or $file->is_directory()) {
|
||||
if (!$file = $fs->get_file($context->id, 'course', $filearea, 0, $filepath, $filename) or $file->is_directory()) {
|
||||
send_file_not_found();
|
||||
}
|
||||
|
||||
|
@ -116,7 +116,9 @@ li.section.hidden span.commands a.editing_show {cursor:default;}
|
||||
.coursebox .name a {display:block;background-image:url([[pix:moodle|i/course]]);background-repeat: no-repeat;padding-left:21px;background-position: center left;}
|
||||
.coursebox.remotehost .name a {background-image:url([[pix:moodle|i/mnethost]]);}
|
||||
.coursebox .name,
|
||||
.coursebox .teachers {float:left;width: 40%;}
|
||||
.coursebox .teachers,
|
||||
.coursebox .content .courseimage,
|
||||
.coursebox .content .coursefile {float:left;width:40%;clear:left;}
|
||||
.coursebox .teachers li {list-style-type:none;padding:0;margin:0;}
|
||||
.coursebox .enrolmenticons {padding:3px 0;float:right;}
|
||||
.coursebox .moreinfo {padding:3px 0;float:right;}
|
||||
@ -127,10 +129,13 @@ li.section.hidden span.commands a.editing_show {cursor:default;}
|
||||
.coursebox .coursecat {float:right;width: 55%;}
|
||||
.coursebox .coursecat {text-align:right;clear:right;}
|
||||
.coursebox.remotecoursebox .remotecourseinfo {float:left;width: 40%;}
|
||||
.coursebox .content .courseimage img {max-width:100px;max-height:100px;}
|
||||
|
||||
.dir-rtl .coursebox .name a {padding-left:0;padding-right:21px;background-position: center right;}
|
||||
.dir-rtl .coursebox .name,
|
||||
.dir-rtl .coursebox .teachers {float:right;}
|
||||
.dir-rtl .coursebox .teachers,
|
||||
.dir-rtl .coursebox .content .courseimage,
|
||||
.dir-rtl .coursebox .content .coursefile {float:right;clear:right;}
|
||||
.dir-rtl .coursebox .enrolmenticons,
|
||||
.dir-rtl .coursebox .moreinfo {float:left;}
|
||||
.dir-rtl .coursebox .summary,
|
||||
|
@ -17,7 +17,9 @@
|
||||
.coursebox .content {font-size:90%;}
|
||||
.coursebox .teachers {margin:5px 1em;}
|
||||
.coursebox .summary,
|
||||
.coursebox .coursecat {margin:5px;}
|
||||
.coursebox .coursecat,
|
||||
.coursebox .content .courseimage,
|
||||
.coursebox .content .coursefile {margin:5px;}
|
||||
.coursebox > .content:after,
|
||||
.coursebox > .info:after {clear:both;content:".";display:block;height:0;min-width:0;visibility:hidden;}
|
||||
|
||||
|
@ -924,15 +924,25 @@ div.coursebox h3.name a {
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.dir-rtl .coursebox ul.teachers {
|
||||
.coursebox .content .courseimage,
|
||||
.coursebox .content .coursefile {
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.dir-rtl .coursebox ul.teachers,
|
||||
.dir-rtl .coursebox .content .courseimage,
|
||||
.dir-rtl .coursebox .content .coursefile {
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.coursebox ul.teachers li {
|
||||
.coursebox ul.teachers li,
|
||||
.coursebox .coursecat {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.coursebox ul.teachers li a {
|
||||
.coursebox ul.teachers li a,
|
||||
.coursebox .coursecat a,
|
||||
.coursebox .content .coursefile a {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
|
@ -358,7 +358,7 @@ li.activity {
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
.coursebox .summary{
|
||||
padding: 10px 0;
|
||||
padding: 0 0 10px 0;
|
||||
}
|
||||
.que .info{
|
||||
width: 10em;
|
||||
|
@ -82,6 +82,8 @@
|
||||
.coursebox .teachers {padding:3px 0 3px 21px;margin:0;font-size:0.9em;}
|
||||
.coursebox .coursecat,
|
||||
.coursebox .summary,
|
||||
.coursebox .courseimage,
|
||||
.coursebox .coursefile,
|
||||
.coursebox.remotecoursebox .remotecourseinfo {padding:3px 5px;font-size:0.9em;}
|
||||
.dir-rtl .coursebox .teachers {padding:3px 21px 3px 0;}
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$version = 2013040300.01; // YYYYMMDD = weekly release date of this DEV branch
|
||||
$version = 2013040300.02; // YYYYMMDD = weekly release date of this DEV branch
|
||||
// RR = release increments - 00 in DEV branches
|
||||
// .XX = incremental changes
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user