Merge branch 'wip-MDL-38708-master' of git://github.com/marinaglancy/moodle

Conflicts:
	version.php
This commit is contained in:
Aparup Banerjee 2013-04-04 15:07:01 +08:00
commit 37240ce5c6
19 changed files with 211 additions and 12 deletions

View File

@ -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'));

View File

@ -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)

View File

@ -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) {

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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'));

View File

@ -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.';

View File

@ -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';

View File

@ -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';

View File

@ -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) {

View File

@ -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'),

View File

@ -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();
}

View File

@ -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,

View File

@ -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;}

View File

@ -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;
}

View File

@ -358,7 +358,7 @@ li.activity {
padding-bottom: 5px;
}
.coursebox .summary{
padding: 10px 0;
padding: 0 0 10px 0;
}
.que .info{
width: 10em;

View File

@ -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;}

View File

@ -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