exit(1);
}
} else {
- cli_error(get_string('maturitycorewarning', 'admin'));
+ cli_problem(get_string('maturitycorewarning', 'admin', $maturitylevel));
+ cli_error(get_string('maturityallowunstable', 'admin'));
}
}
}
}
// now get cli options
-list($options, $unrecognized) = cli_get_params(array('help'=>false, 'list'=>false, 'engine'=>false),
- array('h'=>'help', 'l'=>'list'));
+list($options, $unrecognized) = cli_get_params(array('help'=>false, 'list'=>false, 'engine'=>false, 'available'=>false),
+ array('h'=>'help', 'l'=>'list', 'a'=>'available'));
if ($unrecognized) {
$unrecognized = implode("\n ", $unrecognized);
Options:
--engine=ENGINE Convert MySQL tables to different engine
-l, --list Show table information
+-a, --available Show list of available engines
-h, --help Print out this help
Example:
";
if (!empty($options['engine'])) {
+ $engines = mysql_get_engines();
$engine = clean_param($options['engine'], PARAM_ALPHA);
+ if (!isset($engines[strtoupper($engine)])) {
+ cli_error("Error: engine '$engine' is not available on this server!");
+ }
echo "Converting tables to '$engine' for $CFG->wwwroot:\n";
$prefix = $DB->get_prefix();
$rs = $DB->get_recordset_sql($sql);
$converted = 0;
$skipped = 0;
+ $errors = 0;
foreach ($rs as $table) {
- if ($table->engine === $engine) {
- echo str_pad($table->name, 40). " - NO CONVERSION NEEDED\n";
+ if (strtoupper($table->engine) === strtoupper($engine)) {
+ $newengine = mysql_get_table_engine($table->name);
+ echo str_pad($table->name, 40). " - NO CONVERSION NEEDED ($newengine)\n";
$skipped++;
continue;
}
try {
$DB->change_database_structure("ALTER TABLE {$table->name} ENGINE = $engine");
+ $newengine = mysql_get_table_engine($table->name);
+ if (strtoupper($newengine) !== strtoupper($engine)) {
+ echo "ERROR ($newengine)\n";
+ $errors++;
+ continue;
+ }
+ echo "DONE ($newengine)\n";
+ $converted++;
} catch (moodle_exception $e) {
echo $e->getMessage()."\n";
- $skipped++;
+ $errors++;
continue;
}
- echo "DONE\n";
- $converted++;
}
$rs->close();
- echo "Converted: $converted, skipped: $skipped\n";
+ echo "Converted: $converted, skipped: $skipped, errors: $errors\n";
exit(0); // success
} else if (!empty($options['list'])) {
}
exit(0); // success
+} else if (!empty($options['available'])) {
+ echo "List of available MySQL engines for $CFG->wwwroot:\n";
+ $engines = mysql_get_engines();
+ foreach ($engines as $engine) {
+ echo " $engine\n";
+ }
+ die;
+
} else {
echo $help;
die;
}
+
+
+
+// ========== Some functions ==============
+
+function mysql_get_engines() {
+ global $DB;
+
+ $sql = "SHOW Engines";
+ $rs = $DB->get_recordset_sql($sql);
+ $engines = array();
+ foreach ($rs as $engine) {
+ if (strtoupper($engine->support) !== 'YES' and strtoupper($engine->support) !== 'DEFAULT') {
+ continue;
+ }
+ $engines[strtoupper($engine->engine)] = $engine->engine;
+ if (strtoupper($engine->support) === 'DEFAULT') {
+ $engines[strtoupper($engine->engine)] .= ' (default)';
+ }
+ }
+ $rs->close();
+
+ return $engines;
+}
+
+function mysql_get_table_engine($tablename) {
+ global $DB;
+
+ $engine = null;
+ $sql = "SHOW TABLE STATUS WHERE Name = '$tablename'"; // no special chars expected here
+ $rs = $DB->get_recordset_sql($sql);
+ if ($rs->valid()) {
+ $record = $rs->current();
+ $engine = $record->engine;
+ }
+ $rs->close();
+ return $engine;
+}
echo get_string('morehelp') . ': ' . get_docs_url('admin/versions') . PHP_EOL;
cli_separator();
} else {
- cli_error(get_string('maturitycorewarning', 'admin', $maturitylevel));
+ cli_problem(get_string('maturitycorewarning', 'admin', $maturitylevel));
+ cli_error(get_string('maturityallowunstable', 'admin'));
}
}
}
$discussion->groupid = $groupid;
$message = '';
- $discussionid = forum_add_discussion($discussion, null, $message);
+ $discussionid = forum_add_discussion($discussion, null, $message, $blogentry->userid);
// Copy file attachment records
$fs = get_file_storage();
/// If we can find the Shibboleth attribute, save it in session and return to main login page
if (!empty($_SERVER[$pluginconfig->user_attribute])) { // Shibboleth auto-login
+ $frm = new stdClass();
$frm->username = strtolower($_SERVER[$pluginconfig->user_attribute]);
$frm->password = substr(base64_encode($_SERVER[$pluginconfig->user_attribute]),0,8);
// The random password consists of the first 8 letters of the base 64 encoded user ID
$rules[] = new restore_log_rule('course', 'report outline', 'report/outline/index.php?id={course}', '{course}');
$rules[] = new restore_log_rule('course', 'report participation', 'report/participation/index.php?id={course}', '{course}');
$rules[] = new restore_log_rule('course', 'report stats', 'report/stats/index.php?id={course}', '{course}');
+ $rules[] = new restore_log_rule('course', 'view section', 'view.php?id={course}§ion={course_sectionnumber}', '{course}');
// module 'user' rules
$rules[] = new restore_log_rule('user', 'view', 'view.php?id={user}&course={course}', '{user}');
global $CFG, $DB;
$data = (object)$data;
$oldid = $data->id; // We'll need this later
+ $oldsection = $data->number;
$restorefiles = false;
$DB->update_record('course_sections', $section);
$newitemid = $secrec->id;
+ $oldsection = $secrec->section;
}
// Annotate the section mapping, with restorefiles option if needed
$this->set_mapping('course_section', $oldid, $newitemid, $restorefiles);
+ $this->set_mapping('course_sectionnumber', $oldsection, $section->section, $restorefiles);
// set the new course_section id in the task
$this->task->set_sectionid($newitemid);
$data = (object)$data;
$oldid = $data->id;
-
+ $oldsection = $data->sectionnumber;
$this->task->set_old_moduleversion($data->version);
$data->course = $this->task->get_courseid();
'course' => $this->get_courseid(),
'section' => 1);
$data->section = $DB->insert_record('course_sections', $sectionrec); // section 1
+ $this->set_mapping('course_sectionnumber', $oldsection, $sectionrec->section, $restorefiles);
}
$data->groupingid= $this->get_mappingid('grouping', $data->groupingid); // grouping
if (!$CFG->enablegroupmembersonly) { // observe groupsmemberonly
*/
public static function launch_automated_backup($course, $starttime, $userid) {
+ $outcome = true;
$config = get_config('backup');
$bc = new backup_controller(backup::TYPE_1COURSE, $course->id, backup::FORMAT_MOODLE, backup::INTERACTIVE_NO, backup::MODE_AUTOMATED, $userid);
$bc->set_status(backup::STATUS_AWAITING);
- $outcome = $bc->execute_plan();
+ $bc->execute_plan();
$results = $bc->get_results();
$file = $results['backup_destination'];
$dir = $config->backup_auto_destination;
}
}
- $outcome = true;
- } catch (backup_exception $e) {
- $bc->log('backup_auto_failed_on_course', backup::LOG_WARNING, $course->shortname);
+ } catch (moodle_exception $e) {
+ $bc->log('backup_auto_failed_on_course', backup::LOG_ERROR, $course->shortname); // Log error header.
+ $bc->log('Exception: ' . $e->errorcode, backup::LOG_ERROR, $e->a, 1); // Log original exception problem.
+ $bc->log('Debug: ' . $e->debuginfo, backup::LOG_DEBUG, null, 1); // Log original debug information.
$outcome = false;
}
$bc->destroy();
unset($bc);
- return true;
+ return $outcome;
}
/**
$days_title = calendar_get_days();
$summary = get_string('calendarheading', 'calendar', userdate(make_timestamp($y, $m), get_string('strftimemonthyear')));
- $summary = get_string('tabledata', 'access', $summary);
$content .= '<table class="minicalendar calendartable" summary="'.$summary.'">'; // Begin table
$content .= '<tr class="weekdays">'; // Header row: day names
*/
abstract protected function page_title();
+ /**
+ * Generate the section title
+ *
+ * @param stdClass $section The course_section entry from DB
+ * @param stdClass $course The course entry from DB
+ * @return string HTML to output.
+ */
+ public function section_title($section, $course) {
+ $title = get_section_name($course, $section);
+ if ($section->section != 0 && $course->coursedisplay == COURSE_DISPLAY_MULTIPAGE) {
+ $title = html_writer::link(course_get_url($course, $section->section), $title);
+ }
+ return $title;
+ }
+
/**
* Generate the content to displayed on the right part of a section
* before course modules are included
*
* @param stdClass $section The course_section entry from DB
* @param stdClass $course The course entry from DB
- * @param bool $onsectionpage true if being printed on a section page
+ * @param bool $onsectionpage true if being printed on a single-section page
* @return string HTML to output.
*/
protected function section_header($section, $course, $onsectionpage) {
$o = '';
$currenttext = '';
$sectionstyle = '';
- $linktitle = false;
if ($section->section != 0) {
// Only in the non-general sections.
} else if ($this->is_section_current($section, $course)) {
$sectionstyle = ' current';
}
- $linktitle = ($course->coursedisplay == COURSE_DISPLAY_MULTIPAGE);
}
$o.= html_writer::start_tag('li', array('id' => 'section-'.$section->section,
$o.= html_writer::start_tag('div', array('class' => 'content'));
if (!$onsectionpage) {
- $title = get_section_name($course, $section);
- if ($linktitle) {
- $title = html_writer::link(course_get_url($course, $section->section), $title);
- }
- $o.= $this->output->heading($title, 3, 'sectionname');
+ $o.= $this->output->heading($this->section_title($section, $course), 3, 'sectionname');
}
$o.= html_writer::start_tag('div', array('class' => 'summary'));
-// Javascript functions for course format
+// Javascript functions for Topics course format
M.course = M.course || {};
M.course.format.swap_sections = function(Y, node1, node2) {
var CSS = {
COURSECONTENT : 'course-content',
- LEFT : 'left',
SECTIONADDMENUS : 'section_add_menus'
};
var sectionlist = Y.Node.all('.'+CSS.COURSECONTENT+' '+M.course.format.get_section_selector(Y));
- // Swap left block
- sectionlist.item(node1).one('.'+CSS.LEFT).swap(sectionlist.item(node2).one('.'+CSS.LEFT));
// Swap menus
sectionlist.item(node1).one('.'+CSS.SECTIONADDMENUS).swap(sectionlist.item(node2).one('.'+CSS.SECTIONADDMENUS));
}
+
+/**
+ * Process sections after ajax response
+ *
+ * @param {YUI} Y YUI3 instance
+ * @param {array} response ajax response
+ * @param {string} sectionfrom first affected section
+ * @param {string} sectionto last affected section
+ * @return void
+ */
+M.course.format.process_sections = function(Y, sectionlist, response, sectionfrom, sectionto) {
+ var CSS = {
+ SECTIONNAME : 'sectionname'
+ };
+
+ if (response.action == 'move') {
+ // update titles in all affected sections
+ for (var i = sectionfrom; i <= sectionto; i++) {
+ sectionlist.item(i).one('.'+CSS.SECTIONNAME).setContent(response.sectiontitles[i]);
+ }
+ }
+}
$ajaxsupport->testedbrowsers = array('MSIE' => 6.0, 'Gecko' => 20061111, 'Safari' => 531, 'Chrome' => 6.0);
return $ajaxsupport;
}
+
+/**
+ * Callback function to do some action after section move
+ *
+ * @param stdClass $course The course entry from DB
+ * @return array This will be passed in ajax respose.
+ */
+function callback_topics_ajax_section_move($course) {
+ global $COURSE, $PAGE;
+
+ $titles = array();
+ rebuild_course_cache($course->id);
+ $modinfo = get_fast_modinfo($COURSE);
+ $renderer = $PAGE->get_renderer('format_topics');
+ if ($renderer && ($sections = $modinfo->get_section_info_all())) {
+ foreach ($sections as $number => $section) {
+ $titles[$number] = $renderer->section_title($section, $course);
+ }
+ }
+ return array('sectiontitles' => $titles, 'action' => 'move');
+}
-// Javascript functions for course format
+// Javascript functions for Weeks course format
M.course = M.course || {};
M.course.format.swap_sections = function(Y, node1, node2) {
var CSS = {
COURSECONTENT : 'course-content',
- LEFT : 'left',
SECTIONADDMENUS : 'section_add_menus',
- WEEKDATES: 'sectionname'
};
var sectionlist = Y.Node.all('.'+CSS.COURSECONTENT+' '+M.course.format.get_section_selector(Y));
- // Swap left block
- sectionlist.item(node1).one('.'+CSS.LEFT).swap(sectionlist.item(node2).one('.'+CSS.LEFT));
// Swap menus
sectionlist.item(node1).one('.'+CSS.SECTIONADDMENUS).swap(sectionlist.item(node2).one('.'+CSS.SECTIONADDMENUS));
- // Swap week dates
- sectionlist.item(node1).one('.'+CSS.WEEKDATES).swap(sectionlist.item(node2).one('.'+CSS.WEEKDATES));
+}
+
+/**
+ * Process sections after ajax response
+ *
+ * @param {YUI} Y YUI3 instance
+ * @param {array} response ajax response
+ * @param {string} sectionfrom first affected section
+ * @param {string} sectionto last affected section
+ * @return void
+ */
+M.course.format.process_sections = function(Y, sectionlist, response, sectionfrom, sectionto) {
+ var CSS = {
+ SECTIONNAME : 'sectionname'
+ };
+
+ if (response.action == 'move') {
+ // update titles in all affected sections
+ for (var i = sectionfrom; i <= sectionto; i++) {
+ sectionlist.item(i).one('.'+CSS.SECTIONNAME).setContent(response.sectiontitles[i]);
+ }
+ }
}
return $dates;
}
+
+/**
+ * Callback function to do some action after section move
+ *
+ * @param stdClass $course The course entry from DB
+ * @return array This will be passed in ajax respose.
+ */
+function callback_weeks_ajax_section_move($course) {
+ global $COURSE, $PAGE;
+
+ $titles = array();
+ rebuild_course_cache($course->id);
+ $modinfo = get_fast_modinfo($COURSE);
+ $renderer = $PAGE->get_renderer('format_weeks');
+ if ($renderer && ($sections = $modinfo->get_section_info_all())) {
+ foreach ($sections as $number => $section) {
+ $titles[$number] = $renderer->section_title($section, $course);
+ }
+ }
+ return array('sectiontitles' => $titles, 'action' => 'move');
+}
// see the activity itself, or for staff)
if (!$mod->uservisible) {
echo '<div class="availabilityinfo">'.$mod->availableinfo.'</div>';
- } else if ($canviewhidden && !empty($CFG->enableavailability)) {
+ } else if ($canviewhidden && !empty($CFG->enableavailability) && $mod->visible) {
$ci = new condition_info($mod);
$fullinfo = $ci->get_full_information();
if($fullinfo) {
}
$n++;
}
+ // After moving section, rebuild course cache.
+ rebuild_course_cache($course->id, true);
return true;
}
echo $OUTPUT->spacer(array('height'=>30, 'br'=>true)); // should be done with CSS instead
}
echo $OUTPUT->box_start();
- echo "<h2>$activity->name</h2>";
+ if (!empty($activity->name)) {
+ echo html_writer::tag('h2', $activity->name);
+ }
$inbox = true;
} else if ($activity->type == 'activity') {
$cm = $modinfo->cms[$activity->cmid];
if ($cm->visible) {
- $linkformat = '';
+ $class = '';
} else {
- $linkformat = 'class="dimmed"';
+ $class = 'dimmed';
}
$name = format_string($cm->name);
$modfullname = $modnames[$cm->modname];
- $image = "<img src=\"" . $OUTPUT->pix_url('icon', $cm->modname) . "\" class=\"icon\" alt=\"$modfullname\" />";
- echo "<h3>$image $modfullname".
- " <a href=\"$CFG->wwwroot/mod/$cm->modname/view.php?id=$cm->id\" $linkformat>$name</a></h3>";
+ $image = $OUTPUT->pix_icon('icon', $modfullname, $cm->modname, array('class' => 'icon smallicon'));
+ $link = html_writer::link(new moodle_url("/mod/$cm->modname/view.php",
+ array("id" => $cm->id)), $name, array('class' => $class));
+ echo html_writer::tag('h3', "$image $modfullname $link");
}
} else {
} else {
- echo '<h3><center>' . get_string('norecentactivity') . '</center></h3>';
+ echo html_writer::tag('h3', get_string('norecentactivity'), array('class' => 'mdl-align'));
}
case 'move':
move_section_to($course, $id, $value);
+ // See if format wants to do something about it
+ $libfile = $CFG->dirroot.'/course/format/'.$course->format.'/lib.php';
+ $functionname = 'callback_'.$course->format.'_ajax_section_move';
+ if (!function_exists($functionname) && file_exists($libfile)) {
+ require_once $libfile;
+ }
+ if (function_exists($functionname)) {
+ echo json_encode($functionname($course));
+ }
break;
}
rebuild_course_cache($course->id);
require_once($CFG->dirroot.'/calendar/lib.php'); /// This is after login because it needs $USER
- //TODO: danp do we need different urls?
- add_to_log($course->id, 'course', 'view', "view.php?id=$course->id", "$course->id");
+ $logparam = 'id='. $course->id;
+ $loglabel = 'view';
+ $infoid = $course->id;
+ if(!empty($section)) {
+ $logparam .= '§ion='. $section;
+ $loglabel = 'view section';
+ $sectionparams = array('course' => $course->id, 'section' => $section);
+ if ($coursesections = $DB->get_record('course_sections', $sectionparams, 'id', MUST_EXIST)) {
+ $infoid = $coursesections->id;
+ }
+ }
+ add_to_log($course->id, 'course', $loglabel, "view.php?". $logparam, $infoid);
$course->format = clean_param($course->format, PARAM_ALPHA);
if (!file_exists($CFG->dirroot.'/course/format/'.$course->format.'/format.php')) {
return null;
}
+ /**
+ * Process sections after ajax response (should be defined in format.js)
+ * If some response is expected, we pass it over to format, as it knows better
+ * hot to process it.
+ *
+ * @param {YUI} Y YUI3 instance
+ * @param {NodeList} list of sections
+ * @param {array} response ajax response
+ * @param {string} sectionfrom first affected section
+ * @param {string} sectionto last affected section
+ * @return void
+ */
+ M.course.format.process_sections = M.course.format.process_sections || function(Y, sectionlist, response, sectionfrom, sectionto) {
+ return null;
+ }
/**
* Get sections config for this format, for examples see function definition
drag.get('dragNode').addClass(CSS.COURSECONTENT);
},
+ drag_dropmiss : function(e) {
+ // Missed the target, but we assume the user intended to drop it
+ // on the last last ghost node location, e.drag and e.drop should be
+ // prepared by global_drag_dropmiss parent so simulate drop_hit(e).
+ this.drop_hit(e);
+ },
+
drop_hit : function(e) {
var drag = e.drag;
// Get a reference to our drag node
lightbox.show();
},
success: function(tid, response) {
- window.setTimeout(function(e) {
- lightbox.hide();
- }, 250);
+ // Update section titles, we can't simply swap them as
+ // they might have custom title
+ try {
+ var responsetext = Y.JSON.parse(response.responseText);
+ if (responsetext.error) {
+ new M.core.ajaxException(responsetext);
+ }
+ M.course.format.process_sections(Y, sectionlist, responsetext, loopstart, loopend);
+ } catch (e) {}
+
// Classic bubble sort algorithm is applied to the section
// nodes between original drag node location and the new one.
do {
}
loopend = loopend - 1;
} while (swapped);
+
+ // Finally, hide the lightbox
+ window.setTimeout(function(e) {
+ lightbox.hide();
+ }, 250);
},
failure: function(tid, response) {
this.ajax_failure(response);
drag.get('dragNode').all('img.iconsmall').setStyle('vertical-align', 'baseline');
},
+ drag_dropmiss : function(e) {
+ // Missed the target, but we assume the user intended to drop it
+ // on the last last ghost node location, e.drag and e.drop should be
+ // prepared by global_drag_dropmiss parent so simulate drop_hit(e).
+ this.drop_hit(e);
+ },
+
drop_hit : function(e) {
var drag = e.drag;
// Get a reference to our drag node
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class graded_users_iterator {
- public $course;
- public $grade_items;
- public $groupid;
- public $users_rs;
- public $grades_rs;
- public $gradestack;
- public $sortfield1;
- public $sortorder1;
- public $sortfield2;
- public $sortorder2;
+
+ /**
+ * The couse whose users we are interested in
+ */
+ protected $course;
+
+ /**
+ * An array of grade items or null if only user data was requested
+ */
+ protected $grade_items;
+
+ /**
+ * The group ID we are interested in. 0 means all groups.
+ */
+ protected $groupid;
+
+ /**
+ * A recordset of graded users
+ */
+ protected $users_rs;
+
+ /**
+ * A recordset of user grades (grade_grade instances)
+ */
+ protected $grades_rs;
+
+ /**
+ * Array used when moving to next user while iterating through the grades recordset
+ */
+ protected $gradestack;
+
+ /**
+ * The first field of the users table by which the array of users will be sorted
+ */
+ protected $sortfield1;
+
+ /**
+ * Should sortfield1 be ASC or DESC
+ */
+ protected $sortorder1;
+
+ /**
+ * The second field of the users table by which the array of users will be sorted
+ */
+ protected $sortfield2;
+
+ /**
+ * Should sortfield2 be ASC or DESC
+ */
+ protected $sortorder2;
/**
* Should users whose enrolment has been suspended be ignored?
* @param string $sortfield2 The second field of the users table by which the array of users will be sorted
* @param string $sortorder2 The order in which the second sorting field will be sorted (ASC or DESC)
*/
- public function graded_users_iterator($course, $grade_items=null, $groupid=0,
+ public function __construct($course, $grade_items=null, $groupid=0,
$sortfield1='lastname', $sortorder1='ASC',
$sortfield2='firstname', $sortorder2='ASC') {
$this->course = $course;
/**
* Initialise the iterator
+ *
* @return boolean success
*/
public function init() {
* Returns information about the next user
* @return mixed array of user info, all grades and feedback or null when no more users found
*/
- function next_user() {
+ public function next_user() {
if (!$this->users_rs) {
return false; // no users present
}
}
/**
- * Close the iterator, do not forget to call this function.
- * @return void
+ * Close the iterator, do not forget to call this function
*/
- function close() {
+ public function close() {
if ($this->users_rs) {
$this->users_rs->close();
$this->users_rs = null;
/**
- * _push
+ * Add a grade_grade instance to the grade stack
*
* @param grade_grade $grade Grade object
*
* @return void
*/
- function _push($grade) {
+ private function _push($grade) {
array_push($this->gradestack, $grade);
}
/**
- * _pop
+ * Remove a grade_grade instance from the grade stack
*
- * @return object current grade object
+ * @return grade_grade current grade object
*/
- function _pop() {
+ private function _pop() {
global $DB;
if (empty($this->gradestack)) {
if (empty($this->grades_rs) || !$this->grades_rs->valid()) {
$string['skipblock'] = 'Skip block';
$string['skipnavigation'] = 'Skip navigation';
$string['skipto'] = 'Skip to {$a}';
-$string['tabledata'] = 'Data table, {$a}';
-$string['tablelayout'] = 'Layout table, {$a}';
$string['tocontent'] = 'Skip to main content';
$string['tonavigation'] = 'Go to navigation';
$string['youarehere'] = 'You are here';
$string['maturity100'] = 'Beta';
$string['maturity150'] = 'Release candidate';
$string['maturity200'] = 'Stable version';
+$string['maturityallowunstable'] = 'Hint: You may want to run this script with --allow-unstable option';
$string['maturitycoreinfo'] = 'Your site is currently running unstable "{$a}" development code.';
$string['maturitycorewarning'] = 'The version of Moodle that you are about to install or upgrade to contains
unstable "{$a}" development code that is not suitable for use on most production
* @param object $cm Moodle course-module object. May have extra fields
* ->conditionsgrade, ->conditionscompletion which should come from
* get_fast_modinfo. Should have ->availablefrom, ->availableuntil,
- * and ->showavailability, ->course; but the only required thing is ->id.
+ * and ->showavailability, ->course, ->visible; but the only required
+ * thing is ->id.
* @param int $expectingmissing Used to control whether or not a developer
* debugging message (performance warning) will be displayed if some of
* the above data is missing and needs to be retrieved; a
* @return array Array of field names
*/
protected function get_main_table_fields() {
- return array('id', 'course', 'availablefrom', 'availableuntil', 'showavailability');
+ return array('id', 'course', 'visible',
+ 'availablefrom', 'availableuntil', 'showavailability');
}
/**
}
}
+ // If the item is marked as 'not visible' then we don't change the available
+ // flag (visible/available are treated distinctly), but we remove any
+ // availability info. If the item is hidden with the eye icon, it doesn't
+ // make sense to show 'Available from <date>' or similar, because even
+ // when that date arrives it will still not be available unless somebody
+ // toggles the eye icon.
+ if (!$this->item->visible) {
+ $information = '';
+ }
+
$information = trim($information);
return $available;
}
</KEYS>
<INDEXES>
<INDEX NAME="course" UNIQUE="false" FIELDS="course" NEXT="criteriatype"/>
- <INDEX NAME="criteriatype" UNIQUE="false" FIELDS="criteriatype" PREVIOUS="course"/>
+ <INDEX NAME="criteriatype" UNIQUE="false" FIELDS="criteriatype" PREVIOUS="course" NEXT="coursecriteriatype"/>
+ <INDEX NAME="coursecriteriatype" UNIQUE="true" FIELDS="course, criteriatype" PREVIOUS="criteriatype"/>
</INDEXES>
</TABLE>
<TABLE NAME="course_completion_criteria" COMMENT="Course completion criteria" PREVIOUS="course_completion_aggr_methd" NEXT="course_completion_crit_compl">
<INDEX NAME="userid" UNIQUE="false" FIELDS="userid" NEXT="course"/>
<INDEX NAME="course" UNIQUE="false" FIELDS="course" PREVIOUS="userid" NEXT="criteriaid"/>
<INDEX NAME="criteriaid" UNIQUE="false" FIELDS="criteriaid" PREVIOUS="course" NEXT="timecompleted"/>
- <INDEX NAME="timecompleted" UNIQUE="false" FIELDS="timecompleted" PREVIOUS="criteriaid"/>
+ <INDEX NAME="timecompleted" UNIQUE="false" FIELDS="timecompleted" PREVIOUS="criteriaid" NEXT="useridcoursecriteriaid"/>
+ <INDEX NAME="useridcoursecriteriaid" UNIQUE="true" FIELDS="userid, course, criteriaid" PREVIOUS="timecompleted"/>
</INDEXES>
</TABLE>
<TABLE NAME="course_completion_notify" COMMENT="Course completion notification emails" PREVIOUS="course_completion_crit_compl" NEXT="course_completions">
<INDEXES>
<INDEX NAME="userid" UNIQUE="false" FIELDS="userid" NEXT="course"/>
<INDEX NAME="course" UNIQUE="false" FIELDS="course" PREVIOUS="userid" NEXT="timecompleted"/>
- <INDEX NAME="timecompleted" UNIQUE="false" FIELDS="timecompleted" PREVIOUS="course"/>
+ <INDEX NAME="timecompleted" UNIQUE="false" FIELDS="timecompleted" PREVIOUS="course" NEXT="useridcourse"/>
+ <INDEX NAME="useridcourse" UNIQUE="true" FIELDS="userid, course" PREVIOUS="timecompleted"/>
</INDEXES>
</TABLE>
<TABLE NAME="enrol" COMMENT="Instances of enrolment plugins used in courses, fields marked as custom have a plugin defined meaning, core does not touch them. Create a new linked table if you need even more custom fields." PREVIOUS="course_completions" NEXT="user_enrolments">
</KEYS>
</TABLE>
</TABLES>
-</XMLDB>
\ No newline at end of file
+</XMLDB>
$logs = array(
array('module'=>'course', 'action'=>'user report', 'mtable'=>'user', 'field'=>$DB->sql_concat('firstname', "' '" , 'lastname')),
array('module'=>'course', 'action'=>'view', 'mtable'=>'course', 'field'=>'fullname'),
+ array('module'=>'course', 'action'=>'view section', 'mtable'=>'course_sections', 'field'=>'COALESCE(name, section)'),
array('module'=>'course', 'action'=>'update', 'mtable'=>'course', 'field'=>'fullname'),
array('module'=>'course', 'action'=>'enrol', 'mtable'=>'course', 'field'=>'fullname'), // there should be some way to store user id of the enrolled user!
array('module'=>'course', 'action'=>'unenrol', 'mtable'=>'course', 'field'=>'fullname'), // there should be some way to store user id of the enrolled user!
upgrade_main_savepoint(true, 2012052100.00);
}
+ if ($oldversion < 2012052500.03) { // fix invalid course_completion_records MDL-27368
+ //first get all instances of duplicate records
+ $sql = 'SELECT userid, course FROM {course_completions} WHERE (deleted IS NULL OR deleted <> 1) GROUP BY userid, course HAVING (count(id) > 1)';
+ $duplicates = $DB->get_recordset_sql($sql, array());
+
+ foreach ($duplicates as $duplicate) {
+ $pointer = 0;
+ //now get all the records for this user/course
+ $sql = 'userid = ? AND course = ? AND (deleted IS NULL OR deleted <> 1)';
+ $completions = $DB->get_records_select('course_completions', $sql,
+ array($duplicate->userid, $duplicate->course), 'timecompleted DESC, timestarted DESC');
+ $needsupdate = false;
+ $origcompletion = null;
+ foreach ($completions as $completion) {
+ $pointer++;
+ if ($pointer === 1) { //keep 1st record but delete all others.
+ $origcompletion = $completion;
+ } else {
+ //we need to keep the "oldest" of all these fields as the valid completion record.
+ $fieldstocheck = array('timecompleted', 'timestarted', 'timeenrolled');
+ foreach ($fieldstocheck as $f) {
+ if ($origcompletion->$f > $completion->$f) {
+ $origcompletion->$f = $completion->$f;
+ $needsupdate = true;
+ }
+ }
+ $DB->delete_records('course_completions', array('id'=>$completion->id));
+ }
+ }
+ if ($needsupdate) {
+ $DB->update_record('course_completions', $origcompletion);
+ }
+ }
+
+ // Main savepoint reached
+ upgrade_main_savepoint(true, 2012052500.03);
+ }
+
+ if ($oldversion < 2012052900.00) {
+ // Clean up all duplicate records in the course_completions table in preparation
+ // for adding a new index there.
+ upgrade_course_completion_remove_duplicates(
+ 'course_completions',
+ array('userid', 'course'),
+ array('timecompleted', 'timestarted', 'timeenrolled')
+ );
+
+ // Main savepoint reached
+ upgrade_main_savepoint(true, 2012052900.00);
+ }
+
+ if ($oldversion < 2012052900.01) {
+ // Add indexes to prevent new duplicates in the course_completions table.
+ // Define index useridcourse (unique) to be added to course_completions
+ $table = new xmldb_table('course_completions');
+ $index = new xmldb_index('useridcourse', XMLDB_INDEX_UNIQUE, array('userid', 'course'));
+
+ // Conditionally launch add index useridcourse
+ if (!$dbman->index_exists($table, $index)) {
+ $dbman->add_index($table, $index);
+ }
+
+ // Main savepoint reached
+ upgrade_main_savepoint(true, 2012052900.01);
+ }
+
+ if ($oldversion < 2012052900.02) {
+ // Clean up all duplicate records in the course_completion_crit_compl table in preparation
+ // for adding a new index there.
+ upgrade_course_completion_remove_duplicates(
+ 'course_completion_crit_compl',
+ array('userid', 'course', 'criteriaid'),
+ array('timecompleted')
+ );
+
+ // Main savepoint reached
+ upgrade_main_savepoint(true, 2012052900.02);
+ }
+
+ if ($oldversion < 2012052900.03) {
+ // Add indexes to prevent new duplicates in the course_completion_crit_compl table.
+ // Define index useridcoursecriteraid (unique) to be added to course_completion_crit_compl
+ $table = new xmldb_table('course_completion_crit_compl');
+ $index = new xmldb_index('useridcoursecriteraid', XMLDB_INDEX_UNIQUE, array('userid', 'course', 'criteriaid'));
+
+ // Conditionally launch add index useridcoursecriteraid
+ if (!$dbman->index_exists($table, $index)) {
+ $dbman->add_index($table, $index);
+ }
+
+ // Main savepoint reached
+ upgrade_main_savepoint(true, 2012052900.03);
+ }
+
+ if ($oldversion < 2012052900.04) {
+ // Clean up all duplicate records in the course_completion_aggr_methd table in preparation
+ // for adding a new index there.
+ upgrade_course_completion_remove_duplicates(
+ 'course_completion_aggr_methd',
+ array('course', 'criteriatype')
+ );
+
+ // Main savepoint reached
+ upgrade_main_savepoint(true, 2012052900.04);
+ }
+
+ if ($oldversion < 2012052900.05) {
+ // Add indexes to prevent new duplicates in the course_completion_aggr_methd table.
+ // Define index coursecriteratype (unique) to be added to course_completion_aggr_methd
+ $table = new xmldb_table('course_completion_aggr_methd');
+ $index = new xmldb_index('coursecriteriatype', XMLDB_INDEX_UNIQUE, array('course', 'criteriatype'));
+
+ // Conditionally launch add index coursecriteratype
+ if (!$dbman->index_exists($table, $index)) {
+ $dbman->add_index($table, $index);
+ }
+
+ // Main savepoint reached
+ upgrade_main_savepoint(true, 2012052900.05);
+ }
+
return true;
-}
+}
\ No newline at end of file
if ($this->is_directory()) {
$filepath = $this->lf->get_filepath();
$fs = get_file_storage();
- $storedfiles = $fs->get_area_files($this->context->id, $this->get_component(), $this->lf->get_filearea(), $this->lf->get_itemid(), "");
+ $storedfiles = $fs->get_area_files($this->context->id, $this->get_component(), $this->lf->get_filearea(), $this->lf->get_itemid());
foreach ($storedfiles as $file) {
if (strpos($file->get_filepath(), $filepath) === 0) {
$file->delete();
if (!empty($options['preview'])) {
// replace the file with its preview
$fs = get_file_storage();
- $stored_file = $fs->get_file_preview($stored_file, $options['preview']);
- if (!$stored_file) {
- // unable to create a preview of the file
- send_header_404();
- die();
+ $preview_file = $fs->get_file_preview($stored_file, $options['preview']);
+ if (!$preview_file) {
+ // unable to create a preview of the file, send its default mime icon instead
+ if ($options['preview'] === 'tinyicon') {
+ $size = 24;
+ } else if ($options['preview'] === 'thumb') {
+ $size = 90;
+ } else {
+ $size = 256;
+ }
+ $fileicon = file_file_icon($stored_file, $size);
+ send_file($CFG->dirroot.'/pix/'.$fileicon.'.png', basename($fileicon).'.png');
} else {
// preview images have fixed cache lifetime and they ignore forced download
// (they are generated by GD and therefore they are considered reasonably safe).
+ $stored_file = $preview_file;
$lifetime = DAYSECS;
$filter = 0;
$forcedownload = false;
}
// fix file name automatically
- if ($filename !== 'f1' and $filename !== 'f2') {
+ if ($filename !== 'f1' and $filename !== 'f2' and $filename !== 'f3') {
$filename = 'f1';
}
redirect($theme->pix_url('u/'.$filename, 'moodle')); // intentionally not cached
}
- if (!$file = $fs->get_file($context->id, 'user', 'icon', 0, '/', $filename.'/.png')) {
- if (!$file = $fs->get_file($context->id, 'user', 'icon', 0, '/', $filename.'/.jpg')) {
- // bad reference - try to prevent future retries as hard as possible!
- if ($user = $DB->get_record('user', array('id'=>$context->instanceid), 'id, picture')) {
- if ($user->picture == 1 or $user->picture > 10) {
- $DB->set_field('user', 'picture', 0, array('id'=>$user->id));
+ if (!$file = $fs->get_file($context->id, 'user', 'icon', 0, '/', $filename.'.png')) {
+ if (!$file = $fs->get_file($context->id, 'user', 'icon', 0, '/', $filename.'.jpg')) {
+ if ($filename === 'f3') {
+ // f3 512x512px was introduced in 2.3, there might be only the smaller version.
+ if (!$file = $fs->get_file($context->id, 'user', 'icon', 0, '/', 'f1.png')) {
+ $file = $fs->get_file($context->id, 'user', 'icon', 0, '/', 'f1.jpg');
}
}
- // no redirect here because it is not cached
- $theme = theme_config::load($themename);
- $imagefile = $theme->resolve_image_location('u/'.$filename, 'moodle');
- send_file($imagefile, basename($imagefile), 60*60*24*14);
}
}
+ if (!$file) {
+ // bad reference - try to prevent future retries as hard as possible!
+ if ($user = $DB->get_record('user', array('id'=>$context->instanceid), 'id, picture')) {
+ if ($user->picture > 0) {
+ $DB->set_field('user', 'picture', 0, array('id'=>$user->id));
+ }
+ }
+ // no redirect here because it is not cached
+ $theme = theme_config::load($themename);
+ $imagefile = $theme->resolve_image_location('u/'.$filename, 'moodle');
+ send_file($imagefile, basename($imagefile), 60*60*24*14);
+ }
send_stored_file($file, 60*60*24*365, 0, false, array('preview' => $preview)); // enable long caching, there are many images on each page
* Returns all files belonging to given repository
*
* @param int $repositoryid
- * @param string $sort
+ * @param string $sort A fragment of SQL to use for sorting
*/
public function get_external_files($repositoryid, $sort = 'sortorder, itemid, filepath, filename') {
global $DB;
FROM {files} f
LEFT JOIN {files_reference} r
ON f.referencefileid = r.id
- WHERE r.repositoryid = ?
- ORDER BY $sort";
+ WHERE r.repositoryid = ?";
+ if (!empty($sort)) {
+ $sql .= " ORDER BY {$sort}";
+ }
$result = array();
$filerecords = $DB->get_records_sql($sql, array($repositoryid));
* @param string $component component
* @param string $filearea file area
* @param int $itemid item ID or all files if not specified
- * @param string $sort sort fields
+ * @param string $sort A fragment of SQL to use for sorting
* @param bool $includedirs whether or not include directories
* @return array of stored_files indexed by pathanmehash
*/
- public function get_area_files($contextid, $component, $filearea, $itemid = false, $sort="sortorder, itemid, filepath, filename", $includedirs = true) {
+ public function get_area_files($contextid, $component, $filearea, $itemid = false, $sort = "sortorder, itemid, filepath, filename", $includedirs = true) {
global $DB;
$conditions = array('contextid'=>$contextid, 'component'=>$component, 'filearea'=>$filearea);
WHERE f.contextid = :contextid
AND f.component = :component
AND f.filearea = :filearea
- $itemidsql
- ORDER BY $sort";
+ $itemidsql";
+ if (!empty($sort)) {
+ $sql .= " ORDER BY {$sort}";
+ }
$result = array();
$filerecords = $DB->get_records_sql($sql, $conditions);
* @param int $filepath directory path
* @param bool $recursive include all subdirectories
* @param bool $includedirs include files and directories
- * @param string $sort sort fields
+ * @param string $sort A fragment of SQL to use for sorting
* @return array of stored_files indexed by pathanmehash
*/
public function get_directory_files($contextid, $component, $filearea, $itemid, $filepath, $recursive = false, $includedirs = true, $sort = "filepath, filename") {
return array();
}
+ $orderby = (!empty($sort)) ? " ORDER BY {$sort}" : '';
+
if ($recursive) {
$dirs = $includedirs ? "" : "AND filename <> '.'";
AND ".$DB->sql_substr("f.filepath", 1, $length)." = :filepath
AND f.id <> :dirid
$dirs
- ORDER BY $sort";
+ $orderby";
$params = array('contextid'=>$contextid, 'component'=>$component, 'filearea'=>$filearea, 'itemid'=>$itemid, 'filepath'=>$filepath, 'dirid'=>$directory->get_id());
$files = array();
AND f.itemid = :itemid AND f.filename = '.'
AND ".$DB->sql_substr("f.filepath", 1, $length)." = :filepath
AND f.id <> :dirid
- ORDER BY $sort";
+ $orderby";
$reqlevel = substr_count($filepath, '/') + 1;
$filerecords = $DB->get_records_sql($sql, $params);
foreach ($filerecords as $filerecord) {
ON f.referencefileid = r.id
WHERE f.contextid = :contextid AND f.component = :component AND f.filearea = :filearea AND f.itemid = :itemid
AND f.filepath = :filepath AND f.filename <> '.'
- ORDER BY $sort";
+ $orderby";
$filerecords = $DB->get_records_sql($sql, $params);
foreach ($filerecords as $filerecord) {
$newrecord->timecreated = $filerecord->timecreated;
$newrecord->timemodified = $filerecord->timemodified;
- $newrecord->mimetype = empty($filerecord->mimetype) ? $this->mimetype($pathname) : $filerecord->mimetype;
+ $newrecord->mimetype = empty($filerecord->mimetype) ? $this->mimetype($pathname, $filerecord->filename) : $filerecord->mimetype;
$newrecord->userid = empty($filerecord->userid) ? null : $filerecord->userid;
$newrecord->source = empty($filerecord->source) ? null : $filerecord->source;
$newrecord->author = empty($filerecord->author) ? null : $filerecord->author;
list($newrecord->contenthash, $newrecord->filesize, $newfile) = $this->add_string_to_pool($content);
$filepathname = $this->path_from_hash($newrecord->contenthash) . '/' . $newrecord->contenthash;
// get mimetype by magic bytes
- $newrecord->mimetype = empty($filerecord->mimetype) ? $this->mimetype($filepathname) : $filerecord->mimetype;
+ $newrecord->mimetype = empty($filerecord->mimetype) ? $this->mimetype($filepathname, $filerecord->filename) : $filerecord->mimetype;
$newrecord->pathnamehash = $this->get_pathname_hash($newrecord->contextid, $newrecord->component, $newrecord->filearea, $newrecord->itemid, $newrecord->filepath, $newrecord->filename);
$filerecord->timemodified = $now;
}
+ $transaction = $DB->start_delegated_transaction();
+
// Insert file reference record.
try {
$referencerecord = new stdClass;
$this->create_directory($filerecord->contextid, $filerecord->component, $filerecord->filearea, $filerecord->itemid, $filerecord->filepath, $filerecord->userid);
+ $transaction->allow_commit();
+
// Adding repositoryid and reference to file record to create stored_file instance
$filerecord->repositoryid = $repositoryid;
$filerecord->reference = $reference;
* If file has a known extension, we return the mimetype based on extension.
* Otherwise (when possible) we try to get the mimetype from file contents.
*
- * @param string $pathname
+ * @param string $pathname full path to the file
+ * @param string $filename correct file name with extension, if omitted will be taken from $path
* @return string
*/
- public static function mimetype($pathname) {
- $type = mimeinfo('type', $pathname);
+ public static function mimetype($pathname, $filename = null) {
+ if (empty($filename)) {
+ $filename = $pathname;
+ }
+ $type = mimeinfo('type', $filename);
if ($type === 'document/unknown' && class_exists('finfo') && file_exists($pathname)) {
$finfo = new finfo(FILEINFO_MIME_TYPE);
$type = mimeinfo_from_type('type', $finfo->file($pathname));
// Remove repository info.
$this->repository = null;
+ $transaction = $DB->start_delegated_transaction();
+
// Remove reference info from DB.
$DB->delete_records('files_reference', array('id'=>$this->file_record->referencefileid));
$filerecord->referencefileid = null;
$this->update($filerecord);
+ $transaction->allow_commit();
+
// unset object variable
unset($this->file_record->repositoryid);
unset($this->file_record->reference);
*/
public function delete() {
global $DB;
+
+ $transaction = $DB->start_delegated_transaction();
+
// If other files referring to this file, we need convert them
if ($files = $this->fs->get_references_by_storedfile($this)) {
foreach ($files as $file) {
// Now delete file records in DB
$DB->delete_records('files', array('id'=>$this->file_record->id));
$DB->delete_records('files_reference', array('id'=>$this->file_record->referencefileid));
+
+ $transaction->allow_commit();
+
// moves pool file to trash if content not needed any more
$this->fs->deleted_file_cleanup($this->file_record->contenthash);
return true; // BC only
this.maxfiles = options.maxfiles;
this.maxbytes = options.maxbytes;
this.itemid = options.itemid;
+ this.author = options.author;
this.container = this.Y.one('#'+options.containerid);
if (options.filemanager) {
formdata.append('sesskey', M.cfg.sesskey);
formdata.append('repo_id', this.repositoryid);
formdata.append('itemid', this.itemid);
+ if (this.author) {
+ formdata.append('author', this.author);
+ }
if (this.filemanager) { // Filepickers do not have folders
formdata.append('savepath', this.filemanager.currentpath);
}
filemanager: manager,
acceptedtypes: options.accepted_types,
clientid: options.client_id,
+ author: options.author,
maxfiles: options.maxfiles,
maxbytes: options.maxbytes,
itemid: options.itemid,
var dndoptions = {
clientid: options.client_id,
acceptedtypes: options.accepted_types,
+ author: options.author,
maxfiles: -1,
maxbytes: options.maxbytes,
itemid: options.itemid,
$image->height = $imageinfo[1];
$image->type = $imageinfo[2];
+ $t = null;
switch ($image->type) {
case IMAGETYPE_GIF:
if (function_exists('imagecreatefromgif')) {
debugging('GIF not supported on this server');
return false;
}
+ // Guess transparent colour from GIF.
+ $transparent = imagecolortransparent($im);
+ if ($transparent != -1) {
+ $t = imagecolorsforindex($im, $transparent);
+ }
break;
case IMAGETYPE_JPEG:
if (function_exists('imagecreatefromjpeg')) {
if (function_exists('imagecreatetruecolor') and $CFG->gdversion >= 2) {
$im1 = imagecreatetruecolor(100, 100);
$im2 = imagecreatetruecolor(35, 35);
- if ($image->type == IMAGETYPE_PNG and $imagefnc === 'imagepng') {
+ $im3 = imagecreatetruecolor(512, 512);
+ if ($image->type != IMAGETYPE_JPEG and $imagefnc === 'imagepng') {
+ if ($t) {
+ // Transparent GIF hacking...
+ $transparentcolour = imagecolorallocate($im1 , $t['red'] , $t['green'] , $t['blue']);
+ imagecolortransparent($im1 , $transparentcolour);
+ $transparentcolour = imagecolorallocate($im2 , $t['red'] , $t['green'] , $t['blue']);
+ imagecolortransparent($im2 , $transparentcolour);
+ $transparentcolour = imagecolorallocate($im3 , $t['red'] , $t['green'] , $t['blue']);
+ imagecolortransparent($im3 , $transparentcolour);
+ }
+
imagealphablending($im1, false);
$color = imagecolorallocatealpha($im1, 0, 0, 0, 127);
imagefill($im1, 0, 0, $color);
imagesavealpha($im1, true);
+
imagealphablending($im2, false);
$color = imagecolorallocatealpha($im2, 0, 0, 0, 127);
imagefill($im2, 0, 0, $color);
imagesavealpha($im2, true);
+
+ imagealphablending($im3, false);
+ $color = imagecolorallocatealpha($im3, 0, 0, 0, 127);
+ imagefill($im3, 0, 0, $color);
+ imagesavealpha($im3, true);
}
} else {
$im1 = imagecreate(100, 100);
$im2 = imagecreate(35, 35);
+ $im3 = imagecreate(512, 512);
}
$cx = $image->width / 2;
imagecopybicubic($im1, $im, 0, 0, $cx - $half, $cy - $half, 100, 100, $half * 2, $half * 2);
imagecopybicubic($im2, $im, 0, 0, $cx - $half, $cy - $half, 35, 35, $half * 2, $half * 2);
+ imagecopybicubic($im3, $im, 0, 0, $cx - $half, $cy - $half, 512, 512, $half * 2, $half * 2);
$fs = get_file_storage();
$icon['filename'] = 'f2'.$imageext;
$fs->create_file_from_string($icon, $data);
+ ob_start();
+ if (!$imagefnc($im3, NULL, $quality, $filters)) {
+ ob_end_clean();
+ $fs->delete_area_files($context->id, $component, $filearea, $itemid);
+ return false;
+ }
+ $data = ob_get_clean();
+ imagedestroy($im3);
+ $icon['filename'] = 'f3'.$imageext;
+ $fs->create_file_from_string($icon, $data);
+
return $file1->get_id();
}
set_config('release', $release);
set_config('branch', $branch);
+ if (PHPUNIT_TEST) {
+ // mark as test database as soon as possible
+ set_config('phpunittest', 'na');
+ }
+
// install all plugins types, local, etc.
upgrade_noncore(true);
* @param string $formula
* @return string localised formula
*/
- function localize($formula) {
+ public static function localize($formula) {
$formula = str_replace('.', '$', $formula); // temp placeholder
$formula = str_replace(',', get_string('listsep', 'langconfig'), $formula);
$formula = str_replace('$', get_string('decsep', 'langconfig'), $formula);
* @param string $formula localised formula
* @return string
*/
- function unlocalize($formula) {
+ public static function unlocalize($formula) {
$formula = str_replace(get_string('decsep', 'langconfig'), '$', $formula);
$formula = str_replace(get_string('listsep', 'langconfig'), ',', $formula);
$formula = str_replace('$', '.', $formula); // temp placeholder
*/
function mtrace($string, $eol="\n", $sleep=0) {
- if (defined('STDOUT')) {
+ if (defined('STDOUT') and !PHPUNIT_TEST) {
fwrite(STDOUT, $string.$eol);
} else {
echo $string . $eol;
} else if ($this->size === true or $this->size == 1) {
$filename = 'f1';
$size = 100;
+ } else if ($this->size > 100) {
+ $filename = 'f3';
+ $size = (int)$this->size;
} else if ($this->size >= 50) {
$filename = 'f1';
$size = (int)$this->size;
*/
public function get_tempfiles($skipfile='portfolio-export.zip') {
$fs = get_file_storage();
- $files = $fs->get_area_files(SYSCONTEXTID, 'portfolio', 'exporter', $this->id, '', false);
+ $files = $fs->get_area_files(SYSCONTEXTID, 'portfolio', 'exporter', $this->id, 'sortorder, itemid, filepath, filename', false);
if (empty($files)) {
return array();
}
if (PHPUNIT_TEST and !PHPUNIT_UTIL) {
// make sure tests do not run in parallel
phpunit_util::acquire_test_lock();
- // reset DB tables
- phpunit_util::reset_database();
+ $dbhash = null;
+ try {
+ if ($dbhash = $DB->get_field('config', 'value', array('name'=>'phpunittest'))) {
+ // reset DB tables
+ phpunit_util::reset_database();
+ }
+ } catch (Exception $e) {
+ if ($dbhash) {
+ // we ned to reinit if reset fails
+ $DB->set_field('config', 'value', 'na', array('name'=>'phpunittest'));
+ } else {
+ throw $e;
+ }
+ }
+ unset($dbhash);
}
// Disable errors for now - needed for installation when debug enabled in config.php
$this->assertEquals(
(object)array('id'=>$id,'showavailability'=>1,
'availablefrom'=>17,'availableuntil'=>398,'course'=>64,
- 'conditionsgrade'=>array(), 'conditionscompletion'=>array()),
+ 'conditionsgrade'=>array(), 'conditionscompletion'=>array(),
+ 'visible' => 1),
$test->get_full_course_module());
// just the course_modules stuff; check it doesn't request that from db
$cm->availablefrom=2;
$cm->availableuntil=74;
$cm->course=38;
+ $cm->visible = 1;
$test=new condition_info($cm,CONDITION_MISSING_EXTRATABLE);
$this->assertEquals(
(object)array('id'=>$id,'showavailability'=>0,
'availablefrom'=>2,'availableuntil'=>74,'course'=>38,
- 'conditionsgrade'=>array(), 'conditionscompletion'=>array()),
+ 'conditionsgrade' => array(), 'conditionscompletion' => array(),
+ 'visible' => 1),
$test->get_full_course_module());
// Now let's add some actual grade/completion conditions
$this->assertEquals(
(object)array('id' => $id, 'showavailability' => 1, 'groupingid' => 13,
'availablefrom' => 17, 'availableuntil' => 398, 'course' => 64,
- 'conditionsgrade' => array(), 'conditionscompletion' => array()),
+ 'conditionsgrade' => array(), 'conditionscompletion' => array(),
+ 'visible' => 1),
$test->get_full_section());
// Just the course_sections stuff; check it doesn't request that from db
$section->availableuntil = 74;
$section->course = 38;
$section->groupingid = 99;
+ $section->visible = 1;
$test = new condition_info_section($section, CONDITION_MISSING_EXTRATABLE);
$this->assertEquals(
(object)array('id' => $id, 'showavailability' => 0, 'groupingid' => 99,
'availablefrom' => 2, 'availableuntil' => 74, 'course' => 38,
- 'conditionsgrade' => array(), 'conditionscompletion' => array()),
+ 'conditionsgrade' => array(), 'conditionscompletion' => array(),
+ 'visible' => 1),
$test->get_full_section());
// Now let's add some actual grade/completion conditions
}
return $profile;
}
+
+
+/**
+ * This function finds duplicate records (based on combinations of fields that should be unique)
+ * and then progamatically generated a "most correct" version of the data, update and removing
+ * records as appropriate
+ *
+ * Thanks to Dan Marsden for help
+ *
+ * @param string $table Table name
+ * @param array $uniques Array of field names that should be unique
+ * @param array $fieldstocheck Array of fields to generate "correct" data from (optional)
+ * @return void
+ */
+function upgrade_course_completion_remove_duplicates($table, $uniques, $fieldstocheck = array()) {
+ global $DB;
+
+ // Find duplicates
+ $sql_cols = implode(', ', $uniques);
+
+ $sql = "SELECT {$sql_cols} FROM {{$table}} GROUP BY {$sql_cols} HAVING (count(id) > 1)";
+ $duplicates = $DB->get_recordset_sql($sql, array());
+
+ // Loop through duplicates
+ foreach ($duplicates as $duplicate) {
+ $pointer = 0;
+
+ // Generate SQL for finding records with these duplicate uniques
+ $sql_select = implode(' = ? AND ', $uniques).' = ?'; // builds "fieldname = ? AND fieldname = ?"
+ $uniq_values = array();
+ foreach ($uniques as $u) {
+ $uniq_values[] = $duplicate->$u;
+ }
+
+ $sql_order = implode(' DESC, ', $uniques).' DESC'; // builds "fieldname DESC, fieldname DESC"
+
+ // Get records with these duplicate uniques
+ $records = $DB->get_records_select(
+ $table,
+ $sql_select,
+ $uniq_values,
+ $sql_order
+ );
+
+ // Loop through and build a "correct" record, deleting the others
+ $needsupdate = false;
+ $origrecord = null;
+ foreach ($records as $record) {
+ $pointer++;
+ if ($pointer === 1) { // keep 1st record but delete all others.
+ $origrecord = $record;
+ } else {
+ // If we have fields to check, update original record
+ if ($fieldstocheck) {
+ // we need to keep the "oldest" of all these fields as the valid completion record.
+ // but we want to ignore null values
+ foreach ($fieldstocheck as $f) {
+ if ($record->$f && (($origrecord->$f > $record->$f) || !$origrecord->$f)) {
+ $origrecord->$f = $record->$f;
+ $needsupdate = true;
+ }
+ }
+ }
+ $DB->delete_records($table, array('id' => $record->id));
+ }
+ }
+ if ($needsupdate || isset($origrecord->reaggregate)) {
+ // If this table has a reaggregate field, update to force recheck on next cron run
+ if (isset($origrecord->reaggregate)) {
+ $origrecord->reaggregate = time();
+ }
+ $DB->update_record($table, $origrecord);
+ }
+ }
+}
this.dragsourceregion = null;
},
+ drag_dropmiss : function(e) {
+ // Missed the target, but we assume the user intended to drop it
+ // on the last last ghost node location, e.drag and e.drop should be
+ // prepared by global_drag_dropmiss parent so simulate drop_hit(e).
+ this.drop_hit(e);
+ },
+
drop_hit : function(e) {
var drag = e.drag;
// Get a reference to our drag node
samenodeclass : null,
parentnodeclass : null,
groups : [],
+ lastdroptarget : null,
initializer : function(params) {
// Listen for all drag:start events
Y.DD.DDM.on('drag:start', this.global_drag_start, this);
Y.DD.DDM.on('drop:over', this.global_drop_over, this);
// Listen for all drop:hit events
Y.DD.DDM.on('drop:hit', this.global_drop_hit, this);
+ // Listen for all drop:miss events
+ Y.DD.DDM.on('drag:dropmiss', this.global_drag_dropmiss, this);
},
get_drag_handle: function(title, classname, iconclass) {
.setAttrs({
'src' : M.util.image_url(MOVEICON.pix, MOVEICON.component),
'alt' : title,
- 'title' : M.str.moodle.move,
- 'hspace' : '3'
+ 'title' : M.str.moodle.move
});
if (iconclass) {
dragicon.addClass(iconclass);
return new M.core.exception(e);
},
+ in_group: function(target) {
+ var ret = false;
+ Y.each(this.groups, function(v, k) {
+ if (target._groups[v]) {
+ ret = true;
+ }
+ }, this);
+ return ret;
+ },
/*
* Drag-dropping related functions
*/
global_drag_start : function(e) {
// Get our drag object
var drag = e.target;
- // Check that drop object belong to correct group
- if (!drag.target.inGroup(this.groups)) {
+ // Check that drag object belongs to correct group
+ if (!this.in_group(drag)) {
return;
}
// Set some general styles here
global_drag_end : function(e) {
var drag = e.target;
- // Check that drop object belong to correct group
- if (!drag.target.inGroup(this.groups)) {
+ // Check that drag object belongs to correct group
+ if (!this.in_group(drag)) {
return;
}
//Put our general styles back
global_drag_drag : function(e) {
var drag = e.target;
- // Check that drop object belong to correct group
- if (!drag.target.inGroup(this.groups)) {
+ // Check that drag object belongs to correct group
+ if (!this.in_group(drag)) {
return;
}
//Get the last y point
//Get a reference to our drag and drop nodes
var drag = e.drag.get('node');
var drop = e.drop.get('node');
+ // Save last drop target for the case of missed target processing
+ this.lastdroptarget = e.drop;
//Are we dropping on the same node?
if (drop.hasClass(this.samenodeclass)) {
//Are we not going up?
this.drop_over(e);
},
+ global_drag_dropmiss : function(e) {
+ // drag:dropmiss does not have e.drag and e.drop properties
+ // we substitute them for the ease of use. For e.drop we use,
+ // this.lastdroptarget (ghost node we use for indicating where to drop)
+ e.drag = e.target;
+ // Check that drop object belong to correct group
+ if (!e.drag.target.inGroup(this.groups)) {
+ return;
+ }
+ e.drop = this.lastdroptarget;
+ this.drag_dropmiss(e);
+ },
+
global_drop_hit : function(e) {
// Check that drop object belong to correct group
if (!e.drop.inGroup(this.groups)) {
drag_start : function(e) {},
drag_end : function(e) {},
drag_drag : function(e) {},
+ drag_dropmiss : function(e) {},
drop_over : function(e) {},
drop_hit : function(e) {}
}, {
$string['pluginadministration'] = 'Book administration';
$string['toc'] = 'Table of contents';
-$string['faq'] = 'Book FAQ';
-$string['faq_help'] = '
-*Why only two levels?*
-
-Two levels are generally enough for all books, three levels would lead to poorly structured documents. Book module is designed for
-creation of short multipage study materials. It is usually better to use PDF format for longer documents. The easiest way to create PDFs are
-virtual printers (see
-<a href="http://sector7g.wurzel6.de/pdfcreator/index_en.htm" target="_blank">PDFCreator</a>,
-<a href="http://fineprint.com/products/pdffactory/index.html" target="_blank">PDFFactory</a>,
-<a href="http://www.adobe.com/products/acrobatstd/main.html" target="_blank">Adobe Acrobat</a>,
-etc.).
-
-*Can students edit books?*
-
-Only teachers can create and edit books. There are no plans to implement student editing for books, but somebody may create something
-similar for students (Portfolio?). The main reason is to keep Book module as simple as possible.
-
-*How do I search the books?*
-
-At present there is only one way, use browser\'s search capability in print page. Global searching is now possible only in Moodle forums.
-It would be nice to have global searching for all resources including books, any volunteers?
-
-*My titles do not fit on one line.*
-
-Either rephrase your titles or ask your site admin to change TOC
-width. It is defined globally for all books in module configuration
-page.';
-
$string['customtitles'] = 'Custom titles';
-$string['customtitles_help'] = 'Chapter titles are displayed automatically only in TOC.';
+$string['customtitles_help'] = 'Normally the chapter title is displayed in the table of contents (TOC) AND as a heading above the content.
+If the custom titles checkbox is ticked, the chapter title is NOT displayed as a heading above the content. A different title (perhaps longer than the chapter title) may be entered as part of the content.';
$string['chapters'] = 'Chapters';
$string['editingchapter'] = 'Editing chapter';
$string['chaptertitle'] = 'Chapter title';
$string['content'] = 'Content';
$string['subchapter'] = 'Subchapter';
-
-$string['numbering'] = 'Chapter numbering';
-$string['numbering_help'] = '* None - chapter and subchapter titles are not formatted at all, use if you want to define special numbering styles. For example letters: in chapter title type "A First Chapter", "A.1 Some Subchapter",...
-* Numbers - chapters and subchapters are numbered (1, 1.1, 1.2, 2, ...)
-* Bullets - subchapters are indented and displayed with bullets
-* Indented - subchapters are indented';
-
+$string['numbering'] = 'Chapter formatting';
+$string['numbering_help'] = '* None - Chapter and subchapter titles have no formatting
+* Numbers - Chapters and subchapter titles are numbered 1, 1.1, 1.2, 2, ...
+* Bullets - Subchapters are indented and displayed with bullets in the table of contents
+* Indented - Subchapters are indented in the table of contents';
$string['numbering0'] = 'None';
$string['numbering1'] = 'Numbers';
$string['numbering2'] = 'Bullets';
$string['numbering3'] = 'Indented';
-$string['numberingoptions'] = 'Available numbering options';
-$string['numberingoptions_help'] = 'Select numbering options that should be available when creating new books.';
-
+$string['numberingoptions'] = 'Available options for chapter formatting';
+$string['numberingoptions_desc'] = 'Options for displaying chapters and subchapters in the table of contents';
$string['chapterscount'] = 'Chapters';
-
$string['addafter'] = 'Add new chapter';
$string['confchapterdelete'] = 'Do you really want to delete this chapter?';
$string['confchapterdeleteall'] = 'Do you really want to delete this chapter and all its subchapters?';
-
$string['top'] = 'top';
-
$string['navprev'] = 'Previous';
$string['navnext'] = 'Next';
$string['navexit'] = 'Exit book';
-
$string['book:addinstance'] = 'Add a new book';
$string['book:read'] = 'Read book';
$string['book:edit'] = 'Edit book chapters';
$string['book:viewhiddenchapters'] = 'View hidden book chapters';
-
-$string['errorchapter'] = 'Error reading book chapter.';
+$string['errorchapter'] = 'Error reading chapter of book.';
$string['page-mod-book-x'] = 'Any book module page';
$toc = book_get_toc($chapters, $chapter, $book, $cm, $edit, 0);
- if ($edit) {
- $toc .= '<div class="book_faq">';
- $toc .= $OUTPUT->help_icon('faq', 'mod_book', get_string('faq', 'mod_book'));
- $toc .= '</div>';
- }
-
$bc = new block_contents();
$bc->title = get_string('toc', 'mod_book');
$bc->attributes['class'] = 'block';
$options = book_get_numbering_types();
$settings->add(new admin_setting_configmultiselect('book/numberingoptions',
- get_string('numberingoptions', 'mod_book'), get_string('numberingoptions_help', 'mod_book'),
+ get_string('numberingoptions', 'mod_book'), get_string('numberingoptions_desc', 'mod_book'),
array_keys($options), $options));
$settings->add(new admin_setting_configselect('book/numbering',
get_string('numbering', 'mod_book'), '', BOOK_NUM_NUMBERS, $options));
-}
\ No newline at end of file
+}
/* == Fake toc block == */
-.mod_book .book_faq {
- font-size: 0.7em;
-}
-
/* toc style NONE */
.mod_book .book_toc_none {
font-size: 0.8em;
$string['exportimscp:export'] = 'Export book as IMS content package';
$string['generateimscp'] = 'Generate IMS CP';
-$string['nochapters'] = 'No book chapters found, can not export to IMS CP.';
+$string['nochapters'] = 'No book chapters found, so unable to export to IMS CP.';
$string['pluginname'] = 'Book IMS CP export';
defined('MOODLE_INTERNAL') || die;
$string['doimport'] = 'Import';
-$string['errornochapters'] = 'Can not find chapters in selected file';
-$string['import'] = 'Import from HTML';
+$string['errornochapters'] = 'Cannot find chapters in selected file';
+$string['import'] = 'Import chapter';
$string['importhtml:import'] = 'Import chapters';
$string['importing'] = 'Importing';
$string['importingchapters'] = 'Importing chapters into book';
-$string['pluginname'] = 'Book HTML import';
+$string['pluginname'] = 'Book chapter import';
$string['relinking'] = 'Relinking';
$string['type'] = 'Type';
$string['typeonefile'] = 'One HTML file with headings as chapters';
$string['typezipfiles'] = 'Each HTML file represents one chapter';
-$string['typezipdirs'] = 'Each directory represents one chapter';
-$string['ziparchive'] = 'Zip archive';
-$string['ziparchive_help'] = 'Select a ZIP archive that contains HTML files and other media. File or directory names ending with "_sub" indicate subchapters. You can use copy and paste in text editor for simple HML files without embedded media.';
\ No newline at end of file
+$string['typezipdirs'] = 'Each folder represents one chapter';
+$string['ziparchive'] = 'Zip file';
+$string['ziparchive_help'] = 'Select a zip file containing HTML files and optional multimedia files and folders. To upload subchapters, add "_sub" to the end of HTML file or folder names.';
defined('MOODLE_INTERNAL') || die;
$module->component = 'mod_book'; // Full name of the plugin (used for diagnostics)
-$module->version = 2012052100; // The current module version (Date: YYYYMMDDXX)
+$module->version = 2012052700; // The current module version (Date: YYYYMMDDXX)
$module->requires = 2012051900; // Requires this Moodle version
$module->cron = 0; // Period for cron to check this module (secs)
//get the value
$frmvaluename = $feedbackitem->typ . '_'. $feedbackitem->id;
if (isset($savereturn)) {
- if (isset($formdata->{$frmvaluename})) {
- $value = $formdata->{$frmvaluename};
- } else {
- $value = null;
- }
+ $value = isset($formdata->{$frmvaluename}) ? $formdata->{$frmvaluename} : null;
+ $value = feedback_clean_input_value($feedbackitem, $value);
} else {
if (isset($feedbackcompletedtmp->id)) {
$value = feedback_get_item_value($feedbackcompletedtmp->id,
feedback_print_item_complete($feedbackitem, $value, $highlightrequired);
echo $OUTPUT->box_end();
}
+
echo $OUTPUT->box_end();
$lastbreakposition = $feedbackitem->position; //last item-pos (item or pagebreak)
!isset($formdata->gonextpage) AND
!isset($formdata->gopreviouspage)) {
- $gopage = $formdata->lastpage;
+ $gopage = (int) $formdata->lastpage;
}
if (isset($formdata->savevalues)) {
$savevalues = true;
echo $OUTPUT->box_start('feedback_item_box_'.$align.$dependstyle);
$value = '';
//get the value
- $frmvaluename = $feedbackitem->typ.'_'.$feedbackitem->id;
+ $frmvaluename = $feedbackitem->typ . '_'. $feedbackitem->id;
if (isset($savereturn)) {
- if (isset($formdata->{$frmvaluename})) {
- $value = $formdata->{$frmvaluename};
- } else {
- $value = null;
- }
+ $value = isset($formdata->{$frmvaluename}) ? $formdata->{$frmvaluename} : null;
+ $value = feedback_clean_input_value($feedbackitem, $value);
} else {
if (isset($feedbackcompletedtmp->id)) {
$value = feedback_get_item_value($feedbackcompletedtmp->id,
feedback_print_item_complete($feedbackitem, $value, $highlightrequired);
echo $OUTPUT->box_end();
}
+
echo $OUTPUT->box_end();
$lastbreakposition = $feedbackitem->position; //last item-pos (item or pagebreak)
public function can_switch_require() {
return false;
}
+
+ /**
+ * Cleans the value coming from the user for a field of this type.
+ * @param mixed $value
+ * @return mixed
+ */
+ public function clean_input_value($value) {
+ return clean_param($value, PARAM_RAW);
+ }
}
*/
abstract public function print_item_show_value($item, $value = '');
+ /**
+ * cleans the userinput while submitting the form
+ *
+ * @param mixed $value
+ * @return mixed
+ */
+ abstract public function clean_input_value($value);
+
}
//a dummy class to realize pagebreaks
}
public function can_switch_require() {
}
+ public function clean_input_value($value) {
+ }
-}
-
-
+}
\ No newline at end of file
public function can_switch_require() {
return false;
}
+
+ /**
+ * Cleans the value coming from the user for a field of this type.
+ * @param mixed $value
+ * @return mixed
+ */
+ public function clean_input_value($value) {
+ return clean_param($value, PARAM_INT);
+ }
}
}
public function get_analysed($item, $groupid = false, $courseid = false) {
}
+ /**
+ * Cleans the value coming from the user for a field of this type.
+ * @param mixed $value
+ * @return mixed
+ */
+ public function clean_input_value($value) {
+ return '';
+ }
}
public function value_is_array() {
return true;
}
+
+ /**
+ * Cleans the value coming from the user for a field of this type.
+ * @param mixed $value
+ * @return mixed
+ */
+ public function clean_input_value($value) {
+ return clean_param_array($value, PARAM_INT);
+ }
}
return true;
}
+ /**
+ * Cleans the value coming from the user for a field of this type.
+ * @param mixed $value
+ * @return mixed
+ */
+ public function clean_input_value($value) {
+ return clean_param($value, PARAM_INT);
+ }
}
public function can_switch_require() {
return true;
}
+
+ /**
+ * Cleans the value coming from the user for a field of this type.
+ * @param mixed $value
+ * @return mixed
+ */
+ public function clean_input_value($value) {
+ return clean_param($value, PARAM_FLOAT);
+ }
}
public function can_switch_require() {
return true;
}
+
+ /**
+ * Cleans the value coming from the user for a field of this type.
+ * @param mixed $value
+ * @return mixed
+ */
+ public function clean_input_value($value) {
+ return clean_param($value, PARAM_CLEANHTML);
+ }
}
public function can_switch_require() {
return true;
}
+
+ /**
+ * Cleans the value coming from the user for a field of this type.
+ * @param mixed $value
+ * @return mixed
+ */
+ public function clean_input_value($value) {
+ return clean_param($value, PARAM_CLEANHTML);
+ }
}
//functions to handle the values
////////////////////////////////////////////////
+/**
+ * cleans the userinput while submitting the form.
+ *
+ * @param stdClass $item The feedback item record from the database that the value needs to be cleaned against.
+ * @param mixed $value
+ * @return mixed
+ */
+function feedback_clean_input_value($item, $value) {
+ $itemobj = feedback_get_item_class($item->typ);
+ return $itemobj->clean_input_value($value);
+}
+
/**
* this saves the values of an completed.
* if the param $tmp is set true so the values are saved temporary in table feedback_valuetmp.
$data = new stdClass();
$data->id = $cm->id;
-$options = array('mainfile'=>true, 'subdirs'=>1, 'maxbytes'=>$CFG->maxbytes, 'maxfiles'=>-1, 'accepted_types'=>'*');
+$options = array('subdirs'=>1, 'maxbytes'=>$CFG->maxbytes, 'maxfiles'=>-1, 'accepted_types'=>'*');
file_prepare_standard_filemanager($data, 'files', $options, $context, 'mod_folder', 'content', 0);
$mform = new mod_folder_edit_form(null, array('data'=>$data, 'options'=>$options));
* @return string the full path to the cached RSS feed directory. Null if there is a problem.
*/
function forum_rss_get_feed($context, $args) {
- global $CFG, $DB;
+ global $CFG, $DB, $USER;
$status = true;
$forumid = clean_param($args[3], PARAM_INT);
$cm = get_coursemodule_from_instance('forum', $forumid, 0, false, MUST_EXIST);
- $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
+ $modcontext = context_module::instance($cm->id);
//context id from db should match the submitted one
if ($context->id != $modcontext->id || !has_capability('mod/forum:viewdiscussion', $modcontext)) {
//the sql that will retreive the data for the feed and be hashed to get the cache filename
$sql = forum_rss_get_sql($forum, $cm);
- //hash the sql to get the cache file name
- $filename = rss_get_file_name($forum, $sql);
+ // Hash the sql to get the cache file name.
+ // If the forum is Q and A then we need to cache the files per user. This can
+ // have a large impact on performance, so we want to only do it on this type of forum.
+ if ($forum->type == 'qanda') {
+ $filename = rss_get_file_name($forum, $sql . $USER->id);
+ } else {
+ $filename = rss_get_file_name($forum, $sql);
+ }
$cachedfilepath = rss_get_file_full_name('mod_forum', $filename);
//Is the cache out of date?
$now = round(time(), -2);
$params = array($cm->instance);
- $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
+ $modcontext = context_module::instance($cm->id);
if (!empty($CFG->forum_enabletimedposts)) { /// Users must fulfill timed posts
if (!has_capability('mod/forum:viewhiddentimedposts', $modcontext)) {
* @return string the SQL query to be used to get the Post details from the forum table of the database
*/
function forum_rss_feed_posts_sql($forum, $cm, $newsince=0) {
- $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
+ $modcontext = context_module::instance($cm->id);
//get group enforcement SQL
$groupmode = groups_get_activity_groupmode($cm);
*
* @Todo MDL-31129 implement post attachment handling
*/
-function forum_rss_feed_contents($forum, $sql, $context) {
- global $CFG, $DB;
+
+function forum_rss_feed_contents($forum, $sql) {
+ global $CFG, $DB, $USER;
+
$status = true;
$isdiscussion = false;
}
+ if (!$cm = get_coursemodule_from_instance('forum', $forum->id, $forum->course)) {
+ print_error('invalidcoursemodule');
+ }
+ $context = context_module::instance($cm->id);
+
$formatoptions = new stdClass();
$items = array();
foreach ($recs as $rec) {
$item = new stdClass();
$user = new stdClass();
- if ($isdiscussion && !empty($rec->discussionname)) {
- $item->title = format_string($rec->discussionname);
- } else if (!empty($rec->postsubject)) {
- $item->title = format_string($rec->postsubject);
+
+ if ($isdiscussion && !forum_user_can_see_discussion($forum, $rec->discussionid, $context)) {
+ // This is a discussion which the user has no permission to view
+ $item->title = get_string('forumsubjecthidden', 'forum');
+ $message = get_string('forumbodyhidden', 'forum');
+ $item->author = get_string('forumauthorhidden', 'forum');
+ } else if (!$isdiscussion && !forum_user_can_see_post($forum, $rec->discussionid, $rec->postid, $USER, $cm)) {
+ // This is a post which the user has no permission to view
+ $item->title = get_string('forumsubjecthidden', 'forum');
+ $message = get_string('forumbodyhidden', 'forum');
+ $item->author = get_string('forumauthorhidden', 'forum');
} else {
- //we should have an item title by now but if we dont somehow then substitute something somewhat meaningful
- $item->title = format_string($forum->name.' '.userdate($rec->postcreated,get_string('strftimedatetimeshort', 'langconfig')));
+ // The user must have permission to view
+ if ($isdiscussion && !empty($rec->discussionname)) {
+ $item->title = format_string($rec->discussionname);
+ } else if (!empty($rec->postsubject)) {
+ $item->title = format_string($rec->postsubject);
+ } else {
+ //we should have an item title by now but if we dont somehow then substitute something somewhat meaningful
+ $item->title = format_string($forum->name.' '.userdate($rec->postcreated,get_string('strftimedatetimeshort', 'langconfig')));
+ }
+ $user->firstname = $rec->userfirstname;
+ $user->lastname = $rec->userlastname;
+ $item->author = fullname($user);
+ $message = file_rewrite_pluginfile_urls($rec->postmessage, 'pluginfile.php', $context->id,
+ 'mod_forum', 'post', $rec->postid);
+ $formatoptions->trusted = $rec->posttrust;
}
- $user->firstname = $rec->userfirstname;
- $user->lastname = $rec->userlastname;
- $item->author = fullname($user);
- $item->pubdate = $rec->postcreated;
+
if ($isdiscussion) {
$item->link = $CFG->wwwroot."/mod/forum/discuss.php?d=".$rec->discussionid;
} else {
}
$formatoptions->trusted = $rec->posttrust;
- $message = file_rewrite_pluginfile_urls($rec->postmessage, 'pluginfile.php', $context->id,
- 'mod_forum', 'post', $rec->postid);
$item->description = format_text($message, $rec->postformat, $formatoptions, $forum->course);
//TODO: MDL-31129 implement post attachment handling
$item->attachments = array();
}
}*/
+ $item->pubdate = $rec->postcreated;
$items[] = $item;
}
if (!has_capability('mod/forum:managesubscriptions', $context)) {
print_error('nopermissiontosubscribe', 'forum');
}
- $user = $DB->get_record('user', array('id' => $user), MUST_EXIST);
+ $user = $DB->get_record('user', array('id' => $user), '*', MUST_EXIST);
} else {
$user = $USER;
}
$fs = get_file_storage();
- $files = $fs->get_area_files($context->id, 'mod_scorm', 'content', 0, '', false);
+ $files = $fs->get_area_files($context->id, 'mod_scorm', 'content', 0, 'sortorder, itemid, filepath, filename', false);
$version = 'AICC';
$ids = array();
return $errors;
}
+ if (empty($data['format'])) {
+ $errors['format'] = get_string('required');
+ return $errors;
+ }
+
$formatfile = 'format/' . $data['format'] . '/format.php';
if (!is_readable($formatfile)) {
throw new moodle_exception('formatnotfound', 'question', '', $data['format']);
// Moodle v2.2.0 release upgrade line
// Put any upgrade step following this
+ if ($oldversion < 2011102701) {
+ // In Moodle <= 2.0 essay had both question.generalfeedback and question_answers.feedback.
+ // This was silly, and in Moodel >= 2.1 only question.generalfeedback. To avoid
+ // dataloss, we concatenate question_answers.feedback onto the end of question.generalfeedback.
+ $toupdate = $DB->get_recordset_sql("
+ SELECT q.id,
+ q.generalfeedback,
+ q.generalfeedbackformat,
+ qa.feedback,
+ qa.feedbackformat
+
+ FROM {question} q
+ JOIN {question_answers} qa ON qa.question = q.id
+
+ WHERE q.qtype = 'essay'
+ AND " . $DB->sql_isnotempty('question_answers', 'feedback', false, true));
+
+ foreach ($toupdate as $data) {
+ upgrade_set_timeout(60);
+ if ($data->generalfeedbackformat == $data->feedbackformat) {
+ $DB->set_field('question', 'generalfeedback',
+ $data->generalfeedback . $data->feedback,
+ array('id' => $data->id));
+
+ } else {
+ $newdata = new stdClass();
+ $newdata->id = $data->id;
+ $newdata->generalfeedback =
+ qtype_essay_convert_to_html($data->generalfeedback, $data->generalfeedbackformat) .
+ qtype_essay_convert_to_html($data->feedback, $data->feedbackformat);
+ $newdata->generalfeedbackformat = FORMAT_HTML;
+ $DB->update_record('question', $newdata);
+ }
+ }
+
+ $toupdate->close();
+
+ // Essay savepoint reached.
+ upgrade_plugin_savepoint(true, 2011102701, 'qtype', 'essay');
+ }
+
+ if ($oldversion < 2011102702) {
+ // Then we delete the old question_answers rows for essay questions.
+ $DB->delete_records_select('question_answers',
+ "question IN (SELECT id FROM {question} WHERE qtype = 'essay')");
+
+ // Essay savepoint reached.
+ upgrade_plugin_savepoint(true, 2011102702, 'qtype', 'essay');
+ }
+
return true;
}
+
+/**
+ * Convert some content to HTML.
+ * @param string $text the content to convert to HTML
+ * @param int $oldformat One of the FORMAT_... constants.
+ */
+function qtype_essay_convert_to_html($text, $oldformat) {
+ switch ($oldformat) {
+ // Similar to format_text.
+
+ case FORMAT_PLAIN:
+ $text = s($text);
+ $text = str_replace(' ', ' ', $text);
+ $text = nl2br($text);
+ return $text;
+
+ case FORMAT_MARKDOWN:
+ return markdown_to_html($text);
+
+ case FORMAT_MOODLE:
+ return text_to_html($text);
+
+ case FORMAT_HTML:
+ return $text;
+
+ default:
+ throw new coding_exception(
+ 'Unexpected text format when upgrading essay questions.');
+ }
+}
$pickeroptions->itemid = $qa->prepare_response_files_draft_itemid(
'attachments', $options->context->id);
- return form_filemanager_render($pickeroptions) . html_writer::empty_tag(
+ $fm = new form_filemanager($pickeroptions);
+ $filesrenderer = $this->page->get_renderer('core', 'files');
+ return $filesrenderer->render($fm). html_writer::empty_tag(
'input', array('type' => 'hidden', 'name' => $qa->get_qt_field_name('attachments'),
'value' => $pickeroptions->itemid));
}
defined('MOODLE_INTERNAL') || die();
$plugin->component = 'qtype_essay';
-$plugin->version = 2011102700;
+$plugin->version = 2011102702;
$plugin->requires = 2011102700;
}
public function supported_returntypes() {
- return (FILE_INTERNAL | FILE_EXTERNAL | FILE_REFERENCE);
+ return (FILE_INTERNAL | FILE_REFERENCE);
}
public static function get_type_option_names() {
'standard' => array(
'file' => 'default.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
// Main course page
'course' => array(
'file' => 'default.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
'options' => array('langmenu'=>true),
),
'coursecategory' => array(
'file' => 'default.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
// part of course, typical for modules - default page layout if $cm specified in require_login()
'incourse' => array(
'file' => 'default.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
// The site home page.
'frontpage' => array(
'file' => 'default.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
'options' => array('langmenu'=>true),
),
// Server administration scripts.
'standard' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
'options' => array('langmenu' => true)
),
// Course page
'course' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
'options' => array('langmenu' => true)
),
// Course page
'coursecategory' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
'options' => array('langmenu' => true)
),
'incourse' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
'options' => array('langmenu' => true)
),
'frontpage' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
'options' => array('langmenu' => true)
),
'admin' => array(
'mydashboard' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
'options' => array('langmenu' => true)
),
'mypublic' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
'options' => array('langmenu' => true)
),
'login' => array(
$THEME->parents = array(
- 'canvas',
- 'base',
+ 'canvas',
+ 'base',
);
/////////////////////////////////////////////////////
$THEME->sheets = array(
'pagelayout',
- 'core',
- 'settings',
+ 'core',
+ 'settings',
);
////////////////////////////////////////////////////
////////////////////////////////////////////////////
$THEME->parents_exclude_sheets = array(
- 'base'=>array(
- 'pagelayout',
- ),
- 'canvas'=>array(
- 'pagelayout',
- ),
+ 'base'=>array(
+ 'pagelayout',
+ ),
+ 'canvas'=>array(
+ 'pagelayout',
+ ),
);
'options' => array('nofooter'=>true, 'nonavbar'=>true, 'nocustommenu'=>true),
),
'embedded' => array(
- 'theme' => 'canvas',
+ 'theme' => 'canvas',
'file' => 'embedded.php',
'regions' => array(),
'options' => array('nofooter'=>true, 'nonavbar'=>true, 'nocustommenu'=>true),
// As above but will be included in the page footer.
////////////////////////////////////////////////////
-$THEME->larrow = '⟨';
+$THEME->larrow = '⟨';
////////////////////////////////////////////////////
// Overrides the left arrow image used throughout
// Moodle
////////////////////////////////////////////////////
-$THEME->rarrow = '⟩';
+$THEME->rarrow = '⟩';
////////////////////////////////////////////////////
// Overrides the right arrow image used throughout Moodle
'standard' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
// Main course page
'course' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
'options' => array('langmenu'=>true),
),
'coursecategory' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
// part of course, typical for modules - default page layout if $cm specified in require_login()
'incourse' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
// The site home page.
'frontpage' => array(
'file' => 'frontpage.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
// Server administration scripts.
'admin' => array(
'mydashboard' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
'options' => array('langmenu'=>true),
),
// My public page
'mypublic' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'login' => array(
'file' => 'general.php',
'base' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'standard' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'course' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post'
+ 'defaultregion' => 'side-pre'
),
'coursecategory' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'incourse' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'frontpage' => array(
'file' => 'frontpage.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'admin' => array(
'file' => 'general.php',
'mydashboard' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
'options' => array('langmenu'=>true),
),
'mypublic' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'login' => array(
'file' => 'general.php',
+++ /dev/null
-/* --------------------------------------------------------------
-
- Boilerplate reset.css
- * Resets default browser CSS.
-
--------------------------------------------------------------- */
-
-html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, code, del, dfn, em, img, q, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td { margin: 0; padding: 0; border: 0; font-weight: inherit; font-style: inherit; font-size: 100%; font-family: inherit; vertical-align: baseline; }
-body { line-height: 1.5; background: #fff; margin: 0; }
-table { border-collapse: collapse; border-spacing: 0; }
-caption, th, td { text-align: left; font-weight:400; }
-blockquote:before, blockquote:after, q:before, q:after { content: ""; }
-blockquote, q { quotes: "" ""; }
-a img { border: none; }
-input,textarea { margin: 0; }
-
-/* Removes Firefox imposed outline */
-a { outline: none; }
-
-/* Clearing floats without extra markup */
-.wrapper { display: inline-block; }
-.wrapper:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
-* html .wrapper { height: 1%; }
-.wrapper { display: block; }
-
-/* --------------------------------------------------------------
-
- Boilerplate typography.css
- * Sets up some sensible default typography.
-
--------------------------------------------------------------- */
-
-/* This is where you set your desired font size. The line-heights
- and vertical margins are automatically calculated from this.
- The percentage is of 16px (0.75 * 16px = 12px). */
-body { font-size: 85%; }
-
-
-/* Default fonts and colors. */
-body,h1,h2,h3,h4,h5,h6,p,ul,ol,dl,input,textarea { font-family: Helvetica, Arial, sans-serif; }
-
-
-/* Headings
--------------------------------------------------------------- */
-
-h1,h2,h3,h4,h5,h6 { font-weight: bold; }
-
-h1 { font-size: 2.25em; line-height: 1; margin-bottom: 0.5em; }
-h2 { font-size: 1.75em; margin-bottom: 0.5em; }
-h3 { font-size: 1.5em; line-height: 1; margin-bottom: 1em; }
-h4 { font-size: 1.2em; line-height: 1.25; margin-bottom: 1em; }
-h5 { font-size: 1em; margin-bottom: 1.5em; }
-h6 { font-size: 1em; }
-
-
-/* Text elements
--------------------------------------------------------------- */
-
-p { margin: 0 0 1em; }
-
-ul, ol { margin: 0 1.5em 1.5em 1.5em; }
-ul { list-style-type: circle; }
-ol { list-style-type: decimal; }
-
-dl { margin: 0 0 1.5em 0; }
-dl dt { font-weight: bold; }
-dl dd { margin-left: 1.5em; }
-
-abbr, acronym { border-bottom: 1px dotted #000; }
-address { margin-top: 1.5em; font-style: italic; }
-del { color: #000; }
-
-a { color: #009; text-decoration: none; }
-a:hover { text-decoration: underline; }
-
-blockquote { margin: 1.5em; }
-strong { font-weight: bold; }
-em, dfn { font-style: italic; }
-dfn { font-weight: bold; }
-pre, code { margin: 1.5em 0; white-space: pre; }
-pre, code, tt { font: 1.2em monospace; line-height: 1.5; }
-tt { display: block; margin: 1.5em 0; line-height: 1.5; }
-
-
-/* Tables
--------------------------------------------------------------- */
-
-th { border-bottom: 2px solid #ddd; font-weight: bold; }
-th,td { padding: 4px;vertical-align: middle }
-tfoot { font-style: italic; }
-caption { background: #ffc; }
-
-
-/* Some default classes
--------------------------------------------------------------- */
-
-.small { font-size: .8em; margin-bottom: 1.875em; line-height: 1.875em; }
-.large { font-size: 1.25em; line-height:1.5em; margin-bottom: 1em; }
-.quiet { color: #999; }
-
-.hide { display: none; }
-.highlight { background: #ffc; }
-
-.top { margin-top: 0; padding-top: 0; }
-.bottom { margin-bottom: 0; padding-bottom: 0; }
-
-/* --------------------------------------------------------------
-
- Boilerplate forms.css
- * Sets up some default styling for forms
-
--------------------------------------------------------------- */
-
-label { font-weight: bold; }
-
-/* Fieldsets */
-fieldset { padding: 1.4em; margin: 0 0 1.5em 0; border: 1px solid #ddd; }
-legend { padding: 0 .4em; font-weight: bold; font-size: 1.2em; }
-
-/* Textareas */
-textarea { margin: 0.5em 0.5em 0 0; }
-textarea { padding: .4em; }
-
-
-/* hForm
--------------------------------------------------------------- */
-form.hform p { margin: 0 0 .5em; }
-form.hform p label { float: left; width: 100px; }
-
-form.hform p input { width: 200px; }
-form.hform p select { width: 200px; }
-
-form.hform p input.button { width: auto; }
-form.hform p input.checkbox { width: auto; }
-form.hform p input.radio { width: auto; }
-
-form.hform p.checkbox { margin-left: 100px; }
-form.hform p.checkbox label { float: none; }
-form.hform p.checkbox input { width: auto; }
-
-
-/* vForm
--------------------------------------------------------------- */
-form.vform p { margin: 0 0 .5em; }
-form.vform p label { display: block; }
-
-form.vform p.checkbox label { display: inline; }
'base' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'standard' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'course' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post'
+ 'defaultregion' => 'side-pre'
),
'coursecategory' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'incourse' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'frontpage' => array(
'file' => 'frontpage.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'admin' => array(
'file' => 'general.php',
'mydashboard' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
'options' => array('langmenu'=>true),
),
'mypublic' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'login' => array(
'file' => 'general.php',
'base' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'standard' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'course' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
'options' => array('langmenu'=>true),
),
'coursecategory' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'incourse' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'frontpage' => array(
'file' => 'frontpage.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
'options' => array('langmenu'=>true),
),
'admin' => array(
'mydashboard' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
'options' => array('langmenu'=>true),
),
'mypublic' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'login' => array(
'file' => 'general.php',
#page-enrol-instances .select.menujump {margin-left:0.5em;}
/* environmenttable */
-.environmenttable .error {
- background-color: red;
-}
-
-.environmenttable .warn {
- background-color: yellow;
-}
-
-.environmenttable .ok {
- background-color: lime;
-}
+.environmenttable .error {background-color:red;}
+.environmenttable .warn {background-color:yellow;}
+.environmenttable .ok {background-color:lime;}
/* adminsettings */
-#adminsettings .form-overridden {
- background-color: yellow;
-}
+#adminsettings .form-overridden {background-color:yellow;}
+#adminsettings .form-warning {color:red;}
/* tables */
.editcourse th,
'base' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'standard' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'course' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post'
+ 'defaultregion' => 'side-pre'
),
'coursecategory' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'incourse' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'frontpage' => array(
'file' => 'frontpage.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'admin' => array(
'file' => 'general.php',
'mydashboard' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
'options' => array('langmenu'=>true),
),
'mypublic' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'login' => array(
'file' => 'general.php',
'base' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'standard' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'course' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post'
+ 'defaultregion' => 'side-pre'
),
'coursecategory' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'incourse' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'frontpage' => array(
'file' => 'frontpage.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'admin' => array(
'file' => 'general.php',
'mydashboard' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
'options' => array('langmenu'=>true),
),
'mypublic' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'login' => array(
'file' => 'general.php',
////////////////////////////////////////////////////
$THEME->layouts = array(
+ // Most backwards compatible layout without the blocks - this is the layout used by default
'base' => array(
'file' => 'general.php',
- 'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'regions' => array(),
),
- 'general' => array(
+ // Standard layout with blocks, this is recommended for most pages with general information
+ 'standard' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'course' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post'
+ 'defaultregion' => 'side-pre'
),
'coursecategory' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'incourse' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'frontpage' => array(
'file' => 'frontpage.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'admin' => array(
'file' => 'general.php',
'mydashboard' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
'options' => array('langmenu'=>true),
),
'mypublic' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'login' => array(
'file' => 'general.php',
+++ /dev/null
-<?php echo $OUTPUT->doctype() ?>
-<html <?php echo $OUTPUT->htmlattributes() ?>>
-<head>
- <title><?php echo $PAGE->title ?></title>
- <link rel="shortcut icon" href="<?php echo $OUTPUT->pix_url('favicon', 'theme')?>" />
- <?php echo $OUTPUT->standard_head_html() ?>
-</head>
-<body id="<?php p($PAGE->bodyid) ?>" class="<?php p($PAGE->bodyclasses) ?>">
-<?php echo $OUTPUT->standard_top_of_body_html() ?>
-
-<div id="page">
-
-<!-- END OF HEADER -->
-
- <div id="content" class="clearfix">
- <?php echo $OUTPUT->main_content() ?>
- </div>
-
-<!-- START OF FOOTER -->
-</div>
-<?php echo $OUTPUT->standard_end_of_body_html() ?>
-</body>
-</html>
\ No newline at end of file
+++ /dev/null
-<?php
-
-$hassidepre = (empty($PAGE->layout_options['noblocks']) && $PAGE->blocks->region_has_content('side-pre', $OUTPUT));
-$hassidepost = (empty($PAGE->layout_options['noblocks']) && $PAGE->blocks->region_has_content('side-post', $OUTPUT));
-
-$showsidepre = ($hassidepre && !$PAGE->blocks->region_completely_docked('side-pre', $OUTPUT));
-$showsidepost = ($hassidepost && !$PAGE->blocks->region_completely_docked('side-post', $OUTPUT));
-$custommenu = $OUTPUT->custom_menu();
-$hascustommenu = (empty($PAGE->layout_options['nocustommenu']) && !empty($custommenu));
-
-$bodyclasses = array();
-if ($showsidepre && !$showsidepost) {
- $bodyclasses[] = 'side-pre-only';
-} else if ($showsidepost && !$showsidepre) {
- $bodyclasses[] = 'side-post-only';
-} else if (!$showsidepost && !$showsidepre) {
- $bodyclasses[] = 'content-only';
-}
-if ($hassidepre || $hassidepost) {
- $bodyclasses[] = 'background';
-}
-if ($hascustommenu) {
- $bodyclasses[] = 'has_custom_menu';
-}
-
-echo $OUTPUT->doctype() ?>
-<html <?php echo $OUTPUT->htmlattributes() ?>>
-<head>
- <title><?php echo $PAGE->title ?></title>
- <link rel="shortcut icon" href="<?php echo $OUTPUT->pix_url('favicon', 'theme')?>" />
- <meta name="description" content="<?php p(strip_tags(format_text($SITE->summary, FORMAT_HTML))) ?>" />
- <?php echo $OUTPUT->standard_head_html() ?>
-</head>
-<body id="<?php p($PAGE->bodyid) ?>" class="<?php p($PAGE->bodyclasses.' '.join(' ', $bodyclasses)) ?>">
-<?php echo $OUTPUT->standard_top_of_body_html() ?>
-
-<div id="page">
- <div id="wrapper" class="clearfix">
-
-<!-- START OF HEADER -->
-
- <div id="page-header" class="clearfix">
- <div id="page-header-wrapper">
- <h1 class="headermain"><?php echo $PAGE->heading ?></h1>
- <div class="headermenu">
- <?php
- echo $OUTPUT->login_info();
- echo $OUTPUT->lang_menu();
- echo $PAGE->headingmenu;
- ?>
- </div>
- </div>
- </div>
-<?php if ($hascustommenu) { ?>
- <div id="custommenu"><?php echo $custommenu; ?></div>
-<?php } ?>
-<!-- END OF HEADER -->
-
-<!-- START OF CONTENT -->
-
-<div id="page-content-wrapper">
- <div id="page-content">
- <div id="region-main-box">
- <div id="region-post-box">
-
- <div id="region-main-wrap">
- <div id="region-main">
- <div class="region-content">
- <?php echo $OUTPUT->main_content() ?>
- </div>
- </div>
- </div>
-
- <?php if ($hassidepre) { ?>
- <div id="region-pre" class="block-region">
- <div class="region-content">
- <?php echo $OUTPUT->blocks_for_region('side-pre') ?>
- </div>
- </div>
- <?php } ?>
-
- <?php if ($hassidepost) { ?>
- <div id="region-post" class="block-region">
- <div class="region-content">
- <?php echo $OUTPUT->blocks_for_region('side-post') ?>
- </div>
- </div>
- <?php } ?>
-
- </div>
- </div>
- </div>
-</div>
-
-<!-- END OF CONTENT -->
-
- </div>
-
-<!-- START OF FOOTER -->
-
- <div id="page-footer">
- <p class="helplink">
- <?php echo page_doc_link(get_string('moodledocslink')) ?>
- </p>
-
- <?php
- echo $OUTPUT->login_info();
- echo $OUTPUT->home_link();
- echo $OUTPUT->standard_footer_html();
- ?>
- </div>
-
-<!-- END OF FOOTER -->
-</div>
-<?php echo $OUTPUT->standard_end_of_body_html() ?>
-</body>
-</html>
+++ /dev/null
-<?php
-
-$hasheading = ($PAGE->heading);
-$hasnavbar = (empty($PAGE->layout_options['nonavbar']) && $PAGE->has_navbar());
-$hasfooter = (empty($PAGE->layout_options['nofooter']));
-$hassidepre = (empty($PAGE->layout_options['noblocks']) && $PAGE->blocks->region_has_content('side-pre', $OUTPUT));
-$hassidepost = (empty($PAGE->layout_options['noblocks']) && $PAGE->blocks->region_has_content('side-post', $OUTPUT));
-
-$showsidepre = ($hassidepre && !$PAGE->blocks->region_completely_docked('side-pre', $OUTPUT));
-$showsidepost = ($hassidepost && !$PAGE->blocks->region_completely_docked('side-post', $OUTPUT));
-$custommenu = $OUTPUT->custom_menu();
-$hascustommenu = (empty($PAGE->layout_options['nocustommenu']) && !empty($custommenu));
-
-$bodyclasses = array();
-if ($showsidepre && !$showsidepost) {
- $bodyclasses[] = 'side-pre-only';
-} else if ($showsidepost && !$showsidepre) {
- $bodyclasses[] = 'side-post-only';
-} else if (!$showsidepost && !$showsidepre) {
- $bodyclasses[] = 'content-only';
-}
-if ($hascustommenu) {
- $bodyclasses[] = 'has_custom_menu';
-}
-echo $OUTPUT->doctype() ?>
-<html <?php echo $OUTPUT->htmlattributes() ?>>
-<head>
- <title><?php echo $PAGE->title ?></title>
- <link rel="shortcut icon" href="<?php echo $OUTPUT->pix_url('favicon', 'theme')?>" />
- <?php echo $OUTPUT->standard_head_html() ?>
-</head>
-<body id="<?php p($PAGE->bodyid) ?>" class="<?php p($PAGE->bodyclasses.' '.join(' ', $bodyclasses)) ?>">
-<?php echo $OUTPUT->standard_top_of_body_html() ?>
-
-<div id="page">
- <div id="wrapper" class="clearfix">
-<?php if ($hasheading || $hasnavbar) { ?>
-
- <div id="page-header" class="clearfix">
-
- <?php if ($hasheading) { ?>
- <h1 class="headermain"><?php echo $PAGE->heading ?></h1>
- <div class="headermenu">
- <?php
- echo $OUTPUT->login_info();
- if (!empty($PAGE->layout_options['langmenu'])) {
- echo $OUTPUT->lang_menu();
- }
- echo $PAGE->headingmenu
- ?>
- </div>
- <?php } ?>
-
- </div>
-
- <?php if ($hascustommenu) { ?>
- <div id="custommenu"><?php echo $custommenu; ?></div>
- <?php } ?>
-
- <?php if ($hasnavbar) { ?>
- <div class="navbar clearfix">
- <div class="breadcrumb"><?php echo $OUTPUT->navbar(); ?></div>
- <div class="navbutton"> <?php echo $PAGE->button; ?></div>
- </div>
- <?php } ?>
-
-<?php } ?>
-
-<!-- END OF HEADER -->
-
-<div id="page-content-wrapper">
- <div id="page-content">
- <div id="region-main-box">
- <div id="region-post-box">
-
- <div id="region-main-wrap">
- <div id="region-main">
- <div class="region-content">
- <?php echo $OUTPUT->main_content() ?>
- </div>
- </div>
- </div>
-
- <?php if ($hassidepre) { ?>
- <div id="region-pre" class="block-region">
- <div class="region-content">
- <?php echo $OUTPUT->blocks_for_region('side-pre') ?>
- </div>
- </div>
- <?php } ?>
-
- <?php if ($hassidepost) { ?>
- <div id="region-post" class="block-region">
- <div class="region-content">
- <?php echo $OUTPUT->blocks_for_region('side-post') ?>
- </div>
- </div>
- <?php } ?>
-
- </div>
- </div>
- </div>
-</div>
-
- </div>
-
-<!-- START OF FOOTER -->
- <?php if ($hasfooter) { ?>
- <div id="page-footer" class="clearfix">
- <p class="helplink"><?php echo page_doc_link(get_string('moodledocslink')) ?></p>
- <?php
- echo $OUTPUT->login_info();
- echo $OUTPUT->home_link();
- echo $OUTPUT->standard_footer_html();
- ?>
- </div>
- <?php } ?>
-</div>
-<?php echo $OUTPUT->standard_end_of_body_html() ?>
-</body>
-</html>
'standard' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post'
+ 'defaultregion' => 'side-pre'
),
// Course page
'course' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post'
+ 'defaultregion' => 'side-pre'
),
// Course page
'coursecategory' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post'
+ 'defaultregion' => 'side-pre'
),
'incourse' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post'
+ 'defaultregion' => 'side-pre'
),
'frontpage' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post'
+ 'defaultregion' => 'side-pre'
),
'admin' => array(
'file' => 'general.php',
'mydashboard' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post'
+ 'defaultregion' => 'side-pre'
),
'mypublic' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post'
+ 'defaultregion' => 'side-pre'
),
'login' => array(
'file' => 'general.php',
'standard' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
// Main course page
'course' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
'options' => array('langmenu'=>true),
),
'coursecategory' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
// part of course, typical for modules - default page layout if $cm specified in require_login()
'incourse' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
// The site home page.
'frontpage' => array(
'file' => 'frontpage.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
// Server administration scripts.
'admin' => array(
'mydashboard' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
'options' => array('langmenu'=>true),
),
// My public page
'mypublic' => array(
'file' => 'general.php',
'regions' => array('side-pre', 'side-post'),
- 'defaultregion' => 'side-post',
+ 'defaultregion' => 'side-pre',
),
'login' => array(
'file' => 'general.php',
information provided here is intended especially for theme designer.
+=== 2.3 ===
+
+optional changes:
+* add new u/f3.png image when theme contains customised f1 and f2 default user images
+
=== 2.2 ===
required changes:
defined('MOODLE_INTERNAL') || die();
-$version = 2012052500.00; // YYYYMMDD = weekly release date of this DEV branch
+$version = 2012052900.05; // YYYYMMDD = weekly release date of this DEV branch
// RR = release increments - 00 in DEV branches
// .XX = incremental changes