$message = get_string('formatuninstallconfirm', 'admin', $format->displayname);
}
$deleteurl->param('confirm', 1);
- echo $OUTPUT->confirm($message, $deleteurl, $return);
+ echo $OUTPUT->confirm($message, $deleteurl, $return);
} else {
$a = new stdClass();
$a->plugin = $format->displayname;
echo $OUTPUT->footer();
exit;
}
-redirect($return);
\ No newline at end of file
+redirect($return);
// Question type settings
if ($hassiteconfig || has_capability('moodle/question:config', $systemcontext)) {
+ if (!$hassiteconfig) {
+ require_once("$CFG->libdir/pluginlib.php");
+ $allplugins = plugin_manager::instance()->get_plugins();
+ }
// Question behaviour settings.
$ADMIN->add('modules', new admin_category('qbehavioursettings', new lang_string('questionbehaviours', 'admin')));
$ADMIN->add('qbehavioursettings', new admin_page_manageqbehaviours());
$temp->add(new admin_setting_configtext('curltimeoutkbitrate', new lang_string('curltimeoutkbitrate', 'admin'),
new lang_string('curltimeoutkbitrate_help', 'admin'), 56, PARAM_INT));
-/* //TODO: we need to fix code instead of relying on slow rcache, enable this once we have some code that is actually using it
-$temp->add(new admin_setting_special_selectsetup('cachetype', new lang_string('cachetype', 'admin'),
- new lang_string('configcachetype', 'admin'), '',
- array( '' => new lang_string('none'),
- 'internal' => 'internal',
- 'memcached' => 'memcached',
- 'eaccelerator' => 'eaccelerator')));
-// NOTE: $CFG->rcache is forced to bool in lib/setup.php
-$temp->add(new admin_setting_special_selectsetup('rcache', new lang_string('rcache', 'admin'),
- new lang_string('configrcache', 'admin'), 0,
- array( '0' => new lang_string('no'),
- '1' => new lang_string('yes'))));
-$temp->add(new admin_setting_configtext('rcachettl', new lang_string('rcachettl', 'admin'),
- new lang_string('configrcachettl', 'admin'), 10));
-$temp->add(new admin_setting_configtext('intcachemax', new lang_string('intcachemax', 'admin'),
- new lang_string('configintcachemax', 'admin'), 10));
-$temp->add(new admin_setting_configtext('memcachedhosts', new lang_string('memcachedhosts', 'admin'),
- new lang_string('configmemcachedhosts', 'admin'), ''));
-$temp->add(new admin_setting_configselect('memcachedpconn', new lang_string('memcachedpconn', 'admin'),
- new lang_string('configmemcachedpconn', 'admin'), 0,
- array( '0' => new lang_string('no'),
- '1' => new lang_string('yes'))));
-*/
$ADMIN->add('server', $temp);
} else {
$columndir = $dir == "ASC" ? "DESC":"ASC";
if ($column == "lastaccess") {
- $columnicon = $dir == "ASC" ? "up":"down";
+ $columnicon = ($dir == "ASC") ? "sort_desc" : "sort_asc";
} else {
- $columnicon = $dir == "ASC" ? "down":"up";
+ $columnicon = ($dir == "ASC") ? "sort_asc" : "sort_desc";
}
- $columnicon = " <img src=\"" . $OUTPUT->pix_url('t/' . $columnicon) . "\" alt=\"\" />";
+ $columnicon = "<img class='iconsort' src=\"" . $OUTPUT->pix_url('t/' . $columnicon) . "\" alt=\"\" />";
}
$$column = "<a href=\"user.php?sort=$column&dir=$columndir\">".$string[$column]."</a>$columnicon";
return $files;
}
foreach ($matches[2] as $match) {
- $files[] = str_replace(array('$@FILEPHP@$', '$@SLASH@$', '$@FORCEDOWNLOAD@$'), array('', '/', ''), $match);
+ $file = str_replace(array('$@FILEPHP@$', '$@SLASH@$', '$@FORCEDOWNLOAD@$'), array('', '/', ''), $match);
+ $files[] = urldecode($file);
}
return array_unique($files);
<br /><a href=\'$@FILEPHP@$$@SLASH@$MANUAL.DOC$@FORCEDOWNLOAD@$\'>download manual</a><br />');
}
+ public function test_referenced_files_urlencoded() {
+ // This test covers MDL-36204
+ $text = 'This is a text containing links to file.php
+as it is parsed from the backup file. <br /><br /><img border="0" width="110" vspace="0" hspace="0" height="92" title="News" alt="News" src="$@FILEPHP@$$@SLASH@$pics$@SLASH@$news.gif" /><a href="$@FILEPHP@$$@SLASH@$pics$@SLASH@$news.gif$@FORCEDOWNLOAD@$">no space</a><br />
+ <br /><a href=\'$@FILEPHP@$$@SLASH@$pics$@SLASH@$news%20with%20spaces.gif$@FORCEDOWNLOAD@$\'>with urlencoded spaces</a><br />';
+
+ $files = moodle1_converter::find_referenced_files($text);
+ $this->assertEquals(gettype($files), 'array');
+ $this->assertEquals(2, count($files));
+ $this->assertTrue(in_array('/pics/news.gif', $files));
+ $this->assertTrue(in_array('/pics/news with spaces.gif', $files));
+ }
+
public function test_question_bank_conversion() {
global $CFG;
$grade_category = new backup_nested_element('grade_category', array('id'), array(
//'courseid',
'parent', 'depth', 'path', 'fullname', 'aggregation', 'keephigh',
- 'dropload', 'aggregateonlygraded', 'aggregateoutcomes', 'aggregatesubcats',
+ 'droplow', 'aggregateonlygraded', 'aggregateoutcomes', 'aggregatesubcats',
'timecreated', 'timemodified', 'hidden'));
$letters = new backup_nested_element('grade_letters');
AND ' . $DB->sql_compare_text('hint', 255) . ' = ' . $DB->sql_compare_text('?', 255);
$params = array($newquestionid, $data->hint);
$newitemid = $DB->get_field_sql($sql, $params);
+
+ // Not able to find the hint, let's try cleaning the hint text
+ // of all the question's hints in DB as slower fallback. MDL-33863.
+ if (!$newitemid) {
+ $potentialhints = $DB->get_records('question_hints',
+ array('questionid' => $newquestionid), '', 'id, hint');
+ foreach ($potentialhints as $potentialhint) {
+ // Clean in the same way than {@link xml_writer::xml_safe_utf8()}.
+ $cleanhint = preg_replace('/[\x-\x8\xb-\xc\xe-\x1f\x7f]/is','', $potentialhint->hint); // Clean CTRL chars.
+ $cleanhint = preg_replace("/\r\n|\r/", "\n", $cleanhint); // Normalize line ending.
+ if ($cleanhint === $data->hint) {
+ $newitemid = $data->id;
+ }
+ }
+ }
+
// If we haven't found the newitemid, something has gone really wrong, question in DB
// is missing hints, exception
if (!$newitemid) {
foreach ($modfullnames as $modname => $modfullname) {
if ($modname === 'resources') {
- $icon = $OUTPUT->pix_icon(file_extension_icon('.htm'), '', 'moodle', array('class' => 'icon')). ' ';
+ $icon = $OUTPUT->pix_icon('icon', '', 'mod_page', array('class' => 'icon'));
$this->content->items[] = '<a href="'.$CFG->wwwroot.'/course/resources.php?id='.$course->id.'">'.$icon.$modfullname.'</a>';
} else {
- $icon = '<img src="'.$OUTPUT->pix_url('icon', $modname) . '" class="icon" alt="" /> ';
+ $icon = '<img src="'.$OUTPUT->pix_url('icon', $modname) . '" class="icon" alt="" />';
$this->content->items[] = '<a href="'.$CFG->wwwroot.'/mod/'.$modname.'/index.php?id='.$course->id.'">'.$icon.$modfullname.'</a>';
}
}
'class' => 'icon', 'alt' => get_string('addcourse', 'block_community')));
$addcourseurl = new moodle_url('/blocks/community/communitycourse.php',
array('add' => true, 'courseid' => $this->page->course->id));
- $searchlink = html_writer::tag('a', $icon . ' ' . get_string('addcourse', 'block_community'),
+ $searchlink = html_writer::tag('a', $icon . get_string('addcourse', 'block_community'),
array('href' => $addcourseurl->out(false)));
$this->content->items[] = $searchlink;
$this->content->icons = array();
$this->content->footer = '';
- $icon = '<img src="' . $OUTPUT->pix_url('i/course') . '" class="icon" alt="" /> ';
+ $icon = '<img src="' . $OUTPUT->pix_url('i/course') . '" class="icon" alt="" />';
$adminseesall = true;
if (isset($CFG->block_course_list_adminview)) {
return;
}
- $icon = '<img src="'.$OUTPUT->pix_url('i/mnethost') . '" class="icon" alt="" /> ';
+ $icon = '<img src="'.$OUTPUT->pix_url('i/mnethost') . '" class="icon" alt="" />';
// shortcut - the rest is only for logged in users!
if (!isloggedin() || isguestuser()) {
$output .= html_writer::start_tag('div', array('class' => 'activity_overview'));
$url = new moodle_url("/mod/$module/index.php", array('id' => $cid));
$modulename = get_string('modulename', $module);
- $icontext = html_writer::link($url, $this->output->pix_icon('icon', $modulename, 'mod_'.$module, array('class'=>'icon')).' ');
+ $icontext = html_writer::link($url, $this->output->pix_icon('icon', $modulename, 'mod_'.$module, array('class'=>'iconlarge')));
if (get_string_manager()->string_exists("activityoverview", $module)) {
$icontext .= get_string("activityoverview", $module);
} else {
}
.block_course_overview .content {
- margin-left: 20px;
+ margin: 0 20px;
+}
+.block_course_overview .content .notice {
+ margin: 5px 0;
}
.block_course_overview .coursebox {
- padding: 15px 0 10px 10px;
- width: 98%;
+ padding: 15px;
+ width: auto;
}
.block_course_overview .profilepicture {
.block_course_overview .content h2.title {
float: left;
- margin-bottom: 0;
- margin-top: 0;
+ margin: 0 0 .5em 0;
position: relative;
}
.dir-rtl .block_course_overview .content h2.title {
.block_course_overview .activity_overview {
padding: 2px;
}
+.block_course_overview .activity_overview img.iconlarge { vertical-align: text-bottom; margin-right: 6px; }
+.dir-rtl .block_course_overview .activity_overview img.iconlarge { margin-left: 6px; margin-right: 0;}
.block_course_overview .singleselect {
text-align: left;
border-width: 2px;
border-style: dashed;
}
-
-.block_course_overview .collapsibleregioninner .name {margin-right: 20px;}
-.block_course_overview .collapsibleregioninner .info,
-.block_course_overview .collapsibleregioninner .details {margin-right: 25px;}
\ No newline at end of file
'position' : 'relative',
'fontSize' : fontsize,
'width' : width,
- 'top' : width/2,
- 'right' : width/2 - height
+ 'top' : width/2
});
+ // Positioning is different when in RTL mode.
+ if (right_to_left()) {
+ title.setStyle('left', width/2 - height);
+ } else {
+ title.setStyle('right', width/2 - height);
+ }
+
// Rotate the text
title.setStyles({
'transform' : transform,
// Must set the image src seperatly of we get an error with XML strict headers
var moveto = Y.Node.create('<input type="image" class="moveto customcommand requiresjs" alt="'+M.str.block.addtodock+'" title="'+M.str.block.addtodock+'" />');
- moveto.setAttribute('src', M.util.image_url('t/block_to_dock', 'moodle'));
+ var icon = 't/block_to_dock';
+ if (right_to_left()) {
+ icon = 't/block_to_dock_rtl';
+ }
+ moveto.setAttribute('src', M.util.image_url(icon, 'moodle'));
moveto.on('movetodock|click', this.move_to_dock, this, commands);
var blockaction = node.one('.block_action');
// Must set the image src seperatly of we get an error with XML strict headers
var movetoimg = Y.Node.create('<img alt="'+M.str.block.undockitem+'" title="'+M.str.block.undockitem+'" />');
- movetoimg.setAttribute('src', M.util.image_url('t/dock_to_block', 'moodle'));
+ var icon = 't/dock_to_block';
+ if (right_to_left()) {
+ icon = 't/dock_to_block_rtl';
+ }
+ movetoimg.setAttribute('src', M.util.image_url(icon, 'moodle'));
var moveto = Y.Node.create('<a class="moveto customcommand requiresjs"></a>').append(movetoimg);
if (location.href.match(/\?/)) {
moveto.set('href', location.href+'&dock='+this.id);
}, this);
// Add a close icon
// Must set the image src seperatly of we get an error with XML strict headers
- var closeicon = Y.Node.create('<span class="hidepanelicon" tabindex="0"><img alt="" style="width:11px;height:11px;cursor:pointer;" /></span>');
+ var closeicon = Y.Node.create('<span class="hidepanelicon" tabindex="0"><img alt="" /></span>');
closeicon.one('img').setAttribute('src', M.util.image_url('t/dockclose', 'moodle'));
closeicon.on('forceclose|click', this.hide, this);
closeicon.on('dock:actionkey',this.hide, this, {actions:{enter:true,toggle:true}});
$course = $this->page->course;
$modinfo = get_fast_modinfo($course);
$glossaryid = $this->config->glossary;
- $cm = $modinfo->instances['glossary'][$glossaryid];
-
- if (!has_capability('mod/glossary:view', context_module::instance($cm->id))) {
- return '';
- }
if (!isset($modinfo->instances['glossary'][$glossaryid])) {
// we can get here if the glossary has been deleted, so
return $this->content;
}
+ $cm = $modinfo->instances['glossary'][$glossaryid];
+
+ if (!has_capability('mod/glossary:view', context_module::instance($cm->id))) {
+ return '';
+ }
+
if (empty($this->config->cache)) {
$this->config->cache = '';
}
/** General display rules **/
.block_navigation .block_tree {margin:5px;padding-left:0px;overflow:visible;}
.block_navigation .block_tree li {margin:3px;list-style: none;padding:0;}
-.block_navigation .block_tree li.item_with_icon > p {position:relative;}
-.block_navigation .block_tree li.item_with_icon > p img {vertical-align:middle;position:absolute;left:0;top:3px}
+.block_navigation .block_tree li.item_with_icon > p {position:relative; padding-left: 21px;}
+.block_navigation .block_tree li.item_with_icon > p img,
+.block_navigation .block_tree .type_activity > p.tree_item.active_tree_node img,
+.block_navigation .block_tree li > p.hasicon img {vertical-align:middle;position:absolute;left:0;top:-1px;width:16px;height:16px;}
.block_navigation .block_tree li.item_with_icon.contains_branch > p img {left:16px;}
-.block_navigation .block_tree li.item_with_icon.contains_branch .tree_item {padding-left:34px;}
+.block_navigation .block_tree .type_activity > p.branch.hasicon,
+.block_navigation .block_tree li.item_with_icon.contains_branch > .tree_item {padding-left:37px;}
.block_navigation .block_tree li ul {padding-left:0;margin:0;}
.block_navigation .block_tree li.depth_2 ul {padding-left:16px;margin:0;}
-.block_navigation .block_tree .tree_item {padding-left: 18px;margin:3px 0px;text-align:left;}
+.block_navigation .block_tree .type_activity > p.tree_item.branch.hasicon.active_tree_node,
+.block_navigation .block_tree .tree_item {padding-left: 21px;margin:3px 0px;text-align:left;}
-.block_navigation .block_tree .tree_item.branch {background-image: url([[pix:t/expanded]]);background-position: 0 10%;background-repeat: no-repeat;}
+.block_navigation .block_tree .tree_item.branch {background-image: url([[pix:t/expanded]]);background-position: 0 0;background-repeat: no-repeat;}
.block_navigation .block_tree .tree_item.branch.navigation_node {background-image:none;padding-left:0;}
.block_navigation .block_tree .type_activity > .tree_item.branch {background-image:none;position:relative;}
-.block_navigation .block_tree .type_activity > .tree_item.branch img {position:absolute;left:0;}
+.block_navigation .block_tree .type_activity > .tree_item.branch img {left: 16px;}
.block_navigation .block_tree .root_node.leaf {padding-left:0px;}
.block_navigation .block_tree .active_tree_node {font-weight:bold;}
.block_navigation .block_tree .depth_1.current_branch ul {font-weight:normal;}
.dock .block_navigation .tree_item {white-space: nowrap;}
.jsenabled .block_navigation .block_tree .tree_item.branch {cursor:pointer;}
-.jsenabled .block_navigation .block_tree .tree_item.emptybranch {background-image: url([[pix:t/collapsed_empty]]);background-position: 0% 5%;background-repeat: no-repeat;}
+.jsenabled .block_navigation .block_tree .tree_item.emptybranch {background-image: url([[pix:t/collapsed_empty]]);background-position: 0 0;background-repeat: no-repeat;}
.jsenabled .block_navigation .block_tree .collapsed ul {display: none;}
+.jsenabled .block_navigation .block_tree .type_activity > .tree_item.branch {background-image: url([[pix:t/expanded]]);}
.jsenabled .block_navigation .block_tree .collapsed .tree_item.branch {background-image: url([[pix:t/collapsed]]);}
.jsenabled .block_navigation .block_tree .tree_item.branch.loadingbranch {background-image:url([[pix:i/loading_small]]);}
.ie6 .block_navigation .block_tree .tree_item {width:100%;}
/** Overide for RTL layout **/
-.dir-rtl .block_navigation .block_tree li.depth_2 ul {padding-left:0;padding-right: 7px;}
-.dir-rtl .block_navigation .block_tree .tree_item {padding-right: 18px;text-align:right;}
+.dir-rtl .block_navigation .block_tree li.depth_2 ul {padding-left:0;padding-right: 16px; padding-left: 0;}
+.dir-rtl .block_navigation .block_tree .type_activity > p.tree_item.branch.hasicon.active_tree_node,
+.dir-rtl .block_navigation .block_tree .tree_item {padding-right: 21px;text-align:right;}
.dir-rtl .block_navigation .block_tree .tree_item.branch {background-position: center right;}
.dir-rtl .block_navigation .block_tree .root_node.leaf {padding-right:0;}
.dir-rtl .block_navigation .block_tree li.item_with_icon > p img,
-.dir-rtl .block_navigation .block_tree .type_activity > .tree_item.branch img {right:0;left:auto;}
+.dir-rtl .block_navigation .block_tree .type_activity > p.tree_item.active_tree_node img,
+.dir-rtl .block_navigation .block_tree li > p.hasicon img {left:auto; right:0;}
+.dir-rtl .block_navigation .block_tree li.item_with_icon.contains_branch > p img {left: auto; right:16px;}
+.dir-rtl .block_navigation .block_tree .type_activity > p.branch.hasicon,
+.dir-rtl .block_navigation .block_tree li.item_with_icon.contains_branch > .tree_item {padding-right:37px; padding-left: 0;}
+.dir-rtl .block_navigation .block_tree .type_activity > .tree_item.branch img {right: 16px; left: auto;}
.jsenabled.dir-rtl .block_navigation .block_tree .tree_item.emptybranch {background-image: url([[pix:t/collapsed_empty_rtl]]);background-position: center right;}
.jsenabled.dir-rtl .block_navigation .block_tree .collapsed .tree_item.branch {background-image: url([[pix:t/collapsed_rtl]]);}
}
}
- $icon = '<img src="'.$OUTPUT->pix_url('i/users') . '" class="icon" alt="" /> ';
+ $icon = '<img src="'.$OUTPUT->pix_url('i/users') . '" class="icon" alt="" />';
$this->content->items[] = '<a title="'.get_string('listofallpeople').'" href="'.
$CFG->wwwroot.'/user/index.php?contextid='.$currentcontext->id.'">'.$icon.get_string('participants').'</a>';
$result = '<ul>';
foreach ($dir['subdirs'] as $subdir) {
$image = $this->output->pix_icon(file_folder_icon(), $subdir['dirname'], 'moodle', array('class'=>'icon'));
- $result .= '<li yuiConfig=\''.json_encode($yuiconfig).'\'><div>'.$image.' '.s($subdir['dirname']).'</div> '.$this->htmllize_tree($tree, $subdir).'</li>';
+ $result .= '<li yuiConfig=\''.json_encode($yuiconfig).'\'><div>'.$image.s($subdir['dirname']).'</div> '.$this->htmllize_tree($tree, $subdir).'</li>';
}
foreach ($dir['files'] as $file) {
$url = file_encode_url("$CFG->wwwroot/pluginfile.php", '/'.$tree->context->id.'/user/private'.$file->get_filepath().$file->get_filename(), true);
$filename = $file->get_filename();
$image = $this->output->pix_icon(file_file_icon($file), $filename, 'moodle', array('class'=>'icon'));
- $result .= '<li yuiConfig=\''.json_encode($yuiconfig).'\'><div>'.html_writer::link($url, $image.' '.$filename).'</div></li>';
+ $result .= '<li yuiConfig=\''.json_encode($yuiconfig).'\'><div>'.html_writer::link($url, $image.$filename).'</div></li>';
}
$result .= '</ul>';
/** General display rules **/
.block_settings .block_tree {margin:5px;padding-left:0px;overflow:visible;}
.block_settings .block_tree li {margin:0;list-style: none;}
-.block_settings .block_tree li ul {padding-left:16px;margin:0;}
+.block_settings .block_tree li ul {padding-left:18px;margin:0;}
.block_settings .block_tree li.item_with_icon > p {position:relative;}
-.block_settings .block_tree li.item_with_icon > p img {vertical-align:middle;position:absolute;left:0;top:-1px}
+.block_settings .block_tree li.item_with_icon > p img {vertical-align:middle;position:absolute;left:0;top:-1px; width: 16px; height: 16px;}
-.block_settings .block_tree .tree_item {padding-left: 18px;margin:3px 0px;text-align:left;}
+.block_settings .block_tree .tree_item {padding-left: 21px;margin:3px 0px;text-align:left;}
.block_settings .block_tree .tree_item.branch {background-image: url([[pix:t/expanded]]);background-position: 0 10%;background-repeat: no-repeat;}
.block_settings .block_tree .root_node.leaf {padding-left:0px;}
/** Overide for RTL layout **/
.dir-rtl .block_settings .block_tree {padding-right:0px;}
-.dir-rtl .block_settings .block_tree li ul {padding-left:0;padding-right: 7px;}
-.dir-rtl .block_settings .block_tree li.item_with_icon > p img,
-.dir-rtl .block_navigation .block_tree .type_activity > .tree_item.branch img {left:auto;right:0;}
-.dir-rtl .block_settings .block_tree .tree_item {padding-right: 18px;text-align:right;}
+.dir-rtl .block_settings .block_tree li ul {padding-left:0;padding-right: 18px;}
+.dir-rtl .block_settings .block_tree .tree_item {padding-right: 21px; padding-left: 0; text-align:right;}
.dir-rtl .block_settings .block_tree .tree_item.branch {background-position: center right;}
.dir-rtl .block_settings .block_tree .root_node.leaf {padding-right:0px;}
+.dir-rtl .block_settings .block_tree li.item_with_icon > p img { right: 0; left: auto;}
.jsenabled.dir-rtl .block_settings .block_tree .tree_item.emptybranch {background-image: url([[pix:t/collapsed_empty_rtl]]);background-position: center right;}
-.jsenabled.dir-rtl .block_settings .block_tree .collapsed .tree_item.branch {background-image: url([[pix:t/collapsed_rtl]]);}
\ No newline at end of file
+.jsenabled.dir-rtl .block_settings .block_tree .collapsed .tree_item.branch {background-image: url([[pix:t/collapsed_rtl]]);}
} else {
$linkcss = $cm->visible ? '' : ' class="dimmed" ';
//Accessibility: incidental image - should be empty Alt text
- $icon = '<img src="' . $cm->get_icon_url() . '" class="icon" alt="" /> ';
+ $icon = '<img src="' . $cm->get_icon_url() . '" class="icon" alt="" />';
$this->content->items[] = '<a title="'.$cm->modplural.'" '.$linkcss.' '.$cm->extra.
' href="' . $url . '">' . $icon . $instancename . '</a>';
}
$this->content->icons[] = '';
} else {
//Accessibility: incidental image - should be empty Alt text
- $icon = '<img src="' . $mod->get_icon_url() . '" class="icon" alt="" /> ';
+ $icon = '<img src="' . $mod->get_icon_url() . '" class="icon" alt="" />';
$this->content->items[] = '<a title="' . $mod->modfullname . '" ' . $linkcss . ' ' . $mod->extra .
' href="' . $url . '">' . $icon . $instancename . '</a>' . $editbuttons;
}
--- /dev/null
+.block_site_main_menu li { clear: both; }
+.block_site_main_menu li .column { width: 100%; }
+.block_site_main_menu li .buttons { float: right; margin-top: 3px;}
+.dir-rtl .block_site_main_menu li .buttons { float: left; }
+.block_site_main_menu li .buttons a img{ vertical-align: text-bottom; margin: 0 3px;}
+.block_site_main_menu .footer { margin-top: 1em; }
+.block_site_main_menu .section_add_menus noscript div { display: inline;}
return $this->configdefinitions;
}
+ /**
+ * Returns the definitions mapped into the given store name.
+ *
+ * @param string $storename
+ * @return array Associative array of definitions, id=>definition
+ */
+ public static function get_definitions_by_store($storename) {
+ $definitions = array();
+
+ $config = cache_config::instance();
+ $stores = $config->get_all_stores();
+ if (!array_key_exists($storename, $stores)) {
+ // The store does not exist.
+ return false;
+ }
+
+ $defmappings = $config->get_definition_mappings();
+ // Create an associative array for the definition mappings.
+ $thedefmappings = array();
+ foreach ($defmappings as $defmapping) {
+ $thedefmappings[$defmapping['definition']] = $defmapping;
+ }
+
+ // Search for matches in default mappings.
+ $defs = $config->get_definitions();
+ foreach($config->get_mode_mappings() as $modemapping) {
+ if ($modemapping['store'] !== $storename) {
+ continue;
+ }
+ foreach($defs as $id => $definition) {
+ if ($definition['mode'] !== $modemapping['mode']) {
+ continue;
+ }
+ // Exclude custom definitions mapping: they will be managed few lines below.
+ if (array_key_exists($id, $thedefmappings)) {
+ continue;
+ }
+ $definitions[$id] = $definition;
+ }
+ }
+
+ // Search for matches in the custom definitions mapping
+ foreach ($defmappings as $defmapping) {
+ if ($defmapping['store'] !== $storename) {
+ continue;
+ }
+ $definition = $config->get_definition_by_id($defmapping['definition']);
+ if ($definition) {
+ $definitions[$defmapping['definition']] = $definition;
+ }
+ }
+
+ return $definitions;
+ }
+
/**
* Returns all of the stores that are suitable for the given mode and requirements.
*
throw new coding_exception('You must provide a mode when creating a cache definition');
}
if (!array_key_exists('component', $definition)) {
- throw new coding_exception('You must provide a mode when creating a cache definition');
+ throw new coding_exception('You must provide a component when creating a cache definition');
}
if (!array_key_exists('area', $definition)) {
- throw new coding_exception('You must provide a mode when creating a cache definition');
+ throw new coding_exception('You must provide an area when creating a cache definition');
}
$mode = (int)$definition['mode'];
$component = (string)$definition['component'];
* @param int $mode One of cache_store::MODE_*
* @param string $component The component this definition relates to.
* @param string $area The area this definition relates to.
- * @param string $overrideclass The class to use as the loader.
- * @param bool $persistent If this cache should be persistent.
+ * @param array $options An array of options, available options are:
+ * - simplekeys : Set to true if the keys you will use are a-zA-Z0-9_
+ * - simpledata : Set to true if the type of the data you are going to store is scalar, or an array of scalar vars
+ * - overrideclass : The class to use as the loader.
+ * - persistent : If set to true the cache will persist construction requests.
* @return cache_application|cache_session|cache_request
*/
- public static function load_adhoc($mode, $component, $area, $overrideclass = null, $persistent = false) {
+ public static function load_adhoc($mode, $component, $area, array $options = array()) {
$id = 'adhoc/'.$component.'_'.$area;
$definition = array(
'mode' => $mode,
'component' => $component,
'area' => $area,
- 'persistent' => $persistent
);
- if (!is_null($overrideclass)) {
- $definition['overrideclass'] = $overrideclass;
+ if (!empty($options['simplekeys'])) {
+ $definition['simplekeys'] = $options['simplekeys'];
+ }
+ if (!empty($options['simpledata'])) {
+ $definition['simpledata'] = $options['simpledata'];
+ }
+ if (!empty($options['persistent'])) {
+ $definition['persistent'] = $options['persistent'];
+ }
+ if (!empty($options['overrideclass'])) {
+ $definition['overrideclass'] = $options['overrideclass'];
}
return self::load($id, $definition, null);
}
*/
public function get_data_source() {
if (!$this->has_data_source()) {
- throw new coding_exception('This cache does not use a datasource.');
+ throw new coding_exception('This cache does not use a data source.');
}
return forward_static_call(array($this->datasource, 'get_instance_for_cache'), $this);
}
* Returns true if this store supports multiple identifiers.
* @return bool
*/
- public function supports_multiple_indentifiers() {
+ public function supports_multiple_identifiers() {
return false;
}
public static function initialise_test_instance(cache_definition $definition) {
$cache = new cachestore_dummy('Dummy store test');
$cache->initialise($definition);
- return $cache;;
+ return $cache;
}
/**
public function my_name() {
return $this->name;
}
-}
\ No newline at end of file
+}
* @param string $component
* @param string $area
* @param array $identifiers
- * @param bool $persistent
+ * @param array $options An array of options, available options are:
+ * - simplekeys : Set to true if the keys you will use are a-zA-Z0-9_
+ * - simpledata : Set to true if the type of the data you are going to store is scalar, or an array of scalar vars
+ * - persistent : If set to true the cache will persist construction requests.
* @return cache_application|cache_session|cache_request
*/
- public function create_cache_from_params($mode, $component, $area, array $identifiers = array(), $persistent = false) {
+ public function create_cache_from_params($mode, $component, $area, array $identifiers = array(), array $options = array()) {
$key = "{$mode}_{$component}_{$area}";
if (array_key_exists($key, $this->cachesfromparams)) {
return $this->cachesfromparams[$key];
}
// Get the class. Note this is a late static binding so we need to use get_called_class.
- $definition = cache_definition::load_adhoc($mode, $component, $area, null, $persistent);
+ $definition = cache_definition::load_adhoc($mode, $component, $area, $options);
$definition->set_identifiers($identifiers);
$cache = $this->create_cache($definition, $identifiers);
if ($definition->should_be_persistent()) {
/**
* Purges the cache for a specific definition.
*
+ * @todo MDL-36660: Change the signature: $aggregate must be added.
+ *
* @param string $component
* @param string $area
* @param array $identifiers
public static function purge_by_definition($component, $area, array $identifiers = array()) {
// Create the cache.
$cache = cache::make($component, $area, $identifiers);
+ // Initialise, in case of a store.
+ if ($cache instanceof cache_store) {
+ $factory = cache_factory::instance();
+ // TODO MDL-36660: Providing $aggregate is required for purging purposes: $definition->get_id()
+ $definition = $factory->create_definition($component, $area, null);
+ $definition->set_identifiers($identifiers);
+ $cache->initialise($definition);
+ }
// Purge baby, purge.
$cache->purge();
return true;
foreach ($instance->get_definitions() as $name => $definitionarr) {
$definition = cache_definition::load($name, $definitionarr);
if ($definition->invalidates_on_event($event)) {
- // Purge the cache.
+ // Create the cache.
$cache = $factory->create_cache($definition);
+ // Initialise, in case of a store.
+ if ($cache instanceof cache_store) {
+ $cache->initialise($definition);
+ }
+ // Purge the cache.
$cache->purge();
// We need to flag the event in the "Event invalidation" cache if it hasn't already happened.
*/
public static function purge_all() {
$config = cache_config::instance();
- $stores = $config->get_all_stores();
- $definition = cache_definition::load_adhoc(cache_store::MODE_REQUEST, 'core', 'cache_purge');
- foreach ($stores as $store) {
- $class = $store['class'];
- $instance = new $class($store['name'], $store['configuration']);
- if (!$instance->is_ready()) {
- continue;
- }
- $instance->initialise($definition);
- $instance->purge();
+
+ foreach ($config->get_all_stores() as $store) {
+ self::purge_store($store['name']);
}
}
*/
public static function purge_store($storename) {
$config = cache_config::instance();
- foreach ($config->get_all_stores() as $store) {
- if ($store['name'] !== $storename) {
- continue;
- }
- $class = $store['class'];
+
+ $stores = $config->get_all_stores();
+ if (!array_key_exists($storename, $stores)) {
+ // The store does not exist.
+ return false;
+ }
+
+ $store = $stores[$storename];
+ $class = $store['class'];
+
+ // Found the store: is it ready?
+ $instance = new $class($store['name'], $store['configuration']);
+ if (!$instance->is_ready()) {
+ unset($instance);
+ return false;
+ }
+
+ foreach ($config->get_definitions_by_store($storename) as $id => $definition) {
+ $definition = cache_definition::load($id, $definition);
$instance = new $class($store['name'], $store['configuration']);
- if (!$instance->is_ready()) {
- continue;
- }
- $definition = cache_definition::load_adhoc(cache_store::MODE_REQUEST, 'core', 'cache_purge');
$instance->initialise($definition);
$instance->purge();
- return true;
+ unset($instance);
}
- return false;
+
+ return true;
}
/**
*/
public static function hash_key($key, cache_definition $definition) {
if ($definition->uses_simple_keys()) {
+ if (debugging() && preg_match('#[^a-zA-Z0-9_]#', $key)) {
+ throw new coding_exception('Cache definition '.$definition->get_id().' requires simple keys. Invalid key provided.', $key);
+ }
// We put the key first so that we can be sure the start of the key changes.
return (string)$key . '-' . $definition->generate_single_key_prefix();
}
*
* Please note that this happens automatically if the cache definition requires locking.
* it is still made a public method so that adhoc caches can use it if they choose.
- * However this doesn't guarantee consistent access. It will become the reponsiblity of the calling code to ensure locks
- * are acquired, checked, and released.
+ * However this doesn't guarantee consistent access. It will become the responsibility of the calling code to ensure
+ * locks are acquired, checked, and released.
*
* @param string|int $key
* @return bool True if the lock could be acquired, false otherwise.
*
* Please note that this happens automatically if the cache definition requires locking.
* it is still made a public method so that adhoc caches can use it if they choose.
- * However this doesn't guarantee consistent access. It will become the reponsiblity of the calling code to ensure locks
- * are acquired, checked, and released.
+ * However this doesn't guarantee consistent access. It will become the responsibility of the calling code to ensure
+ * locks are acquired, checked, and released.
*
* @param string|int $key
* @return bool True if this code has the lock, false if there is a lock but this code doesn't have it,
*
* Please note that this happens automatically if the cache definition requires locking.
* it is still made a public method so that adhoc caches can use it if they choose.
- * However this doesn't guarantee consistent access. It will become the reponsiblity of the calling code to ensure locks
- * are acquired, checked, and released.
+ * However this doesn't guarantee consistent access. It will become the responsibility of the calling code to ensure
+ * locks are acquired, checked, and released.
*
* @param string|int $key
* @return bool True if the lock has been released, false if there was a problem releasing the lock.
*
* @return bool
*/
- public function supports_multiple_indentifiers();
+ public function supports_multiple_identifiers();
/**
* Returns true if this cache store instance promotes data guarantee.
* Cache loaders
*
* This file is part of Moodle's cache API, affectionately called MUC.
- * It contains the components that are requried in order to use caching.
+ * It contains the components that are required in order to use caching.
*
* @package core
* @category cache
* @param string $component The component this cache relates to.
* @param string $area The area this cache relates to.
* @param array $identifiers Any additional identifiers that should be provided to the definition.
- * @param bool $persistent If set to true the cache will persist construction requests.
+ * @param array $options An array of options, available options are:
+ * - simplekeys : Set to true if the keys you will use are a-zA-Z0-9_
+ * - simpledata : Set to true if the type of the data you are going to store is scalar, or an array of scalar vars
+ * - persistent : If set to true the cache will persist construction requests.
* @return cache_application|cache_session|cache_store
*/
- public static function make_from_params($mode, $component, $area, array $identifiers = array(), $persistent = false) {
+ public static function make_from_params($mode, $component, $area, array $identifiers = array(), array $options = array()) {
$factory = cache_factory::instance();
- return $factory->create_cache_from_params($mode, $component, $area, $identifiers, $persistent);
+ return $factory->create_cache_from_params($mode, $component, $area, $identifiers, $options);
}
/**
// 1. Parse the key.
$parsedkey = $this->parse_key($key);
// 2. Get it from the persist cache if we can (only when persist is enabled and it has already been requested/set).
- $result = $this->get_from_persist_cache($parsedkey);
+ $result = false;
+ if ($this->is_using_persist_cache()) {
+ $result = $this->get_from_persist_cache($parsedkey);
+ }
if ($result !== false) {
- if ($this->perfdebug) {
- cache_helper::record_cache_hit('** static persist **', $this->definition->get_id());
- }
if (!is_scalar($result)) {
// If data is an object it will be a reference.
// If data is an array if may contain references.
$result = $this->unref($result);
}
return $result;
- } else if ($this->perfdebug) {
- cache_helper::record_cache_miss('** static persist **', $this->definition->get_id());
}
// 3. Get it from the store. Obviously wasn't in the persist cache.
$result = $this->store->get($parsedkey);
*/
protected function parse_key($key) {
// First up if the store supports multiple keys we'll go with that.
- if ($this->store->supports_multiple_indentifiers()) {
+ if ($this->store->supports_multiple_identifiers()) {
$result = $this->definition->generate_multi_key_parts();
$result['key'] = $key;
return $result;
$key = $key['key'];
}
if (!$this->persist || !array_key_exists($key, $this->persistcache)) {
- return false;
- }
- $data = $this->persistcache[$key];
- if (!$this->has_a_ttl() || !$data instanceof cache_ttl_wrapper) {
- if ($data instanceof cache_cached_object) {
- $data = $data->restore_object();
+ $result = false;
+ } else {
+ $data = $this->persistcache[$key];
+ if (!$this->has_a_ttl() || !$data instanceof cache_ttl_wrapper) {
+ if ($data instanceof cache_cached_object) {
+ $data = $data->restore_object();
+ }
+ $result = $data;
+ } else if ($data->has_expired()) {
+ $this->delete_from_persist_cache($key);
+ $result = false;
+ } else {
+ if ($data instanceof cache_cached_object) {
+ $data = $data->restore_object();
+ }
+ $result = $data->data;
}
- return $data;
}
- if ($data->has_expired()) {
- $this->delete_from_persist_cache($key);
- return false;
+ if ($result) {
+ if ($this->perfdebug) {
+ cache_helper::record_cache_hit('** static persist **', $this->definition->get_id());
+ }
+ return $result;
} else {
- if ($data instanceof cache_cached_object) {
- $data = $data->restore_object();
+ if ($this->perfdebug) {
+ cache_helper::record_cache_miss('** static persist **', $this->definition->get_id());
}
- return $data->data;
+ return false;
}
}
($store->get_supported_modes($return) & cache_store::MODE_REQUEST) == cache_store::MODE_REQUEST,
),
'supports' => array(
- 'multipleidentifiers' => $store->supports_multiple_indentifiers(),
+ 'multipleidentifiers' => $store->supports_multiple_identifiers(),
'dataguarantee' => $store->supports_data_guarantee(),
'nativettl' => $store->supports_native_ttl(),
'nativelocking' => ($store instanceof cache_is_lockable),
*
* @return bool
*/
- public function supports_multiple_indentifiers() {
+ public function supports_multiple_identifiers() {
return false;
}
* Pre-scan the cache to see which keys are present.
*/
protected function prescan_keys() {
- foreach (glob($this->glob_keys_pattern(), GLOB_MARK | GLOB_NOSORT) as $filename) {
- $this->keys[basename($filename)] = filemtime($filename);
+ $files = glob($this->glob_keys_pattern(), GLOB_MARK | GLOB_NOSORT);
+ if (is_array($files)) {
+ foreach ($files as $filename) {
+ $this->keys[basename($filename)] = filemtime($filename);
+ }
}
}
public function delete($key) {
$filename = $key.'.cache';
$file = $this->file_path_for_key($key);
- $result = @unlink($file);
- unset($this->keys[$filename]);
- return $result;
+
+ if (@unlink($file)) {
+ unset($this->keys[$filename]);
+ return true;
+ }
+
+ return false;
}
/**
* @return boolean True on success. False otherwise.
*/
public function purge() {
- foreach (glob($this->glob_keys_pattern(), GLOB_MARK | GLOB_NOSORT) as $filename) {
- @unlink($filename);
+ $files = glob($this->glob_keys_pattern(), GLOB_MARK | GLOB_NOSORT);
+ if (is_array($files)) {
+ foreach ($files as $filename) {
+ @unlink($filename);
+ }
}
$this->keys = array();
return true;
public function my_name() {
return $this->name;
}
-}
\ No newline at end of file
+}
*
* @return bool
*/
- public function supports_multiple_indentifiers() {
+ public function supports_multiple_identifiers() {
return false;
}
*
* @return bool
*/
- public function supports_multiple_indentifiers() {
+ public function supports_multiple_identifiers() {
return false;
}
* Returns true if this store is making use of multiple identifiers.
* @return bool
*/
- public function supports_multiple_indentifiers() {
+ public function supports_multiple_identifiers() {
return $this->extendedmode;
}
* @return bool
*/
public function supports_native_ttl() {
- return false;;
+ return false;
}
/**
public function my_name() {
return $this->name;
}
-}
\ No newline at end of file
+}
*
* @return bool
*/
- public function supports_multiple_indentifiers() {
+ public function supports_multiple_identifiers() {
return false;
}
*
* @return bool
*/
- public function supports_multiple_indentifiers() {
+ public function supports_multiple_identifiers() {
return false;
}
// Do something here perhaps.
$cache = new cachestore_static('Static store');
$cache->initialise($definition);
- return $cache;;
+ return $cache;
}
/**
self::$staticstore[$id] = array();
}
}
-}
\ No newline at end of file
+}
$requesttable = clone($applicationtable);
-$application = cache_definition::load_adhoc(cache_store::MODE_APPLICATION, 'cache', 'applicationtest', null, false);
-$session = cache_definition::load_adhoc(cache_store::MODE_SESSION, 'cache', 'sessiontest', null, false);
-$request = cache_definition::load_adhoc(cache_store::MODE_REQUEST, 'cache', 'requesttest', null, false);
+$application = cache_definition::load_adhoc(cache_store::MODE_APPLICATION, 'cache', 'applicationtest');
+$session = cache_definition::load_adhoc(cache_store::MODE_SESSION, 'cache', 'sessiontest');
+$request = cache_definition::load_adhoc(cache_store::MODE_REQUEST, 'cache', 'requesttest');
$strinvalidplugin = new lang_string('invalidplugin', 'cache');
$strunsupportedmode = new lang_string('unsupportedmode', 'cache');
$this->assertInstanceOf('coding_exception', $e);
}
}
-}
\ No newline at end of file
+
+ /**
+ * Test the hash_key functionality.
+ */
+ public function test_hash_key() {
+ global $CFG;
+
+ $currentdebugging = $CFG->debug;
+
+ $CFG->debug = E_ALL;
+
+ // First with simplekeys
+ $instance = cache_config_phpunittest::instance(true);
+ $instance->phpunit_add_definition('phpunit/hashtest', array(
+ 'mode' => cache_store::MODE_APPLICATION,
+ 'component' => 'phpunit',
+ 'area' => 'hashtest',
+ 'simplekeys' => true
+ ));
+ $factory = cache_factory::instance();
+ $definition = $factory->create_definition('phpunit', 'hashtest');
+
+ $result = cache_helper::hash_key('test', $definition);
+ $this->assertEquals('test-'.$definition->generate_single_key_prefix(), $result);
+
+ try {
+ cache_helper::hash_key('test/test', $definition);
+ $this->fail('Invalid key was allowed, you should see this.');
+ } catch (coding_exception $e) {
+ $this->assertEquals('test/test', $e->debuginfo);
+ }
+
+ // Second without simple keys
+ $instance->phpunit_add_definition('phpunit/hashtest2', array(
+ 'mode' => cache_store::MODE_APPLICATION,
+ 'component' => 'phpunit',
+ 'area' => 'hashtest2',
+ 'simplekeys' => false
+ ));
+ $definition = $factory->create_definition('phpunit', 'hashtest2');
+
+ $result = cache_helper::hash_key('test', $definition);
+ $this->assertEquals(sha1($definition->generate_single_key_prefix().'-test'), $result);
+
+ $result = cache_helper::hash_key('test/test', $definition);
+ $this->assertEquals(sha1($definition->generate_single_key_prefix().'-test/test'), $result);
+
+ $CFG->debug = $currentdebugging;
+ }
+}
return false;
}
+ // You cannot edit calendar subscription events presently.
+ if (!empty($event->subscriptionid)) {
+ return false;
+ }
+
$sitecontext = context_system::instance();
// if user has manageentries at site level, return true
if (has_capability('moodle/calendar:manageentries', $sitecontext)) {
if ($usingeditor) {
switch ($this->properties->eventtype) {
case 'user':
- $this->editorcontext = $this->properties->context;
$this->properties->courseid = 0;
+ $this->properties->course = 0;
$this->properties->groupid = 0;
$this->properties->userid = $USER->id;
break;
case 'site':
- $this->editorcontext = $this->properties->context;
$this->properties->courseid = SITEID;
+ $this->properties->course = SITEID;
$this->properties->groupid = 0;
$this->properties->userid = $USER->id;
break;
case 'course':
- $this->editorcontext = $this->properties->context;
$this->properties->groupid = 0;
$this->properties->userid = $USER->id;
break;
case 'group':
- $this->editorcontext = $this->properties->context;
$this->properties->userid = $USER->id;
break;
default:
break;
}
+ // If we are actually using the editor, we recalculate the context because some default values
+ // were set when calculate_context() was called from the constructor.
+ if ($usingeditor) {
+ $this->properties->context = $this->calculate_context($this->properties);
+ $this->editorcontext = $this->properties->context;
+ }
+
$editor = $this->properties->description;
$this->properties->format = $this->properties->description['format'];
$this->properties->description = $this->properties->description['text'];
$this->editoroptions,
$editor['text'],
$this->editoroptions['forcehttps']);
-
$DB->set_field('event', 'description', $this->properties->description, array('id'=>$this->properties->id));
}
$choices[0] = get_string('userevents', 'calendar');
}
if ($allowed->site) {
- $choices[SITEID] = get_string('globalevents', 'calendar');
+ $choices[SITEID] = get_string('siteevents', 'calendar');
}
if (!empty($allowed->courses)) {
$choices[$courseid] = get_string('courseevents', 'calendar');
require_once($CFG->libdir.'/filelib.php');
$curl = new curl();
+ $curl->setopt(array('CURLOPT_FOLLOWLOCATION' => 1, 'CURLOPT_MAXREDIRS' => 5));
$calendar = $curl->get($url);
- if (!$calendar) {
+ // Http code validation should actually be the job of curl class.
+ if (!$calendar || $curl->info['http_code'] != 200 || !empty($curl->errorno)) {
throw new moodle_exception('errorinvalidicalurl', 'calendar');
}
// URL.
$mform->addElement('text', 'url', get_string('importfromurl', 'calendar'), array('maxsize' => '255', 'size' => '50'));
- $mform->setType('url', PARAM_URL);
-
- // Import file
- $mform->addElement('filepicker', 'importfile', get_string('importfromfile', 'calendar'));
-
- $mform->disabledIf('url', 'importfrom', 'eq', CALENDAR_IMPORT_FROM_FILE);
- $mform->disabledIf('importfile', 'importfrom', 'eq', CALENDAR_IMPORT_FROM_URL);
+ // Cannot set as PARAM_URL since we need to allow webcal:// protocol.
+ $mform->setType('url', PARAM_RAW);
// Poll interval
$choices = calendar_get_pollinterval_choices();
$mform->addHelpButton('pollinterval', 'pollinterval', 'calendar');
$mform->setType('pollinterval', PARAM_INT);
+ // Import file
+ $mform->addElement('filepicker', 'importfile', get_string('importfromfile', 'calendar'));
+
+ // Disable appropriate elements depending on import from value.
+ $mform->disabledIf('pollinterval', 'importfrom', 'eq', CALENDAR_IMPORT_FROM_FILE);
+ $mform->disabledIf('url', 'importfrom', 'eq', CALENDAR_IMPORT_FROM_FILE);
+ $mform->disabledIf('importfile', 'importfrom', 'eq', CALENDAR_IMPORT_FROM_URL);
+
// Eventtype: 0 = user, 1 = global, anything else = course ID.
list($choices, $groups) = calendar_get_eventtype_choices($courseid);
$mform->addElement('select', 'eventtype', get_string('eventkind', 'calendar'), $choices);
*/
public function validation($data, $files) {
$errors = parent::validation($data, $files);
+
if (empty($data['url']) && empty($data['importfile'])) {
if (!empty($data['importfrom']) && $data['importfrom'] == CALENDAR_IMPORT_FROM_FILE) {
$errors['importfile'] = get_string('errorrequiredurlorfile', 'calendar');
} else {
$errors['url'] = get_string('errorrequiredurlorfile', 'calendar');
}
+ } else if (!empty($data['url'])) {
+ if (clean_param($data['url'], PARAM_URL) !== $data['url']) {
+ $errors['url'] = get_string('invalidurl', 'error');
+ }
}
return $errors;
}
+
+ public function definition_after_data() {
+ $mform =& $this->_form;
+
+ $mform->applyFilter('url', 'calendar_addsubscription_form::strip_webcal');
+ $mform->applyFilter('url', 'trim');
+ }
+
+ /**
+ * Replace webcal:// urls with http:// as
+ * curl does not understand this protocol
+ *
+ * @param string @url url to examine
+ * @return string url with webcal:// replaced
+ */
+ public static function strip_webcal($url) {
+ if (strpos($url, 'webcal://') === 0) {
+ $url = str_replace('webcal://', 'http://', $url);
+ }
+ return $url;
+ }
}
if ($k == $subscription->pollinterval) {
$attributes['selected'] = 'selected';
}
+ $attributes['value'] = $k;
$html .= html_writer::tag('option', $v, $attributes);
}
$html .= html_writer::end_tag('select');
echo $OUTPUT->notification(get_string('removeuserwarning', 'core_cohort'));
// Get the user_selector we will need.
-$potentialuserselector = new cohort_candidate_selector('addselect', array('cohortid'=>$cohort->id));
-$existinguserselector = new cohort_existing_selector('removeselect', array('cohortid'=>$cohort->id));
+$potentialuserselector = new cohort_candidate_selector('addselect', array('cohortid'=>$cohort->id, 'accesscontext'=>$context));
+$existinguserselector = new cohort_existing_selector('removeselect', array('cohortid'=>$cohort->id, 'accesscontext'=>$context));
// Process incoming user assignments to the cohort
// role assignment link
if (has_capability('moodle/course:enrolreview', $coursecontext)) {
$url = new moodle_url('/enrol/users.php', array('id' => $acourse->id));
- echo $OUTPUT->action_icon($url, new pix_icon('i/users', get_string('enrolledusers', 'enrol')));
+ echo $OUTPUT->action_icon($url, new pix_icon('t/enrolusers', get_string('enrolledusers', 'enrol')));
}
if (can_delete_course($acourse->id)) {
preview.li.appendChild(preview.div);
preview.icon.src = M.util.image_url('t/addfile');
+ preview.icon.className = 'icon';
preview.div.appendChild(preview.icon);
preview.div.appendChild(document.createTextNode(' '));
$strmoveup = get_string('moveup');
$controls[] = html_writer::link($url,
- html_writer::empty_tag('img', array('src' => $this->output->pix_url('t/up'),
+ html_writer::empty_tag('img', array('src' => $this->output->pix_url('i/up'),
'class' => 'icon up', 'alt' => $strmoveup)),
array('title' => $strmoveup, 'class' => 'moveup'));
}
$strmovedown = get_string('movedown');
$controls[] = html_writer::link($url,
- html_writer::empty_tag('img', array('src' => $this->output->pix_url('t/down'),
+ html_writer::empty_tag('img', array('src' => $this->output->pix_url('i/down'),
'class' => 'icon down', 'alt' => $strmovedown)),
array('title' => $strmovedown, 'class' => 'movedown'));
}
.course-content ul.topics {margin:0;}
.course-content ul.topics li.section {list-style: none;margin:5px 0 0 0;padding:0;}
.course-content ul.topics li.section .content {margin:0 40px;}
-.course-content ul.topics li.section .left {width:40px;float:left;text-align:center;}
+.course-content ul.topics li.section .left {width:40px;float:left;text-align:center;padding-top: 4px;}
.course-content ul.topics li.section .right {width:40px;float:right;text-align:center;padding-top: 4px;}
-.jumpmenu {text-align:center;}
\ No newline at end of file
+.course-content ul.topics li.section .left .section-handle img.icon { padding:0; vertical-align: baseline; }
+.jumpmenu {text-align:center;}
.course-content ul.weeks {margin:0;}
.course-content ul.weeks li.section {list-style: none;margin:5px 0 0 0;padding:0;}
.course-content ul.weeks li.section .content {margin:0 40px;}
-.course-content ul.weeks li.section .left {width:40px;float:left;text-align:center;}
+.course-content ul.weeks li.section .left {width:40px;float:left;text-align:center;padding-top: 4px;}
.course-content ul.weeks li.section .right {width:40px;float:right;text-align:center;padding-top: 4px;}
+.course-content ul.weeks li.section .left .section-handle img.icon { padding:0; vertical-align: baseline; }
.jumpmenu {text-align:center;}
\ No newline at end of file
$displaylist[0] = get_string('top');
make_categories_list($displaylist, $parentlist);
-echo '<table class="generalbox editcourse boxaligncenter"><tr class="header">';
+echo '<table class="generaltable editcourse boxaligncenter"><tr class="header">';
echo '<th class="header" scope="col">'.$strcategories.'</th>';
echo '<th class="header" scope="col">'.$strcourses.'</th>';
echo '<th class="header" scope="col">'.$stredit.'</th>';
if (has_capability('moodle/cohort:manage', $category->context) or has_capability('moodle/cohort:view', $category->context)) {
echo '<a title="'.$str->cohorts.'" href="'.$CFG->wwwroot.'/cohort/index.php?contextid='.$category->context->id.'"><img'.
- ' src="'.$OUTPUT->pix_url('i/cohort') . '" class="iconsmall" alt="'.$str->cohorts.'" /></a> ';
+ ' src="'.$OUTPUT->pix_url('t/cohort') . '" class="iconsmall" alt="'.$str->cohorts.'" /></a> ';
}
if ($up) {
function course_set_marker($courseid, $marker) {
global $DB;
$DB->set_field("course", "marker", $marker, array('id' => $courseid));
+ format_base::reset_course_cache($courseid);
}
/**
if (!empty($section->sequence)) {
$modules = explode(",", $section->sequence);
foreach ($modules as $moduleid) {
- set_coursemodule_visible($moduleid, $visibility, true);
+ if ($cm = $DB->get_record('course_modules', array('id' => $moduleid), 'visible, visibleold')) {
+ if ($visibility) {
+ // As we unhide the section, we use the previously saved visibility stored in visibleold.
+ set_coursemodule_visible($moduleid, $cm->visibleold);
+ } else {
+ // We hide the section, so we hide the module but we store the original state in visibleold.
+ set_coursemodule_visible($moduleid, 0);
+ $DB->set_field('course_modules', 'visibleold', $cm->visible, array('id' => $moduleid));
+ }
+ }
}
}
rebuild_course_cache($courseid, true);
$modcontext = context_module::instance($mod->id);
$canviewhidden = has_capability('moodle/course:viewhiddenactivities', $modcontext);
$accessiblebutdim = false;
+ $conditionalhidden = false;
if ($canviewhidden) {
$accessiblebutdim = !$mod->visible;
if (!empty($CFG->enableavailability)) {
- $accessiblebutdim = $accessiblebutdim ||
- $mod->availablefrom > time() ||
+ $conditionalhidden = $mod->availablefrom > time() ||
($mod->availableuntil && $mod->availableuntil < time()) ||
count($mod->conditionsgrade) > 0 ||
count($mod->conditionscompletion) > 0;
}
+ $accessiblebutdim = $conditionalhidden || $accessiblebutdim;
}
$liclasses = array();
$linkclasses = '';
$textclasses = '';
if ($accessiblebutdim) {
- $linkclasses .= ' dimmed conditionalhidden';
- $textclasses .= ' dimmed_text conditionalhidden';
+ $linkclasses .= ' dimmed';
+ $textclasses .= ' dimmed_text';
+ if ($conditionalhidden) {
+ $linkclasses .= ' conditionalhidden';
+ $textclasses .= ' conditionalhidden';
+ }
$accesstext = '<span class="accesshide">'.
get_string('hiddenfromstudents').': </span>';
} else {
$accesstext = '';
}
if ($linkclasses) {
- $linkcss = 'class="' . trim($linkclasses) . '" ';
+ $linkcss = 'class="activityinstance ' . trim($linkclasses) . '" ';
} else {
- $linkcss = '';
+ $linkcss = 'class="activityinstance"';
}
if ($textclasses) {
$textcss = 'class="' . trim($textclasses) . '" ';
// Display link itself
echo '<a ' . $linkcss . $mod->extra . $onclick .
' href="' . $url . '"><img src="' . $mod->get_icon_url() .
- '" class="activityicon" alt="' . $mod->modfullname . '" /> ' .
+ '" class="iconlarge activityicon" alt="' . $mod->modfullname . '" />' .
$accesstext . '<span class="instancename">' .
$instancename . $altname . '</span></a>';
} else {
$mod->groupmode = false;
}
- echo ' ';
echo make_editing_buttons($mod, $absolute, true, $mod->indent, $sectionreturn);
echo $mod->get_after_edit_icons();
}
}
/**
-* $prevstateoverrides = true will set the visibility of the course module
-* to what is defined in visibleold. This enables us to remember the current
-* visibility when making a whole section hidden, so that when we toggle
-* that section back to visible, we are able to return the visibility of
-* the course module back to what it was originally.
-*/
-function set_coursemodule_visible($id, $visible, $prevstateoverrides=false) {
+ * Set the visibility of a module and inherent properties.
+ *
+ * From 2.4 the parameter $prevstateoverrides has been removed, the logic it triggered
+ * has been moved to {@link set_section_visible()} which was the only place from which
+ * the parameter was used.
+ *
+ * @param int $id of the module
+ * @param int $visible state of the module
+ * @return bool false when the module was not found, true otherwise
+ */
+function set_coursemodule_visible($id, $visible) {
global $DB, $CFG;
require_once($CFG->libdir.'/gradelib.php');
+ // Trigger developer's attention when using the previously removed argument.
+ if (func_num_args() > 2) {
+ debugging('Wrong number of arguments passed to set_coursemodule_visible(), $prevstateoverrides
+ has been removed.', DEBUG_DEVELOPER);
+ }
+
if (!$cm = $DB->get_record('course_modules', array('id'=>$id))) {
return false;
}
}
}
- if ($prevstateoverrides) {
- if ($visible == '0') {
- // Remember the current visible state so we can toggle this back.
- $DB->set_field('course_modules', 'visibleold', $cm->visible, array('id'=>$id));
- } else {
- // Get the previous saved visible states.
- $DB->set_field('course_modules', 'visible', $cm->visibleold, array('id'=>$id));
- }
- } else {
- $DB->set_field("course_modules", "visible", $visible, array("id"=>$id));
- }
+ // Updating visible and visibleold to keep them in sync. Only changing a section visibility will
+ // affect visibleold to allow for an original visibility restore. See set_section_visible().
+ $cminfo = new stdClass();
+ $cminfo->id = $id;
+ $cminfo->visible = $visible;
+ $cminfo->visibleold = $visible;
+ $DB->update_record('course_modules', $cminfo);
+
rebuild_course_cache($cm->course, true);
return true;
}
if (has_capability('moodle/role:assign', $modcontext)){
$actions[] = new action_link(
new moodle_url('/'.$CFG->admin.'/roles/assign.php', array('contextid' => $modcontext->id)),
- new pix_icon('i/roles', $str->assign, 'moodle', array('class' => 'iconsmall', 'title' => '')),
+ new pix_icon('t/assignroles', $str->assign, 'moodle', array('class' => 'iconsmall', 'title' => '')),
null,
array('class' => 'editing_assign', 'title' => $str->assign)
);
// Put all options into one tag 'alloptions' to allow us to handle scrolling
$formcontent .= html_writer::start_tag('div', array('class' => 'alloptions'));
- // Activities
- $activities = array_filter($modules,
- create_function('$mod', 'return ($mod->archetype !== MOD_CLASS_RESOURCE);'));
+ // Activities
+ $activities = array_filter($modules, function($mod) {
+ return ($mod->archetype !== MOD_ARCHETYPE_RESOURCE && $mod->archetype !== MOD_ARCHETYPE_SYSTEM);
+ });
if (count($activities)) {
$formcontent .= $this->course_modchooser_title('activities');
$formcontent .= $this->course_modchooser_module_types($activities);
}
// Resources
- $resources = array_filter($modules,
- create_function('$mod', 'return ($mod->archetype === MOD_CLASS_RESOURCE);'));
+ $resources = array_filter($modules, function($mod) {
+ return ($mod->archetype === MOD_ARCHETYPE_RESOURCE);
+ });
if (count($resources)) {
$formcontent .= $this->course_modchooser_title('resources');
$formcontent .= $this->course_modchooser_module_types($resources);
// checks whether user can do role assignment
if (has_capability('moodle/course:enrolreview', $coursecontext)) {
echo'<a title="'.get_string('enrolledusers', 'enrol').'" href="'.$CFG->wwwroot.'/enrol/users.php?id='.$course->id.'">';
- echo '<img src="'.$OUTPUT->pix_url('i/users') . '" class="iconsmall" alt="'.get_string('enrolledusers', 'enrol').'" /></a> ' . "\n";
+ echo '<img src="'.$OUTPUT->pix_url('i/enrolusers') . '" class="iconsmall" alt="'.get_string('enrolledusers', 'enrol').'" /></a> ' . "\n";
}
// checks whether user can delete course
$this->assertTrue(empty($modinfo->sections[0]));
$this->assertFalse(empty($modinfo->sections[3]));
}
+
+ public function test_module_visibility() {
+ $this->setAdminUser();
+ $this->resetAfterTest(true);
+
+ // Create course and modules.
+ $course = $this->getDataGenerator()->create_course(array('numsections' => 5));
+ $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id));
+ $assign = $this->getDataGenerator()->create_module('assign', array('duedate' => time(), 'course' => $course->id));
+ $modules = compact('forum', 'assign');
+
+ // Hiding the modules.
+ foreach ($modules as $mod) {
+ set_coursemodule_visible($mod->cmid, 0);
+ $this->check_module_visibility($mod, 0, 0);
+ }
+
+ // Showing the modules.
+ foreach ($modules as $mod) {
+ set_coursemodule_visible($mod->cmid, 1);
+ $this->check_module_visibility($mod, 1, 1);
+ }
+ }
+
+ public function test_section_visibility() {
+ $this->setAdminUser();
+ $this->resetAfterTest(true);
+
+ // Create course.
+ $course = $this->getDataGenerator()->create_course(array('numsections' => 3), array('createsections' => true));
+
+ // Testing an empty section.
+ $sectionnumber = 1;
+ set_section_visible($course->id, $sectionnumber, 0);
+ $section_info = get_fast_modinfo($course->id)->get_section_info($sectionnumber);
+ $this->assertEquals($section_info->visible, 0);
+ set_section_visible($course->id, $sectionnumber, 1);
+ $section_info = get_fast_modinfo($course->id)->get_section_info($sectionnumber);
+ $this->assertEquals($section_info->visible, 1);
+
+ // Testing a section with visible modules.
+ $sectionnumber = 2;
+ $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id),
+ array('section' => $sectionnumber));
+ $assign = $this->getDataGenerator()->create_module('assign', array('duedate' => time(),
+ 'course' => $course->id), array('section' => $sectionnumber));
+ $modules = compact('forum', 'assign');
+ set_section_visible($course->id, $sectionnumber, 0);
+ $section_info = get_fast_modinfo($course->id)->get_section_info($sectionnumber);
+ $this->assertEquals($section_info->visible, 0);
+ foreach ($modules as $mod) {
+ $this->check_module_visibility($mod, 0, 1);
+ }
+ set_section_visible($course->id, $sectionnumber, 1);
+ $section_info = get_fast_modinfo($course->id)->get_section_info($sectionnumber);
+ $this->assertEquals($section_info->visible, 1);
+ foreach ($modules as $mod) {
+ $this->check_module_visibility($mod, 1, 1);
+ }
+
+ // Testing a section with hidden modules, which should stay hidden.
+ $sectionnumber = 3;
+ $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id),
+ array('section' => $sectionnumber));
+ $assign = $this->getDataGenerator()->create_module('assign', array('duedate' => time(),
+ 'course' => $course->id), array('section' => $sectionnumber));
+ $modules = compact('forum', 'assign');
+ foreach ($modules as $mod) {
+ set_coursemodule_visible($mod->cmid, 0);
+ $this->check_module_visibility($mod, 0, 0);
+ }
+ set_section_visible($course->id, $sectionnumber, 0);
+ $section_info = get_fast_modinfo($course->id)->get_section_info($sectionnumber);
+ $this->assertEquals($section_info->visible, 0);
+ foreach ($modules as $mod) {
+ $this->check_module_visibility($mod, 0, 0);
+ }
+ set_section_visible($course->id, $sectionnumber, 1);
+ $section_info = get_fast_modinfo($course->id)->get_section_info($sectionnumber);
+ $this->assertEquals($section_info->visible, 1);
+ foreach ($modules as $mod) {
+ $this->check_module_visibility($mod, 0, 0);
+ }
+ }
+
+ /**
+ * Helper function to assert that a module has correctly been made visible, or hidden.
+ *
+ * @param stdClass $mod module information
+ * @param int $visibility the current state of the module
+ * @param int $visibleold the current state of the visibleold property
+ * @return void
+ */
+ public function check_module_visibility($mod, $visibility, $visibleold) {
+ global $DB;
+ $cm = get_fast_modinfo($mod->course)->get_cm($mod->cmid);
+ $this->assertEquals($visibility, $cm->visible);
+ $this->assertEquals($visibleold, $cm->visibleold);
+
+ // Check the module grade items.
+ $grade_items = grade_item::fetch_all(array('itemtype' => 'mod', 'itemmodule' => $cm->modname,
+ 'iteminstance' => $cm->instance, 'courseid' => $cm->course));
+ if ($grade_items) {
+ foreach ($grade_items as $grade_item) {
+ if ($visibility) {
+ $this->assertFalse($grade_item->is_hidden(), "$cm->modname grade_item not visible");
+ } else {
+ $this->assertTrue($grade_item->is_hidden(), "$cm->modname grade_item not hidden");
+ }
+ }
+ }
+
+ // Check the events visibility.
+ if ($events = $DB->get_records('event', array('instance' => $cm->instance, 'modulename' => $cm->modname))) {
+ foreach ($events as $event) {
+ $calevent = new calendar_event($event);
+ $this->assertEquals($visibility, $calevent->visible, "$cm->modname calendar_event visibility");
+ }
+ }
+ }
+
}
if ((movedown || moveup) && cssleft) {
cssleft.setStyle('cursor', 'move');
- cssleft.appendChild(Y.Node.create('<br />'));
- cssleft.appendChild(this.get_drag_handle(title, CSS.SECTIONHANDLE));
+ cssleft.appendChild(this.get_drag_handle(title, CSS.SECTIONHANDLE, 'icon', true));
if (moveup) {
moveup.remove();
});
del.dd.plug(Y.Plugin.DDProxy, {
// Don't move the node at the end of the drag
- moveOnEnd: false
+ moveOnEnd: false,
+ cloneNode: true
});
del.dd.plug(Y.Plugin.DDConstrained, {
// Keep it inside the .course-content
edit_resource_title : function(e) {
// Get the element we're working on
var element = e.target.ancestor(CSS.ACTIVITYLI);
+ var elementdiv = element.one('div');
var instancename = element.one(CSS.INSTANCENAME);
var currenttitle = instancename.get('firstChild');
var oldtitle = currenttitle.get('data');
})
.addClass('titleeditor');
var editform = Y.Node.create('<form />')
- .setStyle('padding', '0')
- .setStyle('display', 'inline')
+ .addClass('activityinstance')
.setAttribute('action', '#');
-
var editinstructions = Y.Node.create('<span />')
.addClass('editinstructions')
.set('innerHTML', M.util.get_string('edittitleinstructions', 'moodle'));
+ var activityicon = element.one('img.activityicon').cloneNode();
// Clear the existing content and put the editor in
currenttitle.set('data', '');
+ editform.appendChild(activityicon);
editform.appendChild(editor);
anchor.replace(editform);
- element.appendChild(editinstructions);
+ elementdiv.appendChild(editinstructions);
e.preventDefault();
// Focus and select the editor text
if(! @unlink($filename)) {
$eventdata = new stdClass();
$eventdata->modulename = 'moodle';
- $eventdata->component = 'course';
+ $eventdata->component = 'enrol_flatfile';
$eventdata->name = 'flatfile_enrolment';
$eventdata->userfrom = get_admin();
$eventdata->userto = get_admin();
// Send mail to admin
$eventdata = new stdClass();
$eventdata->modulename = 'moodle';
- $eventdata->component = 'course';
+ $eventdata->component = 'enrol_flatfile';
$eventdata->name = 'flatfile_enrolment';
$eventdata->userfrom = get_admin();
$eventdata->userto = get_admin();
$eventdata = new stdClass();
$eventdata->modulename = 'moodle';
- $eventdata->component = 'course';
+ $eventdata->component = 'enrol_flatfile';
$eventdata->name = 'flatfile_enrolment';
$eventdata->userfrom = $teacher;
$eventdata->userto = $user;
$eventdata = new stdClass();
$eventdata->modulename = 'moodle';
- $eventdata->component = 'course';
+ $eventdata->component = 'enrol_flatfile';
$eventdata->name = 'flatfile_enrolment';
$eventdata->userfrom = $user;
$eventdata->userto = $teacher;
if (has_capability('enrol/manual:manage', $context)) {
$managelink = new moodle_url("/enrol/manual/manage.php", array('enrolid'=>$instance->id));
- $icons[] = $OUTPUT->action_icon($managelink, new pix_icon('i/users', get_string('enrolusers', 'enrol_manual'), 'core', array('class'=>'iconsmall')));
+ $icons[] = $OUTPUT->action_icon($managelink, new pix_icon('t/enrolusers', get_string('enrolusers', 'enrol_manual'), 'core', array('class'=>'iconsmall')));
}
if (has_capability('enrol/manual:config', $context)) {
$editlink = new moodle_url("/enrol/manual/edit.php", array('courseid'=>$instance->courseid));
$this->page = optional_param(self::PAGEVAR, 0, PARAM_INT);
$this->perpage = optional_param(self::PERPAGEVAR, self::DEFAULTPERPAGE, PARAM_INT);
- $this->sort = optional_param(self::SORTVAR, self::DEFAULTSORT, PARAM_ALPHA);
+ $this->sort = optional_param(self::SORTVAR, self::DEFAULTSORT, PARAM_ALPHANUM);
$this->sortdirection = optional_param(self::SORTDIRECTIONVAR, self::DEFAULTSORTDIRECTION, PARAM_ALPHA);
$this->attributes = array('class'=>'userenrolment');
} else {
$link = html_writer::link(new moodle_url($url, array(self::SORTVAR=>$n)), $fields[$name][$n]);
if ($this->sort == $n) {
- $link .= ' '.html_writer::link(new moodle_url($url, array(self::SORTVAR=>$n, self::SORTDIRECTIONVAR=>$this->get_field_sort_direction($n))), $this->get_direction_icon($output, $n));
+ $link .= html_writer::link(new moodle_url($url, array(self::SORTVAR=>$n, self::SORTDIRECTIONVAR=>$this->get_field_sort_direction($n))), $this->get_direction_icon($output, $n));
}
$bits[] = html_writer::tag('span', $link, array('class'=>'subheading_'.$n));
} else {
$newlabel = html_writer::link(new moodle_url($url, array(self::SORTVAR=>$name)), $fields[$name]);
if ($this->sort == $name) {
- $newlabel .= ' '.html_writer::link(new moodle_url($url, array(self::SORTVAR=>$name, self::SORTDIRECTIONVAR=>$this->get_field_sort_direction($name))), $this->get_direction_icon($output, $name));
+ $newlabel .= html_writer::link(new moodle_url($url, array(self::SORTVAR=>$name, self::SORTDIRECTIONVAR=>$this->get_field_sort_direction($name))), $this->get_direction_icon($output, $name));
}
}
}
$direction = $this->sortdirection;
}
if ($direction === 'ASC') {
- return html_writer::empty_tag('img', array('alt'=>'', 'src'=>$output->pix_url('t/down')));
+ return html_writer::empty_tag('img', array('alt' => '', 'class' => 'iconsort',
+ 'src' => $output->pix_url('t/sort_asc')));
} else {
- return html_writer::empty_tag('img', array('alt'=>'', 'src'=>$output->pix_url('t/up')));
+ return html_writer::empty_tag('img', array('alt' => '', 'class' => 'iconsort',
+ 'src' => $output->pix_url('t/sort_desc')));
}
}
// default return url
$gpr = new grade_plugin_return();
-$returnurl = $gpr->get_return_url($CFG->wwwroot.'/grade/report.php?id='.$course->id);
+$returnurl = $gpr->get_return_url($CFG->wwwroot.'/grade/report/index.php?id='.$course->id);
if (!$grade_item = grade_item::fetch(array('id'=>$id, 'courseid'=>$course->id))) {
print_error('invaliditemid');
// default return url
$gpr = new grade_plugin_return();
-$returnurl = $gpr->get_return_url($CFG->wwwroot.'/grade/report.php?id='.$course->id);
+$returnurl = $gpr->get_return_url($CFG->wwwroot.'/grade/report/index.php?id='.$course->id);
// security checks!
if (!empty($id)) {
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
-require_once '../../../config.php';
-require_once $CFG->libdir.'/gradelib.php';
-require_once $CFG->dirroot.'/grade/lib.php';
-require_once '../grade_import_form.php';
-require_once '../lib.php';
+require_once("../../../config.php");
+require_once($CFG->libdir.'/gradelib.php');
+require_once($CFG->dirroot.'/grade/lib.php');
+require_once($CFG->dirroot. '/grade/import/grade_import_form.php');
+require_once($CFG->dirroot.'/grade/import/lib.php');
+require_once($CFG->libdir . '/csvlib.class.php');
$id = required_param('id', PARAM_INT); // course id
$separator = optional_param('separator', '', PARAM_ALPHA);
$verbosescales = optional_param('verbosescales', 1, PARAM_BOOL);
+$iid = optional_param('iid', null, PARAM_INT);
+$importcode = optional_param('importcode', '', PARAM_FILE);
$url = new moodle_url('/grade/import/csv/index.php', array('id'=>$id));
if ($separator !== '') {
}
$PAGE->set_url($url);
-define('GRADE_CSV_LINE_LENGTH', 4096);
-
if (!$course = $DB->get_record('course', array('id'=>$id))) {
print_error('nocourseid');
}
$separatemode = (groups_get_course_groupmode($COURSE) == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context));
$currentgroup = groups_get_course_group($course);
-// sort out delimiter
-if (isset($CFG->CSV_DELIMITER)) {
- $csv_delimiter = $CFG->CSV_DELIMITER;
-
- if (isset($CFG->CSV_ENCODE)) {
- $csv_encode = '/\&\#' . $CFG->CSV_ENCODE . '/';
- }
-} else if ($separator == 'tab') {
- $csv_delimiter = "\t";
- $csv_encode = "";
-} else {
- $csv_delimiter = ",";
- $csv_encode = '/\&\#44/';
-}
-
print_grade_page_head($course->id, 'import', 'csv', get_string('importcsv', 'grades'));
-// set up import form
-$mform = new grade_import_form(null, array('includeseparator'=>!isset($CFG->CSV_DELIMITER), 'verbosescales'=>true));
-
-// set up grade import mapping form
-$header = '';
+// Set up the grade import mapping form.
$gradeitems = array();
if ($id) {
if ($grade_items = grade_item::fetch_all(array('courseid'=>$id))) {
foreach ($grade_items as $grade_item) {
- // skip course type and category type
+ // Skip course type and category type.
if ($grade_item->itemtype == 'course' || $grade_item->itemtype == 'category') {
continue;
}
}
}
-if ($importcode = optional_param('importcode', '', PARAM_FILE)) {
- $filename = $CFG->tempdir.'/gradeimport/cvs/'.$USER->id.'/'.$importcode;
- $fp = fopen($filename, "r");
- $headers = fgets($fp, GRADE_CSV_LINE_LENGTH);
- $header = explode($csv_delimiter, $headers);
- fclose($fp);
-}
+// Set up the import form.
+$mform = new grade_import_form(null, array('includeseparator'=>true, 'verbosescales'=>true));
-$mform2 = new grade_import_mapping_form(null, array('gradeitems'=>$gradeitems, 'header'=>$header));
+// If the csv file hasn't been imported yet then look for a form submission or
+// show the initial submission form.
+if (!$iid) {
+ // If the import form has been submitted.
+ if ($formdata = $mform->get_data()) {
-// if import form is submitted
-if ($formdata = $mform->get_data()) {
+ // Large files are likely to take their time and memory. Let PHP know
+ // that we'll take longer, and that the process should be recycled soon
+ // to free up memory.
+ @set_time_limit(0);
+ raise_memory_limit(MEMORY_EXTRA);
- // Large files are likely to take their time and memory. Let PHP know
- // that we'll take longer, and that the process should be recycled soon
- // to free up memory.
- @set_time_limit(0);
- raise_memory_limit(MEMORY_EXTRA);
+ // Use current (non-conflicting) time stamp.
+ $importcode = get_new_importcode();
- // use current (non-conflicting) time stamp
- $importcode = get_new_importcode();
- $filename = make_temp_directory('gradeimport/cvs/'.$USER->id);
- $filename = $filename.'/'.$importcode;
-
- $text = $mform->get_file_content('userfile');
- // trim utf-8 bom
- /// normalize line endings and do the encoding conversion
- $text = textlib::convert($text, $formdata->encoding);
- $text = textlib::trim_utf8_bom($text);
- // Fix mac/dos newlines
- $text = preg_replace('!\r\n?!',"\n",$text);
- $fp = fopen($filename, "w");
- fwrite($fp,$text);
- fclose($fp);
-
- if (!$fp = fopen($filename, "r")) {
- print_error('cannotopenfile');
- }
+ $text = $mform->get_file_content('userfile');
+ $iid = csv_import_reader::get_new_iid('grade');
+ $csvimport = new csv_import_reader($iid, 'grade');
- // --- get header (field names) ---
- $header = explode($csv_delimiter, fgets($fp, GRADE_CSV_LINE_LENGTH));
+ $csvimport->load_csv_content($text, $formdata->encoding, $separator);
- // print some preview
- $numlines = 0; // 0 preview lines displayed
+ // --- get header (field names) ---
+ $header = $csvimport->get_columns();
- echo $OUTPUT->heading(get_string('importpreview', 'grades'));
- echo '<table>';
- echo '<tr>';
- foreach ($header as $h) {
- $h = clean_param($h, PARAM_RAW);
- echo '<th>'.$h.'</th>';
- }
- echo '</tr>';
- while (!feof ($fp) && $numlines <= $formdata->previewrows) {
- $lines = explode($csv_delimiter, fgets($fp, GRADE_CSV_LINE_LENGTH));
- echo '<tr>';
- foreach ($lines as $line) {
- echo '<td>'.$line.'</td>';
- }
- $numlines ++;
- echo '</tr>';
- }
- echo '</table>';
+ // Print a preview of the data.
+ $numlines = 0; // 0 lines previewed so far.
- // display the mapping form with header info processed
- $mform2 = new grade_import_mapping_form(null, array('gradeitems'=>$gradeitems, 'header'=>$header));
- $mform2->set_data(array('importcode'=>$importcode, 'id'=>$id, 'verbosescales'=>$verbosescales, 'separator'=>$separator));
- $mform2->display();
+ echo $OUTPUT->heading(get_string('importpreview', 'grades'));
-//} else if (($formdata = data_submitted()) && !empty($formdata->map)) {
+ foreach ($header as $i => $h) {
+ $h = trim($h); // Remove whitespace.
+ $h = clean_param($h, PARAM_RAW); // Clean the header.
+ $header[$i] = $h;
+ }
-// else if grade import mapping form is submitted
-} else if ($formdata = $mform2->get_data()) {
+ $table = new html_table();
+ $table->head = $header;
+ $csvimport->init();
+ $previewdata = array();
+ while ($numlines <= $formdata->previewrows) {
+ $lines = $csvimport->next();
+ if ($lines) {
+ $previewdata[] = $lines;
+ }
+ $numlines ++;
+ }
+ $table->data = $previewdata;
+ echo html_writer::table($table);
+ } else {
+ // Display the standard upload file form.
+ groups_print_course_menu($course, 'index.php?id='.$id);
+ echo html_writer::start_tag('div', array('class' => 'clearer'));
+ echo html_writer::end_tag('div');
+
+ $mform->display();
+ echo $OUTPUT->footer();
+ die();
+ }
+}
- $importcode = clean_param($formdata->importcode, PARAM_FILE);
- $filename = $CFG->tempdir.'/gradeimport/cvs/'.$USER->id.'/'.$importcode;
+// Data has already been submitted so we can use the $iid to retrieve it.
+$csvimport = new csv_import_reader($iid, 'grade');
+$header = $csvimport->get_columns();
- if (!file_exists($filename)) {
- print_error('cannotuploadfile');
- }
+// we create a form to handle mapping data from the file to the database.
+$mform2 = new grade_import_mapping_form(null, array('gradeitems'=>$gradeitems, 'header'=>$header));
+$mform2->set_data(array('iid' => $iid, 'id' => $id, 'importcode'=>$importcode, 'verbosescales' => $verbosescales));
- if ($fp = fopen($filename, "r")) {
- // --- get header (field names) ---
- $header = explode($csv_delimiter, clean_param(fgets($fp,GRADE_CSV_LINE_LENGTH), PARAM_RAW));
+// Here, if we have data, we process the fields and enter the information into the database.
+if ($formdata = $mform2->get_data()) {
- foreach ($header as $i => $h) {
- $h = trim($h); $header[$i] = $h; // remove whitespace
- }
- } else {
- print_error('cannotopenfile');
+ foreach ($header as $i => $h) {
+ $h = trim($h); // Remove whitespace.
+ $h = clean_param($h, PARAM_RAW); // Clean the header.
+ $header[$i] = $h;
}
$map = array();
$maperrors[$j] = true;
} else {
// collision
- fclose($fp);
- unlink($filename); // needs to be uploaded again, sorry
print_error('cannotmapfield', '', '', $j);
}
}
@set_time_limit(0);
raise_memory_limit(MEMORY_EXTRA);
- // we only operate if file is readable
- if ($fp = fopen($filename, "r")) {
-
- // read the first line makes sure this doesn't get read again
- $header = explode($csv_delimiter, fgets($fp, GRADE_CSV_LINE_LENGTH));
+ $csvimport->init();
- $newgradeitems = array(); // temporary array to keep track of what new headers are processed
- $status = true;
+ $newgradeitems = array(); // temporary array to keep track of what new headers are processed
+ $status = true;
- while (!feof ($fp)) {
- // add something
- $line = explode($csv_delimiter, fgets($fp, GRADE_CSV_LINE_LENGTH));
+ while ($line = $csvimport->next()) {
+ if(count($line) <= 1){
+ // there is no data on this line, move on
+ continue;
+ }
- if(count($line) <= 1){
- // there is no data on this line, move on
- continue;
+ // array to hold all grades to be inserted
+ $newgrades = array();
+ // array to hold all feedback
+ $newfeedbacks = array();
+ // each line is a student record
+ foreach ($line as $key => $value) {
+
+ $value = clean_param($value, PARAM_RAW);
+ $value = trim($value);
+
+ /*
+ * the options are
+ * 1) userid, useridnumber, usermail, username - used to identify user row
+ * 2) new - new grade item
+ * 3) id - id of the old grade item to map onto
+ * 3) feedback_id - feedback for grade item id
+ */
+
+ $t = explode("_", $map[$key]);
+ $t0 = $t[0];
+ if (isset($t[1])) {
+ $t1 = (int)$t[1];
+ } else {
+ $t1 = '';
}
- // array to hold all grades to be inserted
- $newgrades = array();
- // array to hold all feedback
- $newfeedbacks = array();
- // each line is a student record
- foreach ($line as $key => $value) {
- //decode encoded commas
- $value = clean_param($value, PARAM_RAW);
- $value = trim($value);
- if (!empty($csv_encode)) {
- $value = preg_replace($csv_encode, $csv_delimiter, $value);
- }
+ switch ($t0) {
+ case 'userid': //
+ if (!$user = $DB->get_record('user', array('id' => $value))) {
+ // user not found, abort whole import
+ import_cleanup($importcode);
+ echo $OUTPUT->notification("user mapping error, could not find user with id \"$value\"");
+ $status = false;
+ break 3;
+ }
+ $studentid = $value;
+ break;
+ case 'useridnumber':
+ if (!$user = $DB->get_record('user', array('idnumber' => $value))) {
+ // user not found, abort whole import
+ import_cleanup($importcode);
+ echo $OUTPUT->notification("user mapping error, could not find user with idnumber \"$value\"");
+ $status = false;
+ break 3;
+ }
+ $studentid = $user->id;
+ break;
+ case 'useremail':
+ if (!$user = $DB->get_record('user', array('email' => $value))) {
+ import_cleanup($importcode);
+ echo $OUTPUT->notification("user mapping error, could not find user with email address \"$value\"");
+ $status = false;
+ break 3;
+ }
+ $studentid = $user->id;
+ break;
+ case 'username':
+ if (!$user = $DB->get_record('user', array('username' => $value))) {
+ import_cleanup($importcode);
+ echo $OUTPUT->notification("user mapping error, could not find user with username \"$value\"");
+ $status = false;
+ break 3;
+ }
+ $studentid = $user->id;
+ break;
+ case 'new':
+ // first check if header is already in temp database
- /*
- * the options are
- * 1) userid, useridnumber, usermail, username - used to identify user row
- * 2) new - new grade item
- * 3) id - id of the old grade item to map onto
- * 3) feedback_id - feedback for grade item id
- */
-
- $t = explode("_", $map[$key]);
- $t0 = $t[0];
- if (isset($t[1])) {
- $t1 = (int)$t[1];
- } else {
- $t1 = '';
- }
+ if (empty($newgradeitems[$key])) {
- switch ($t0) {
- case 'userid': //
- if (!$user = $DB->get_record('user', array('id' => $value))) {
- // user not found, abort whole import
- import_cleanup($importcode);
- echo $OUTPUT->notification("user mapping error, could not find user with id \"$value\"");
+ $newgradeitem = new stdClass();
+ $newgradeitem->itemname = $header[$key];
+ $newgradeitem->importcode = $importcode;
+ $newgradeitem->importer = $USER->id;
+
+ // insert into new grade item buffer
+ $newgradeitems[$key] = $DB->insert_record('grade_import_newitem', $newgradeitem);
+ }
+ $newgrade = new stdClass();
+ $newgrade->newgradeitem = $newgradeitems[$key];
+
+ // if the user has a grade for this grade item
+ if (trim($value) != '-') {
+ // instead of omitting the grade we could insert one with finalgrade set to 0
+ // we do not have access to grade item min grade
+ $newgrade->finalgrade = $value;
+ $newgrades[] = $newgrade;
+ }
+ break;
+ case 'feedback':
+ if ($t1) {
+ // case of an id, only maps id of a grade_item
+ // this was idnumber
+ if (!$gradeitem = new grade_item(array('id'=>$t1, 'courseid'=>$course->id))) {
+ // supplied bad mapping, should not be possible since user
+ // had to pick mapping
$status = false;
- break 3;
- }
- $studentid = $value;
- break;
- case 'useridnumber':
- if (!$user = $DB->get_record('user', array('idnumber' => $value))) {
- // user not found, abort whole import
import_cleanup($importcode);
- echo $OUTPUT->notification("user mapping error, could not find user with idnumber \"$value\"");
- $status = false;
+ echo $OUTPUT->notification(get_string('importfailed', 'grades'));
break 3;
}
- $studentid = $user->id;
- break;
- case 'useremail':
- if (!$user = $DB->get_record('user', array('email' => $value))) {
- import_cleanup($importcode);
- echo $OUTPUT->notification("user mapping error, could not find user with email address \"$value\"");
+
+ // t1 is the id of the grade item
+ $feedback = new stdClass();
+ $feedback->itemid = $t1;
+ $feedback->feedback = $value;
+ $newfeedbacks[] = $feedback;
+ }
+ break;
+ default:
+ // existing grade items
+ if (!empty($map[$key])) {
+ // case of an id, only maps id of a grade_item
+ // this was idnumber
+ if (!$gradeitem = new grade_item(array('id'=>$map[$key], 'courseid'=>$course->id))) {
+ // supplied bad mapping, should not be possible since user
+ // had to pick mapping
$status = false;
+ import_cleanup($importcode);
+ echo $OUTPUT->notification(get_string('importfailed', 'grades'));
break 3;
}
- $studentid = $user->id;
- break;
- case 'username':
- if (!$user = $DB->get_record('user', array('username' => $value))) {
- import_cleanup($importcode);
- echo $OUTPUT->notification("user mapping error, could not find user with username \"$value\"");
+
+ // check if grade item is locked if so, abort
+ if ($gradeitem->is_locked()) {
$status = false;
+ import_cleanup($importcode);
+ echo $OUTPUT->notification(get_string('gradeitemlocked', 'grades'));
break 3;
}
- $studentid = $user->id;
- break;
- case 'new':
- // first check if header is already in temp database
-
- if (empty($newgradeitems[$key])) {
- $newgradeitem = new stdClass();
- $newgradeitem->itemname = $header[$key];
- $newgradeitem->importcode = $importcode;
- $newgradeitem->importer = $USER->id;
-
- // insert into new grade item buffer
- $newgradeitems[$key] = $DB->insert_record('grade_import_newitem', $newgradeitem);
- }
$newgrade = new stdClass();
- $newgrade->newgradeitem = $newgradeitems[$key];
-
- // if the user has a grade for this grade item
- if (trim($value) != '-') {
- // instead of omitting the grade we could insert one with finalgrade set to 0
- // we do not have access to grade item min grade
- $newgrade->finalgrade = $value;
- $newgrades[] = $newgrade;
- }
- break;
- case 'feedback':
- if ($t1) {
- // case of an id, only maps id of a grade_item
- // this was idnumber
- if (!$gradeitem = new grade_item(array('id'=>$t1, 'courseid'=>$course->id))) {
- // supplied bad mapping, should not be possible since user
- // had to pick mapping
- $status = false;
- import_cleanup($importcode);
- echo $OUTPUT->notification(get_string('importfailed', 'grades'));
- break 3;
- }
-
- // t1 is the id of the grade item
- $feedback = new stdClass();
- $feedback->itemid = $t1;
- $feedback->feedback = $value;
- $newfeedbacks[] = $feedback;
- }
- break;
- default:
- // existing grade items
- if (!empty($map[$key])) {
- // case of an id, only maps id of a grade_item
- // this was idnumber
- if (!$gradeitem = new grade_item(array('id'=>$map[$key], 'courseid'=>$course->id))) {
- // supplied bad mapping, should not be possible since user
- // had to pick mapping
- $status = false;
- import_cleanup($importcode);
- echo $OUTPUT->notification(get_string('importfailed', 'grades'));
- break 3;
- }
-
- // check if grade item is locked if so, abort
- if ($gradeitem->is_locked()) {
- $status = false;
- import_cleanup($importcode);
- echo $OUTPUT->notification(get_string('gradeitemlocked', 'grades'));
- break 3;
- }
-
- $newgrade = new stdClass();
- $newgrade->itemid = $gradeitem->id;
- if ($gradeitem->gradetype == GRADE_TYPE_SCALE and $verbosescales) {
- if ($value === '' or $value == '-') {
- $value = null; // no grade
- } else {
- $scale = $gradeitem->load_scale();
- $scales = explode(',', $scale->scale);
- $scales = array_map('trim', $scales); //hack - trim whitespace around scale options
- array_unshift($scales, '-'); // scales start at key 1
- $key = array_search($value, $scales);
- if ($key === false) {
- echo "<br/>t0 is $t0";
- echo "<br/>grade is $value";
- $status = false;
- import_cleanup($importcode);
- echo $OUTPUT->notification(get_string('badgrade', 'grades'));
- break 3;
- }
- $value = $key;
- }
- $newgrade->finalgrade = $value;
+ $newgrade->itemid = $gradeitem->id;
+ if ($gradeitem->gradetype == GRADE_TYPE_SCALE and $verbosescales) {
+ if ($value === '' or $value == '-') {
+ $value = null; // no grade
} else {
- if ($value === '' or $value == '-') {
- $value = null; // no grade
-
- } else if (!is_numeric($value)) {
- // non numeric grade value supplied, possibly mapped wrong column
+ $scale = $gradeitem->load_scale();
+ $scales = explode(',', $scale->scale);
+ $scales = array_map('trim', $scales); //hack - trim whitespace around scale options
+ array_unshift($scales, '-'); // scales start at key 1
+ $key = array_search($value, $scales);
+ if ($key === false) {
echo "<br/>t0 is $t0";
echo "<br/>grade is $value";
$status = false;
echo $OUTPUT->notification(get_string('badgrade', 'grades'));
break 3;
}
- $newgrade->finalgrade = $value;
+ $value = $key;
}
- $newgrades[] = $newgrade;
- } // otherwise, we ignore this column altogether
- // because user has chosen to ignore them (e.g. institution, address etc)
- break;
- }
- }
-
- // no user mapping supplied at all, or user mapping failed
- if (empty($studentid) || !is_numeric($studentid)) {
- // user not found, abort whole import
- $status = false;
- import_cleanup($importcode);
- echo $OUTPUT->notification('user mapping error, could not find user!');
+ $newgrade->finalgrade = $value;
+ } else {
+ if ($value === '' or $value == '-') {
+ $value = null; // no grade
+
+ } else if (!is_numeric($value)) {
+ // non numeric grade value supplied, possibly mapped wrong column
+ echo "<br/>t0 is $t0";
+ echo "<br/>grade is $value";
+ $status = false;
+ import_cleanup($importcode);
+ echo $OUTPUT->notification(get_string('badgrade', 'grades'));
+ break 3;
+ }
+ $newgrade->finalgrade = $value;
+ }
+ $newgrades[] = $newgrade;
+ } // otherwise, we ignore this column altogether
+ // because user has chosen to ignore them (e.g. institution, address etc)
break;
}
+ }
- if ($separatemode and !groups_is_member($currentgroup, $studentid)) {
- // not allowed to import into this group, abort
- $status = false;
- import_cleanup($importcode);
- echo $OUTPUT->notification('user not member of current group, can not update!');
- break;
- }
+ // no user mapping supplied at all, or user mapping failed
+ if (empty($studentid) || !is_numeric($studentid)) {
+ // user not found, abort whole import
+ $status = false;
+ import_cleanup($importcode);
+ echo $OUTPUT->notification('user mapping error, could not find user!');
+ break;
+ }
- // insert results of this students into buffer
- if ($status and !empty($newgrades)) {
+ if ($separatemode and !groups_is_member($currentgroup, $studentid)) {
+ // not allowed to import into this group, abort
+ $status = false;
+ import_cleanup($importcode);
+ echo $OUTPUT->notification('user not member of current group, can not update!');
+ break;
+ }
- foreach ($newgrades as $newgrade) {
+ // insert results of this students into buffer
+ if ($status and !empty($newgrades)) {
- // check if grade_grade is locked and if so, abort
- if (!empty($newgrade->itemid) and $grade_grade = new grade_grade(array('itemid'=>$newgrade->itemid, 'userid'=>$studentid))) {
- if ($grade_grade->is_locked()) {
- // individual grade locked
- $status = false;
- import_cleanup($importcode);
- echo $OUTPUT->notification(get_string('gradelocked', 'grades'));
- break 2;
- }
- }
+ foreach ($newgrades as $newgrade) {
- $newgrade->importcode = $importcode;
- $newgrade->userid = $studentid;
- $newgrade->importer = $USER->id;
- $DB->insert_record('grade_import_values', $newgrade);
- }
- }
-
- // updating/inserting all comments here
- if ($status and !empty($newfeedbacks)) {
- foreach ($newfeedbacks as $newfeedback) {
- $sql = "SELECT *
- FROM {grade_import_values}
- WHERE importcode=? AND userid=? AND itemid=? AND importer=?";
- if ($feedback = $DB->get_record_sql($sql, array($importcode, $studentid, $newfeedback->itemid, $USER->id))) {
- $newfeedback->id = $feedback->id;
- $DB->update_record('grade_import_values', $newfeedback);
-
- } else {
- // the grade item for this is not updated
- $newfeedback->importcode = $importcode;
- $newfeedback->userid = $studentid;
- $newfeedback->importer = $USER->id;
- $DB->insert_record('grade_import_values', $newfeedback);
+ // check if grade_grade is locked and if so, abort
+ if (!empty($newgrade->itemid) and $grade_grade = new grade_grade(array('itemid'=>$newgrade->itemid, 'userid'=>$studentid))) {
+ if ($grade_grade->is_locked()) {
+ // individual grade locked
+ $status = false;
+ import_cleanup($importcode);
+ echo $OUTPUT->notification(get_string('gradelocked', 'grades'));
+ break 2;
}
}
+
+ $newgrade->importcode = $importcode;
+ $newgrade->userid = $studentid;
+ $newgrade->importer = $USER->id;
+ $DB->insert_record('grade_import_values', $newgrade);
}
}
- /// at this stage if things are all ok, we commit the changes from temp table
- if ($status) {
- grade_import_commit($course->id, $importcode);
+ // updating/inserting all comments here
+ if ($status and !empty($newfeedbacks)) {
+ foreach ($newfeedbacks as $newfeedback) {
+ $sql = "SELECT *
+ FROM {grade_import_values}
+ WHERE importcode=? AND userid=? AND itemid=? AND importer=?";
+ if ($feedback = $DB->get_record_sql($sql, array($importcode, $studentid, $newfeedback->itemid, $USER->id))) {
+ $newfeedback->id = $feedback->id;
+ $DB->update_record('grade_import_values', $newfeedback);
+
+ } else {
+ // the grade item for this is not updated
+ $newfeedback->importcode = $importcode;
+ $newfeedback->userid = $studentid;
+ $newfeedback->importer = $USER->id;
+ $DB->insert_record('grade_import_values', $newfeedback);
+ }
+ }
}
- // temporary file can go now
- fclose($fp);
- unlink($filename);
- } else {
- print_error('cannotreadfile');
}
+ /// at this stage if things are all ok, we commit the changes from temp table
+ if ($status) {
+ grade_import_commit($course->id, $importcode);
+ }
} else {
- groups_print_course_menu($course, 'index.php?id='.$id);
- echo '<div class="clearer"></div>';
-
- // display the standard upload file form
- $mform->display();
-}
-
-echo $OUTPUT->footer();
-
+ // If data hasn't been submitted then display the data mapping form.
+ $mform2->display();
+ echo $OUTPUT->footer();
+}
\ No newline at end of file
$mform->setType('map', PARAM_INT);
$mform->addElement('hidden', 'id');
$mform->setType('id', PARAM_INT);
+ $mform->addElement('hidden', 'iid');
+ $mform->setType('iid', PARAM_INT);
$mform->addElement('hidden', 'importcode');
$mform->setType('importcode', PARAM_FILE);
$mform->addElement('hidden', 'verbosescales', 1);
- $mform->setType('separator', PARAM_ALPHA);
- $mform->addElement('hidden', 'separator', 'comma');
$mform->setType('verbosescales', PARAM_INT);
$mform->addElement('hidden', 'groupid', groups_get_course_group($COURSE));
$mform->setType('groupid', PARAM_INT);
if ($imports = grade_helper::get_plugins_import($courseid)) {
$importnode = $gradenode->add($strings['import'], null, navigation_node::TYPE_CONTAINER);
foreach ($imports as $import) {
- $importnode->add($import->string, $import->link, navigation_node::TYPE_SETTING, null, $import->id, new pix_icon('i/restore', ''));
+ $importnode->add($import->string, $import->link, navigation_node::TYPE_SETTING, null, $import->id, new pix_icon('i/import', ''));
}
}
if ($exports = grade_helper::get_plugins_export($courseid)) {
$exportnode = $gradenode->add($strings['export'], null, navigation_node::TYPE_CONTAINER);
foreach ($exports as $export) {
- $exportnode->add($export->string, $export->link, navigation_node::TYPE_SETTING, null, $export->id, new pix_icon('i/backup', ''));
+ $exportnode->add($export->string, $export->link, navigation_node::TYPE_SETTING, null, $export->id, new pix_icon('i/export', ''));
}
}
// Perform actions
if (!empty($target) && !empty($action) && confirm_sesskey()) {
- grade_report_grader::process_action($target, $action);
+ grade_report_grader::do_process_action($target, $action);
}
$reportname = get_string('pluginname', 'gradereport_grader');
return $icon;
}
+ public function process_action($target, $action) {
+ return self::do_process_action($target, $action);
+ }
+
/**
* Processes a single action against a category, grade_item or grade.
* @param string $target eid ({type}{id}, e.g. c4 for category4)
* @param string $action Which action to take (edit, delete etc...)
* @return
*/
- public function process_action($target, $action) {
+ public static function do_process_action($target, $action) {
// TODO: this code should be in some grade_tree static method
$targettype = substr($target, 0, 1);
$targetid = substr($target, 1);
+++ /dev/null
-<?php
-
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * Automatically generated strings for Moodle installer
- *
- * Do not edit this file manually! It contains just a subset of strings
- * needed during the very first steps of installation. This file was
- * generated automatically by export-installer.php (which is part of AMOS
- * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
- * list of strings defined in /install/stringnames.txt.
- *
- * @package installer
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-defined('MOODLE_INTERNAL') || die();
-
-$string['thislanguage'] = 'English (fixes)';
defined('MOODLE_INTERNAL') || die();
$string['language'] = 'Jezik';
-$string['next'] = 'Nastavi';
+$string['next'] = 'Nastavite';
$string['previous'] = 'Prethodni';
$string['reload'] = 'Učitaj ponovno';
--- /dev/null
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['admindirname'] = 'Administratoriaus aplankas';
+$string['availablelangs'] = 'Galimų kalbų sąrašas';
+$string['chooselanguagehead'] = 'Pasirinkite kalbą';
+$string['chooselanguagesub'] = 'Prašome pasirinkti diegimo kalbą. Ši kalba taip pat taps numatytąją svetainės kalba. Tačiau vėliau, jei norėsite, Jūs galėsite ją pakeisti.';
+$string['clialreadyconfigured'] = 'config.php failas jau egzistuoja. Prašome naudotis admin/cli/install_database.php, jei Jūs norite įdiegti šią svetainę.';
+$string['clialreadyinstalled'] = 'config.php failas jau egzistuoja. Prašome naudoti admin/cli/upgrade.php jei Jūs norite išplėtoti šią svetainę.';
+$string['cliinstallheader'] = '"Moodle" {$a} komandinės eilutės įdiegimo programa';
+$string['databasehost'] = 'Duomenų bazės serveris';
+$string['databasename'] = 'Duomenų bazės pavadinimas';
+$string['databasetypehead'] = 'Pasirinkite duomenų bazės tvarkyklę';
+$string['dataroot'] = 'Duomenų aplankas';
+$string['datarootpermission'] = 'Duomenų aplanko leidimai';
+$string['dbprefix'] = 'Lentelių priešdėlis';
+$string['dirroot'] = '"Moodle" aplankas';
+$string['environmenthead'] = 'Tikrinama Jūsų aplinka...';
+$string['environmentsub2'] = 'Kiekviena "Moodle" laida turi kai kuriuos minimalius reikalavimus PHP versijai ir tam tikrą privalomų PHP plėtinių skaičių.
+Pilnas aplinkos patikrinimas yra padaromas prieš kiekvieną įdiegimą ar plėtotę. Prašome susisiekti su serverio administratoriumi, jeigu Jūs nežinote kaip įdiegti naują versiją ar įgalinti PHP plėtinius.';
+$string['errorsinenvironment'] = 'Aplinkos patikrinimas nesėkmingas!';
+$string['installation'] = 'Įdiegimas';
+$string['langdownloaderror'] = 'Deja "{$a}" kalba negali būti parsiųsta. Diegimo procesas bus tęsiamas anglų kalba.';
+$string['memorylimithelp'] = '<p>Šiuo metu Jūsų serverio PHP atminties limitas yra {$a}.</p>
+
+<p>Vėliau tai gali sukelti atminties trūkumo problemų "Moodle", ypač jei Jūs turite daug įgalintų modulių ir/ar daug vartotojų.</p>
+
+<p>Mes rekomenduojame suderinti PHP taip, kad jis turėtų kiek galima didesnį limitą, pvz.: 40MB.
+ Tam yra keletas būdų, kuriuos Jūs galite pabandyti:</p>
+<ol>
+<li>Jei Jūs galite, sukompiliuokite iš naujo PHP panaudodami <i>--enable-memory-limit</i> raktą.
+ Tai leis nustatyti atminties limitą pačiai "Moodle".</li>
+<li>Jei Jūs turite galimybę koreguoti Jūsų "php.ini" failą, tada pakeiskite <b>memory_limit</b> nuostatą į kažką artimo 40MB. Jei Jūs negalite koreguoti, tuomet gal galite paprašyti, kad Jūsų serverio administratorius tai padarytų už Jus.</li>
+<li>Kai kuriuose PHP serveriuose Jūs galite sukurti ".htaccess" failą "Moodle" aplanke ir įrašykite į jį šią eilutę:
+<blockquote><div>php_value memory_limit 40M</div></blockquote>
+<p>Tačiau kai kuriuose serveriuose tai neleis veikti <b>visiems</b> PHP puslapiams (Jūs matysite klaidas bandydami peržiūrėti tinklapius). Taigi Jums gali tekti pašalinti ".htaccess" failą.</p></li>
+</ol>';
+$string['paths'] = 'Keliai';
+$string['pathserrcreatedataroot'] = 'Diegiklis negali sukurti duomenų katalogo ({$a->dataroot}).';
+$string['pathshead'] = 'Patvirtinkite kelius';
+$string['pathsrodataroot'] = 'Dataroot katalogas yra neįrašomas';
+$string['pathsroparentdataroot'] = 'Virškatalogis ({$a->parent}) yra neįrašomas. Diegiklis negali sukurti duomenų katalogo ({$a->dataroot}).';
+$string['pathssubadmindir'] = 'Nedaugelis interneto paslaugų tiekėjų naudoja /admin kaip specialų URL skirtą prisijungti prie valdymo skydo ar panašiai. Deja tai kelia konfliktus su įprastais Moodle administravimo puslapių talpinimo keliais. Jūs galite tai pataisyti
+pervardydami admin katalogą Jūsų diegime bei įrašydami naują pavadinimą čia. Pavyzdžiui: <em>moodleadmin</em>. Tai pakeis visas admin nuorodas Moodle diegime.';
+$string['pathssubdataroot'] = 'Jums reikia vietos kur Moodle gali išsaugoti įkeliamus failus. Šis katalogas turi būti skaitomas IR ĮRAŠOMAS web serverio naudotojo
+(dažniausiai tai \'nobody\' arba \'apache\'), tačiau jis neturi būti pasiekiamas tiesiogiai per internetą. Diegiklis pabandys sukurti katalogą, jei tokio nėra.';
+$string['pathssubdirroot'] = 'Pilnas kelias iki Moodle diegimo vietos.';
+$string['pathssubwwwroot'] = 'Pilnas internetinis adresas, kuriuo bus pasiekiamas Moodle.
+Pasiekti Moodle naudojantis keliais adresais yra neįmanoma.
+Jei Jūsų svetainėje yra keletas viešų adresų, Jūs turite visuose adresuose nustatyti pastovų peradresavimą į šį adresą.
+Jei Jūsų svetainė yra pasiekiama ir iš Intraneto, ir iš Interneto - panaudokite viešą adresą čia ir nustatykite DNS taip, kad Intraneto naudotojai taip pat galėtų matyti viešą adresą.
+Jei adresas neteisingas - prašome pakeisti URL Jūsų naršyklėje ir pradėti diegimą su nauju adresu.';
+$string['pathsunsecuredataroot'] = 'Dataroot katalogo vieta yra nesaugi.';
+$string['pathswrongadmindir'] = 'Admin katalogas neegzistuoja';
+$string['phpextension'] = '{$a} PHP plėtinys';
+$string['phpversion'] = 'PHP versija';
+$string['phpversionhelp'] = '<p>Moodle reikalauja, kad būtų įdiegta bent 4.3.0 arba 5.1.0 PHP versija (5.0.x versija turi keletą žymių problemų).
+</p>
+<p>Jūs šiuo metu naudojate {$a} versiją</p>
+<p>Jūs turite išplėtoti turimą PHP versiją iki naujesnės arba persikelti pas kitą interneto paslaugų tiekėją, turintį naujesnę PHP versiją!<br/>
+(Turint 5.0.x versiją, Jūs turėtumėte pereiti prie žemesnės 4.4.x versijos)</p>';
+$string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
+$string['welcomep20'] = 'Jūs matote šį puslapį, nes sėkmingai įdiegėte ir užkrovėte <strong>{$a->packname} {$a->packversion}</strong> paketą savo kompiuteryje.
+Sveikiname!';
+$string['welcomep30'] = 'Šis <strong>{$a->installername}</strong> leidimas turi programas skirtas sukurti aplinką, kurioje <strong>Moodle</strong> veiks. Būtent:';
+$string['welcomep40'] = 'Šis paketas taip pat turi <strong>Moodle {$a->moodlerelease} ({$a->moodleversion})</strong>.';
+$string['welcomep50'] = 'Pakete esančių programų naudojimas yra reguliuojamas atitinkamų licencijų. Pilnas <strong>{$a->installername}</strong> paketas yra <a href="http://www.opensource.org/docs/definition_plain.html">atviro kodo</a> ir platinamas remiantis <a href="http://www.gnu.org/copyleft/gpl.html">GPL</a> licencija.';
+$string['welcomep60'] = 'Sekantys puslapiai ves Jus per keletą lengvų žingsnių, kurie padės sukonfigūruoti ir nustatyti <strong>Moodle</strong> Jūsų kompiuteryje. Jūs galite priimti nustatymus pagal nutylėjimą arba, pasirinktinai, pakeisti juos pagal savo poreikius.';
+$string['welcomep70'] = 'Spauskite "Toliau" mygtuką, norėdami tęsti <strong>Moodle</strong> nustatymą.';
+$string['wwwroot'] = 'Interneto adresas';
$string['cachejs'] = 'Cache Javascript';
$string['cachejs_help'] = 'Javascript caching and compression greatly improves page loading performance. it is strongly recommended for production sites. Developers will probably want to disable this feature.';
$string['cachetext'] = 'Text cache lifetime';
-$string['cachetype'] = 'Cache type';
$string['calendarexportsalt'] = 'Calendar export salt';
$string['calendarsettings'] = 'Calendar';
$string['calendar_weekend'] = 'Weekend days';
$string['configautologinguests'] = 'Should visitors be logged in as guests automatically when entering courses with guest access?';
$string['configbloglevel'] = 'This setting allows you to restrict the level to which user blogs can be viewed on this site. Note that they specify the maximum context of the VIEWER not the poster or the types of blog posts. Blogs can also be disabled completely if you don\'t want them at all.';
$string['configcachetext'] = 'For larger sites or sites that use text filters, this setting can really speed things up. Copies of texts will be retained in their processed form for the time specified here. Setting this too small may actually slow things down slightly, but setting it too large may mean texts take too long to refresh (with new links, for example).';
-$string['configcachetype'] = 'Select a type of cache for Moodle to use. This will only configure the cache, remember to enable rcache so that the cache is used for something. Use <strong>only</strong> if you need to reduce the load on the database system -- otherwise Moodle will actually run slower. Medium-traffic sites may see benefits using \'internal\'. A single webserver with eAccelerator or Turckmmcache installed <em>with the shared memory options enabled</em> should try \'eaccelerator\'. If you have a multiple-server setup, and you have one or more memcached daemons running and the PHP-memcached extension, select \'memcached\' and configure the memached options below. <br /><strong>Note:</strong> make sure you test performance under load and tune accordingly -- the caches can make your site slower. In high-traffic situations, eAccelerator and memcached can yield the most benefits, but have the higher costs in CPU usage on the webserver.';
$string['configcalendarexportsalt'] = 'This random text is used for improving of security of authentication tokens used for exporting of calendars. Please note that all current tokens are invalidated if you change this hash salt.';
$string['configclamactlikevirus'] = 'Treat files like viruses';
$string['configclamdonothing'] = 'Treat files as OK';
$string['configgradeexport'] = 'Choose which gradebook export formats are your primary methods for exporting grades. Chosen plugins will then set and use a "last exported" field for every grade. For example, this might result in exported records being identified as being "new" or "updated". If you are not sure about this then leave everything unchecked.';
$string['confighiddenuserfields'] = 'Select which user information fields you wish to hide from other users other than course teachers/admins. This will increase student privacy. Hold CTRL key to select multiple fields.';
$string['configidnumber'] = 'This option specifies whether (a) Users are not be asked for an ID number at all, (b) Users are asked for an ID number but can leave it blank or (c) Users are asked for an ID Number and cannot leave it blank. If given the User\'s ID number is displayed in their Profile.';
-$string['configintcachemax'] = 'For internal cache only. Maximum number of records to keep in the cache. Recommended value: 50. Use lower values to reduce memory usage.';
$string['configintro'] = 'On this page you can specify a number of configuration variables that help make Moodle work properly on your server. Don\'t worry too much about it - the defaults will usually work fine and you can always come back to this page later and change these settings.';
$string['configintroadmin'] = 'On this page you should configure your main administrator account which will have complete control over the site. Make sure you give it a secure username and password as well as a valid email address. You can create more admin accounts later on.';
$string['configintrosite'] = 'This page allows you to configure the front page and name of this new site. You can come back here later to change these settings any time using the Administration menus.';
$string['configmaxconsecutiveidentchars'] = 'Passwords must not have more than this number of consecutive identical characters. Use 0 to disable this check.';
$string['configmaxeditingtime'] = 'This specifies the amount of time people have to re-edit forum postings, glossary comments etc. Usually 30 minutes is a good value.';
$string['configmaxevents'] = 'Events to Lookahead';
-$string['configmemcachedhosts'] = 'For memcached. Comma-separated list of hosts that are running the memcached daemon. Use IP addresses to avoid DNS latency. memcached does not behave well if you add/remove hosts on a running setup.';
-$string['configmemcachedpconn'] = 'For memcached. Use persistent connections. Use carefully -- it can make Apache/PHP crash after a restart of the memcached daemon.';
$string['configmessaging'] = 'Should the messaging system between site users be enabled?';
$string['configmessagingallowemailoverride'] = 'Allow users to have email message notifications sent to an email address other than the email address in their profile';
$string['configmessaginghidereadnotifications'] = 'Hide read notifications of events like forum posts when viewing messaging history';
$string['configproxytype'] = 'Type of web proxy (PHP5 and cURL extension required for SOCKS5 support).';
$string['configproxyuser'] = 'Username needed to access internet through proxy if required, empty if none (PHP cURL extension required).';
$string['configquarantinedir'] = 'If you want clam AV to move infected files to a quarantine directory, enter it here. It must be writable by the webserver. If you leave this blank, or if you enter a directory that doesn\'t exist or isn\'t writable, infected files will be deleted. Do not include a trailing slash.';
-$string['configrcache'] = 'Use the cache to store database records. Remember to set \'cachetype\' as well!';
-$string['configrcachettl'] = 'Time-to-live for cached records, in seconds. Use a short (<15) value here.';
$string['configrecaptchaprivatekey'] = 'String of characters used to communicate between your Moodle server and the recaptcha server. Obtain one for this site by visiting http://www.google.com/recaptcha';
$string['configrecaptchapublickey'] = 'String of characters used to display the reCAPTCHA element in the signup form. Generated by http://www.google.com/recaptcha';
$string['configrequestcategoryselection'] = 'Allow the selection of a category when requesting a course.';
$string['incompatibleblocks'] = 'Incompatible blocks';
$string['installhijacked'] = 'Installation must be finished from the original IP address, sorry.';
$string['installsessionerror'] = 'Can not initialise PHP session, please verify that your browser accepts cookies.';
-$string['intcachemax'] = 'Int. cache max';
$string['intlrecommended'] = 'Intl extension is used to improve internationalization support, such as locale aware sorting.';
$string['invalidsection'] = 'Invalid section.';
$string['invaliduserchangeme'] = 'Username "changeme" is reserved -- you cannot create an account with it.';
$string['mediapluginswfnote'] = 'As a default security measure, normal users should not be allowed to embed swf flash files.';
$string['mediapluginwmv'] = 'Enable .wmv filter';
$string['mediapluginyoutube'] = 'Enable YouTube links filter';
-$string['memcachedhosts'] = 'memcached hosts';
-$string['memcachedpconn'] = 'memcached use persistent connections';
$string['messaging'] = 'Enable messaging system';
$string['messagingallowemailoverride'] = 'Notification email override';
$string['messaginghidereadnotifications'] = 'Hide read notifications';
$string['questioncwqpfsok'] = 'Good. There are no \'random\' questions in your quizzes that are set up to select questions from a mixture of shared and unshared question categories.';
$string['questiontype'] = 'Question type';
$string['questiontypes'] = 'Question types';
-$string['rcache'] = 'Record cache';
-$string['rcachettl'] = 'Record cache TTL';
$string['recaptchaprivatekey'] = 'ReCAPTCHA private key';
$string['recaptchapublickey'] = 'ReCAPTCHA public key';
$string['register'] = 'Register your site';
$string['showgroupsevents'] = 'Show group events';
$string['showuserevents'] = 'Show user events';
$string['shown'] = 'shown';
+$string['siteevents'] = 'Site events';
$string['spanningevents'] = 'Events underway';
$string['subscriptions'] = 'Subscriptions';
$string['subscriptionname'] = 'Calendar name';
$string['contactlistempty'] = 'Your contact list is empty';
$string['contacts'] = 'Contacts';
$string['context'] = 'context';
-$string['couldnotfindpreference'] = 'Could not load preference {$a}. Does the component and name you supplied to message_send() match a row in message_providers? Message providers must appear in the database so users can configure how they will be notified when they receive messages.';
$string['defaultmessageoutputs'] = 'Default message outputs';
$string['defaults'] = 'Defaults';
$string['deletemessagesdays'] = 'Number of days before old messages are automatically deleted';
if ($updowncount > 1) {
$aurl = new moodle_url($url, array('action'=>'up', 'enrol'=>$enrol));
$updown .= "<a href=\"$aurl\">";
- $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"$strup\" /></a> ";
+ $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"$strup\" class=\"iconsmall\" /></a> ";
} else {
- $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"icon\" alt=\"\" /> ";
+ $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" /> ";
}
if ($updowncount < $enrolcount) {
$aurl = new moodle_url($url, array('action'=>'down', 'enrol'=>$enrol));
$updown .= "<a href=\"$aurl\">";
- $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"$strdown\" /></a>";
+ $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"$strdown\" class=\"iconsmall\" /></a>";
} else {
- $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"icon\" alt=\"\" />";
+ $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" />";
}
++$updowncount;
}
*/
public function __construct() {
global $CFG;
- parent::__construct('manageqtypes', get_string('manageqtypes', 'admin'), "$CFG->wwwroot/$CFG->admin/qtypes.php");
+ parent::__construct('manageqtypes', get_string('manageqtypes', 'admin'),
+ new moodle_url('/admin/qtypes.php'));
}
/**
if ($enabled) {
if ($updowncount > 1) {
$updown .= "<a href=\"$url&action=up&auth=$auth\">";
- $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"up\" /></a> ";
+ $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"up\" class=\"iconsmall\" /></a> ";
}
else {
- $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"icon\" alt=\"\" /> ";
+ $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" /> ";
}
if ($updowncount < $authcount) {
$updown .= "<a href=\"$url&action=down&auth=$auth\">";
- $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"down\" /></a>";
+ $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"down\" class=\"iconsmall\" /></a>";
}
else {
- $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"icon\" alt=\"\" />";
+ $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" />";
}
++ $updowncount;
}
if ($enabled) {
if ($updowncount > 1) {
$updown .= "<a href=\"$url&action=up&editor=$editor\">";
- $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"up\" /></a> ";
+ $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"up\" class=\"iconsmall\" /></a> ";
}
else {
- $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"icon\" alt=\"\" /> ";
+ $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" /> ";
}
if ($updowncount < $editorcount) {
$updown .= "<a href=\"$url&action=down&editor=$editor\">";
- $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"down\" /></a>";
+ $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"down\" class=\"iconsmall\" /></a>";
}
else {
- $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"icon\" alt=\"\" />";
+ $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" />";
}
++ $updowncount;
}
$cnt = 0;
$defaultformat = get_config('moodlecourse', 'format');
- $spacer = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'icon'));
+ $spacer = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'iconsmall'));
foreach ($formats as $format) {
$url = new moodle_url('/admin/courseformats.php',
array('sesskey' => sesskey(), 'format' => $format->name));
$updown = '';
if ($cnt) {
$updown .= html_writer::link($url->out(false, array('action' => 'up')),
- $OUTPUT->pix_icon('t/up', $txt->up, 'moodle')). ' ';
+ $OUTPUT->pix_icon('t/up', $txt->up, 'moodle', array('class' => 'iconsmall'))). '';
} else {
$updown .= $spacer;
}
if ($cnt < count($formats) - 1) {
$updown .= ' '.html_writer::link($url->out(false, array('action' => 'down')),
- $OUTPUT->pix_icon('t/down', $txt->down, 'moodle'));
+ $OUTPUT->pix_icon('t/down', $txt->down, 'moodle', array('class' => 'iconsmall')));
} else {
$updown .= $spacer;
}
// Display up/down link
$updown = '';
- $spacer = $OUTPUT->spacer(array('height'=>15, 'width'=>15)); // should be done with CSS instead
+ // Should be done with CSS instead.
+ $spacer = $OUTPUT->spacer(array('height' => 15, 'width' => 15, 'class' => 'smallicon'));
if ($updowncount > 1) {
$updown .= "<a href=\"$this->baseurl&action=moveup&repos=".$typename."\">";
- $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"up\" /></a> ";
+ $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"up\" class=\"iconsmall\" /></a> ";
}
else {
$updown .= $spacer;
}
if ($updowncount < $totalinstances) {
$updown .= "<a href=\"$this->baseurl&action=movedown&repos=".$typename."\">";
- $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"down\" /></a>";
+ $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"down\" class=\"iconsmall\" /></a>";
}
else {
$updown .= $spacer;
function unserialize($string) {
$string = rfc2445_unfold($string); // Unfold any long lines
- $lines = explode(RFC2445_CRLF, $string); // Create an array of lines
+ $lines = preg_split("<".RFC2445_CRLF."|\n|\r>", $string, 0, PREG_SPLIT_NO_EMPTY); // Create an array of lines.
$components = array(); // Initialise a stack of components
$this->clear_errors();
modifications:
1/ removed ereg functions deprecated as of php 5.3 (18 Nov 2009)
-2/ replaced mbstring functions with moodle textlib (28 Nov 2011)
\ No newline at end of file
+2/ replaced mbstring functions with moodle textlib (28 Nov 2011)
+3/ replaced explode in iCalendar_component::unserialize() with preg_split to support various line breaks (20 Nov 2012)
\ No newline at end of file
$controls[] = array('url' => $CFG->wwwroot . '/' . $CFG->admin .
'/roles/assign.php?contextid=' . $block->context->id . '&returnurl=' . urlencode($return),
- 'icon' => 'i/roles', 'caption' => get_string('assignroles', 'role'), 'class' => 'editing_roles');
+ 'icon' => 't/assignroles', 'caption' => get_string('assignroles', 'role'), 'class' => 'editing_roles');
}
return $controls;
Minify::setCache(null, false);
$options = array(
+ // JSMin is not GNU GPL compatible, use the plus version instead.
+ 'minifiers' => array(Minify::TYPE_JS => array('JSMinPlus', 'minify')),
'bubbleCssImports' => false,
// Don't gzip content we just want text for storage
'encodeOutput' => false,
<?xml version="1.0" encoding="UTF-8" ?>
-<XMLDB PATH="lib/db" VERSION="20121102" COMMENT="XMLDB file for core Moodle tables"
+<XMLDB PATH="lib/db" VERSION="20121112" COMMENT="XMLDB file for core Moodle tables"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../lib/xmldb/xmldb.xsd"
>
<KEY NAME="fk_raterid" TYPE="foreign" FIELDS="raterid" REFTABLE="user" REFFIELDS="id" PREVIOUS="fk_definitionid"/>
</KEYS>
</TABLE>
- <TABLE NAME="event_subscriptions" COMMENT="Tracks subscriptions to remote calendars." PREVIOUS="grading_instances">
+ <TABLE NAME="event_subscriptions" COMMENT="Tracks subscriptions to remote calendars." PREVIOUS="grading_instances" NEXT="temp_enroled_template">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="url"/>
<FIELD NAME="url" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="id" NEXT="courseid"/>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
</KEYS>
</TABLE>
+ <TABLE NAME="temp_enroled_template" COMMENT="Temporary storage for course enrolments" PREVIOUS="event_subscriptions" NEXT="temp_log_template">
+ <FIELDS>
+ <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="userid"/>
+ <FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="id" NEXT="courseid"/>
+ <FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="userid" NEXT="roleid"/>
+ <FIELD NAME="roleid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" PREVIOUS="courseid"/>
+ </FIELDS>
+ <KEYS>
+ <KEY NAME="primary" TYPE="primary" FIELDS="id"/>
+ </KEYS>
+ <INDEXES>
+ <INDEX NAME="userid" UNIQUE="false" FIELDS="userid" NEXT="courseid"/>
+ <INDEX NAME="courseid" UNIQUE="false" FIELDS="courseid" PREVIOUS="userid" NEXT="roleid"/>
+ <INDEX NAME="roleid" UNIQUE="false" FIELDS="roleid" PREVIOUS="courseid"/>
+ </INDEXES>
+ </TABLE>
+ <TABLE NAME="temp_log_template" COMMENT="Temporary storage for daily logs" PREVIOUS="temp_enroled_template">
+ <FIELDS>
+ <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="userid"/>
+ <FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="id" NEXT="course"/>
+ <FIELD NAME="course" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="userid" NEXT="action"/>
+ <FIELD NAME="action" TYPE="char" LENGTH="40" NOTNULL="true" SEQUENCE="false" PREVIOUS="course"/>
+ </FIELDS>
+ <KEYS>
+ <KEY NAME="primary" TYPE="primary" FIELDS="id"/>
+ </KEYS>
+ <INDEXES>
+ <INDEX NAME="action" UNIQUE="false" FIELDS="action" NEXT="course"/>
+ <INDEX NAME="course" UNIQUE="false" FIELDS="course" PREVIOUS="action" NEXT="user"/>
+ <INDEX NAME="user" UNIQUE="false" FIELDS="userid" PREVIOUS="course" NEXT="usercourseaction"/>
+ <INDEX NAME="usercourseaction" UNIQUE="false" FIELDS="userid, course, action" PREVIOUS="user"/>
+ </INDEXES>
+ </TABLE>
</TABLES>
</XMLDB>
upgrade_main_savepoint(true, 2012110700.01);
}
+ if ($oldversion < 2012111200.00) {
+
+ // Define table temp_enroled_template to be created
+ $table = new xmldb_table('temp_enroled_template');
+
+ // Adding fields to table temp_enroled_template
+ $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
+ $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
+ $table->add_field('courseid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
+ $table->add_field('roleid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
+
+ // Adding keys to table temp_enroled_template
+ $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
+
+ // Adding indexes to table temp_enroled_template
+ $table->add_index('userid', XMLDB_INDEX_NOTUNIQUE, array('userid'));
+ $table->add_index('courseid', XMLDB_INDEX_NOTUNIQUE, array('courseid'));
+ $table->add_index('roleid', XMLDB_INDEX_NOTUNIQUE, array('roleid'));
+
+ // Conditionally launch create table for temp_enroled_template
+ if (!$dbman->table_exists($table)) {
+ $dbman->create_table($table);
+ }
+
+ // Define table temp_log_template to be created
+ $table = new xmldb_table('temp_log_template');
+
+ // Adding fields to table temp_log_template
+ $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
+ $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
+ $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
+ $table->add_field('action', XMLDB_TYPE_CHAR, '40', null, XMLDB_NOTNULL, null, null);
+
+ // Adding keys to table temp_log_template
+ $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
+
+ // Adding indexes to table temp_log_template
+ $table->add_index('action', XMLDB_INDEX_NOTUNIQUE, array('action'));
+ $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
+ $table->add_index('user', XMLDB_INDEX_NOTUNIQUE, array('userid'));
+ $table->add_index('usercourseaction', XMLDB_INDEX_NOTUNIQUE, array('userid', 'course', 'action'));
+
+ // Conditionally launch create table for temp_log_template
+ if (!$dbman->table_exists($table)) {
+ $dbman->create_table($table);
+ }
+
+ // Main savepoint reached
+ upgrade_main_savepoint(true, 2012111200.00);
+ }
+
+ if ($oldversion < 2012111200.01) {
+ // Force the rebuild of the cache of every courses, some cached information could contain wrong icon references.
+ rebuild_course_cache();
+
+ // Main savepoint reached.
+ upgrade_main_savepoint(true, 2012111200.01);
+ }
+
+ if ($oldversion < 2012111601.01) {
+ // Clea up after old shared memory caching support.
+ unset_config('cachetype');
+ unset_config('rcache');
+ unset_config('rcachettl');
+ unset_config('intcachemax');
+ unset_config('memcachedhosts');
+ unset_config('memcachedpconn');
+
+ // Main savepoint reached.
+ upgrade_main_savepoint(true, 2012111601.01);
+ }
+
+
return true;
}
+++ /dev/null
-<?php
-
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * This class abstracts eaccelerator/turckmmcache
- * API to provide
- *
- * - get()
- * - set()
- * - delete()
- * - getforfill()
- * - releaseforfill()
- *
- * Note: do NOT store booleans here. For compatibility with
- * memcached, a false value is indistinguisable from a
- * "not found in cache" response.
- *
- * @package core
- * @subpackage lib
- * @copyright Martin Langhoff <martin@catalyst.net.nz>
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-defined('MOODLE_INTERNAL') || die();
-
-/**
- *
- * @copyright Martin Langhoff <martin@catalyst.net.nz>
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- * @package moodlecore
- */
-class eaccelerator {
-
- /**
- * @todo Document this function
- *
- * @global object
- */
- function eaccelerator() {
- global $CFG;
- if ( function_exists('eaccelerator_get')) {
- $this->mode = 'eaccelerator';
- } elseif (function_exists('mmcache_get')) {
- $this->mode = 'mmcache';
- } else {
- debugging("\$CFG->eaccelerator is set to true but the required functions are not available. You need to have either eaccelerator or turckmmcache extensions installed, compiled with the shmem keys option enabled.");
- }
-
- $this->prefix = $CFG->dbname .'|' . $CFG->prefix . '|';
- }
-
- /**
- * The status of the eaccelerator, if it has been established
- * this will return true
- *
- * @return bool
- */
- function status() {
- if (isset($this->mode)) {
- return true;
- }
- return false;
- }
-
- /**
- * @todo Document this function
- *
- * @param string $key
- * @param string $value
- * @param int $ttl
- * @return mixed
- */
- function set($key, $value, $ttl=0) {
- $set = $this->mode . '_put';
- $unlock = $this->mode . '_unlock';
-
- // we may have acquired a lock via getforfill
- // release if it exists
- @$unlock($this->prefix . $key . '_forfill');
-
- return $set($this->prefix . $key, serialize($value), $ttl);
- }
-
- /**
- * @todo Document this function
- *
- * @param string $key
- * @return string|bool String if success else false
- */
- function get($key) {
- $fn = $this->mode . '_get';
- $rec = $fn($this->prefix . $key);
- if (is_null($rec)) {
- return false;
- }
- return unserialize($rec);
- }
-
- /**
- * @todo Document this function
- *
- * @param string $key
- * @return mixed
- */
- function delete($key) {
- $fn = $this->mode . '_rm';
- return $fn($this->prefix . $key);
- }
-
- /**
- * In the simple case, this function will
- * get the cached value if available. If the entry
- * is not cached, it will try to get an exclusive
- * lock that announces that this process will
- * populate the cache.
- *
- * If we fail to get the lock -- this means another
- * process is doing it.
- * so we wait (block) for a few microseconds while we wait for
- * the cache to be filled or the lock to timeout.
- *
- * If you get a false from this call, you _must_
- * populate the cache ASAP or indicate that
- * you won't by calling releaseforfill().
- *
- * This technique forces serialisation and so helps deal
- * with thundering herd scenarios where a lot of clients
- * ask the for the same idempotent (and costly) operation.
- * The implementation is based on suggestions in this message
- * http://marc.theaimsgroup.com/?l=git&m=116562052506776&w=2
- *
- * @param $key string
- * @return mixed on cache hit, false otherwise
- */
- function getforfill ($key) {
- $get = $this->mode . '_get';
- $lock = $this->mode . '_lock';
-
- $rec = $get($this->prefix . $key);
- if (!is_null($rec)) {
- return unserialize($rec);
- }
- if ($lock($this->prefix . $key . '_forfill')) {
- // we obtained the _forfill lock
- // our caller will compute and set the value
- return false;
- }
- // someone else has the lock
- // "block" till we can get the value
- // actually, loop .05s waiting for it
- for ($n=0;$n<5;$n++) {
- usleep(10000);
- $rec = $get($this->prefix . $key);
- if (!is_null($rec)) {
- return unserialize($rec);
- }
- }
- return false;
- }
-
- /**
- * Release the exclusive lock obtained by
- * getforfill(). See getforfill()
- * for more details.
- *
- * @param $key string
- * @return bool
- */
- function releaseforfill ($key) {
- $unlock = $this->mode . '_unlock';
- return $unlock($this->prefix . $key . '_forfill');
- }
-}
-
-?>
\ No newline at end of file
$htmllang = get_html_lang();
header('Content-Type: text/html; charset=utf-8');
+header('X-UA-Compatible: IE=edge');
?>
<!DOCTYPE html>
<html <?php echo $htmllang ?>
}
$file = $cachefile;
+} else if ($mimetype === 'text/html') {
+ header('X-UA-Compatible: IE=edge');
}
// Serve file.
$htmllang = get_html_lang();
header('Content-Type: text/html; charset=utf-8');
+header('X-UA-Compatible: IE=edge');
?>
<!DOCTYPE html>
<html <?php echo $htmllang ?>
$matches = $this->_getMatches($lang, $word);\r
\r
if (count($matches) > 0)\r
- $sug = explode("\t", utf8_encode($this->_unhtmlentities($matches[0][4])));\r
+ $sug = explode("\t", $this->_unhtmlentities($matches[0][4]));\r
\r
// Remove empty\r
foreach ($sug as $item) {\r
Changes:
-1/ zIndex 300000 and 200000 changed to 3000 and 2000 - this prevents collision with YUI,
+ * zIndex 300000 and 200000 changed to 3000 and 2000 - this prevents collision with YUI,
see MDL-35771
+ * MDL-25736 - French spellchecker fixes.
TODO:
* create some new automated script that sends other languages from upstream into AMOS
// list all participants - allows assigning roles, groups, etc.
if (has_capability('moodle/course:enrolreview', $coursecontext)) {
$url = new moodle_url('/enrol/users.php', array('id'=>$course->id));
- $usersnode->add(get_string('enrolledusers', 'enrol'), $url, navigation_node::TYPE_SETTING, null, 'review', new pix_icon('i/users', ''));
+ $usersnode->add(get_string('enrolledusers', 'enrol'), $url, navigation_node::TYPE_SETTING, null, 'review', new pix_icon('i/enrolusers', ''));
}
// manage enrol plugin instances
if ($course->id == SITEID or (!empty($CFG->adminsassignrolesincourse) and is_siteadmin())) {
if (has_capability('moodle/role:assign', $coursecontext)) {
$url = new moodle_url('/admin/roles/assign.php', array('contextid'=>$coursecontext->id));
- $permissionsnode->add(get_string('assignedroles', 'role'), $url, navigation_node::TYPE_SETTING, null, 'roles', new pix_icon('i/roles', ''));
+ $permissionsnode->add(get_string('assignedroles', 'role'), $url, navigation_node::TYPE_SETTING, null, 'roles', new pix_icon('i/assignroles', ''));
}
}
// Check role permissions
//TODO, create some new UI for role assignments at course level
if (has_capability('moodle/role:assign', $coursecontext)) {
$url = new moodle_url('/enrol/otherusers.php', array('id'=>$course->id));
- $usersnode->add(get_string('notenrolledusers', 'enrol'), $url, navigation_node::TYPE_SETTING, null, 'otherusers', new pix_icon('i/roles', ''));
+ $usersnode->add(get_string('notenrolledusers', 'enrol'), $url, navigation_node::TYPE_SETTING, null, 'otherusers', new pix_icon('i/assignroles', ''));
}
}
if (!$event = $DB->get_record('event', array('id'=>(int)$eventid, 'eventtype'=>'site'))) {
send_file_not_found();
}
- // Check that we got an event and that it's userid is that of the user
// Get the file and serve if successful
$filename = array_pop($args);
require_login($course);
}
- // Must be able to at least view the course
- if (!is_enrolled($context) and !is_viewing($context)) {
+ // Must be able to at least view the course. This does not apply to the front page.
+ if ($course->id != SITEID && (!is_enrolled($context)) && (!is_viewing($context))) {
//TODO: hmm, do we really want to block guests here?
send_file_not_found();
}
if (!has_capability('moodle/site:accessallgroups', $context) && !groups_is_member($event->groupid, $USER->id)) {
send_file_not_found();
}
- } else if ($event->eventtype === 'course') {
- //ok
+ } else if ($event->eventtype === 'course' || $event->eventtype === 'site') {
+ // Ok. Please note that the event type 'site' still uses a course context.
} else {
- // some other type
+ // Some other type.
send_file_not_found();
}
// switch next two lines for ol li containers for form items.
// $this->_elementTemplates=array('default'=>"\n\t\t".'<li class="fitem"><label>{label}{help}<!-- BEGIN required -->{req}<!-- END required --></label><div class="qfelement<!-- BEGIN error --> error<!-- END error --> {type}"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element}</div></li>');
$this->_elementTemplates = array(
- 'default'=>"\n\t\t".'<div id="{id}" class="fitem {advanced}<!-- BEGIN required --> required<!-- END required --> fitem_{type}"><div class="fitemtitle"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg} {help}</label></div><div class="felement {type}<!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element}</div></div>',
+ 'default'=>"\n\t\t".'<div id="{id}" class="fitem {advanced}<!-- BEGIN required --> required<!-- END required --> fitem_{type}"><div class="fitemtitle"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg}{help} </label></div><div class="felement {type}<!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element}</div></div>',
'actionbuttons'=>"\n\t\t".'<div id="{id}" class="fitem fitem_actionbuttons fitem_{type}"><div class="felement {type}">{element}</div></div>',
- 'fieldset'=>"\n\t\t".'<div id="{id}" class="fitem {advanced}<!-- BEGIN required --> required<!-- END required --> fitem_{type}"><div class="fitemtitle"><div class="fgrouplabel"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg} {help}</label></div></div><fieldset class="felement {type}<!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element}</fieldset></div>',
+ 'fieldset'=>"\n\t\t".'<div id="{id}" class="fitem {advanced}<!-- BEGIN required --> required<!-- END required --> fitem_{type}"><div class="fitemtitle"><div class="fgrouplabel"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg}{help} </label></div></div><fieldset class="felement {type}<!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element}</fieldset></div>',
- 'static'=>"\n\t\t".'<div class="fitem {advanced}"><div class="fitemtitle"><div class="fstaticlabel"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg} {help}</label></div></div><div class="felement fstatic <!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element} </div></div>',
+ 'static'=>"\n\t\t".'<div class="fitem {advanced}"><div class="fitemtitle"><div class="fstaticlabel"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg}{help} </label></div></div><div class="felement fstatic <!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element} </div></div>',
-'warning'=>"\n\t\t".'<div class="fitem {advanced}">{element}</div>',
+ 'warning'=>"\n\t\t".'<div class="fitem {advanced}">{element}</div>',
'nodisplay'=>'');
if ($search) {
$url.='?q='.urlencode($search);
}
- $content = $this->googleoauth->get($url);
-
- $xml = new SimpleXMLElement($content);
$files = array();
+ $content = $this->googleoauth->get($url);
+ try {
+ if (strpos($content, '<?xml') !== 0) {
+ throw new moodle_exception('invalidxmlresponse');
+ }
+ $xml = new SimpleXMLElement($content);
+ } catch (Exception $e) {
+ // An error occured while trying to parse the XML, let's just return nothing. SimpleXML does not
+ // return a more specific Exception, that's why the global Exception class is caught here.
+ return $files;
+ }
foreach ($xml->entry as $gdoc) {
$docid = (string) $gdoc->children('http://schemas.google.com/g/2005')->resourceId;
list($type, $docid) = explode(':', $docid);
* @return mixes $files Array in the format get_listing uses for folders
*/
public function get_albums() {
+ $files = array();
$content = $this->googleoauth->get(self::LIST_ALBUMS_URL);
- $xml = new SimpleXMLElement($content);
- $files = array();
+ try {
+ if (strpos($content, '<?xml') !== 0) {
+ throw new moodle_exception('invalidxmlresponse');
+ }
+ $xml = new SimpleXMLElement($content);
+ } catch (Exception $e) {
+ // An error occured while trying to parse the XML, let's just return nothing. SimpleXML does not
+ // return a more specific Exception, that's why the global Exception class is caught here.
+ return $files;
+ }
foreach ($xml->entry as $album) {
$gphoto = $album->children('http://schemas.google.com/photos/2007');
'thumbnail_height' => 160,
'children' => array(),
);
-
}
return $files;
* @return mixed $files A list of files for the file picker
*/
public function get_photo_details($rawxml) {
+ $files = array();
- $xml = new SimpleXMLElement($rawxml);
+ try {
+ if (strpos($rawxml, '<?xml') !== 0) {
+ throw new moodle_exception('invalidxmlresponse');
+ }
+ $xml = new SimpleXMLElement($rawxml);
+ } catch (Exception $e) {
+ // An error occured while trying to parse the XML, let's just return nothing. SimpleXML does not
+ // return a more specific Exception, that's why the global Exception class is caught here.
+ return $files;
+ }
$this->lastalbumname = (string)$xml->title;
- $files = array();
-
foreach ($xml->entry as $photo) {
$gphoto = $photo->children('http://schemas.google.com/photos/2007');
* Refetch grades from modules, plugins.
*
* @param int $userid optional, limit the refetch to a single user
+ * @return bool Returns true on success or if there is nothing to do
*/
public function refresh_grades($userid=0) {
global $DB;
if ($this->itemtype == 'mod') {
if ($this->is_outcome_item()) {
//nothing to do
- return;
+ return true;
}
if (!$activity = $DB->get_record($this->itemmodule, array('id' => $this->iteminstance))) {
debugging("Can not find $this->itemmodule activity with id $this->iteminstance");
- return;
+ return false;
}
if (!$cm = get_coursemodule_from_instance($this->itemmodule, $activity->id, $this->courseid)) {
debugging('Can not find course module');
- return;
+ return false;
}
$activity->modname = $this->itemmodule;
$activity->cmidnumber = $cm->idnumber;
- grade_update_mod_grades($activity);
+ return grade_update_mod_grades($activity, $userid);
}
+
+ return true;
}
/**
$this->sub_test_grade_item_is_course_item();
$this->sub_test_grade_item_fetch_course_item();
$this->sub_test_grade_item_depends_on();
+ $this->sub_test_refresh_grades();
$this->sub_test_grade_item_is_calculated();
$this->sub_test_grade_item_set_calculation();
$this->sub_test_grade_item_get_calculation();
$this->assertEquals($res, $deps);
}
+ protected function sub_test_refresh_grades() {
+ // Testing with the grade item for a mod_assignment instance.
+ $grade_item = new grade_item($this->grade_items[0], false);
+ $this->assertTrue(method_exists($grade_item, 'refresh_grades'));
+ $this->assertTrue($grade_item->refresh_grades());
+
+ // Break the grade item and check error handling.
+ $grade_item->iteminstance = 123456789;
+ $this->assertFalse($grade_item->refresh_grades());
+ $this->assertDebuggingCalled();
+ }
+
protected function sub_test_grade_item_is_calculated() {
$grade_item = new grade_item($this->grade_items[1], false);
$this->assertTrue(method_exists($grade_item, 'is_calculated'));
$updategradesfunc($modinstance, $userid);
} else {
- // mudule does not support grading??
+ // Module does not support grading?
}
return true;
global $CFG, $OUTPUT; //TODO: MUST NOT USE $OUTPUT HERE!!!
@header('Content-Type: text/html; charset=UTF-8');
+ @header('X-UA-Compatible: IE=edge');
@header('Cache-Control: no-store, no-cache, must-revalidate');
@header('Cache-Control: post-check=0, pre-check=0', false);
@header('Pragma: no-cache');
global $CFG;
@header('Content-Type: text/html; charset=UTF-8');
+ @header('X-UA-Compatible: IE=edge');
@header('Cache-Control: no-store, no-cache, must-revalidate');
@header('Cache-Control: post-check=0, pre-check=0', false);
@header('Pragma: no-cache');
// Get the height of the div at this point before we shrink it if required
var height = this.div.get('offsetHeight');
var collapsedimage = 't/collapsed'; // ltr mode
- if ( Y.one(document.body).hasClass('dir-rtl') ) {
+ if (right_to_left()) {
collapsedimage = 't/collapsed_rtl';
} else {
collapsedimage = 't/collapsed';
animation.on('end', function() {
this.div.toggleClass('collapsed');
var collapsedimage = 't/collapsed'; // ltr mode
- if ( Y.one(document.body).hasClass('dir-rtl') ) {
+ if (right_to_left()) {
collapsedimage = 't/collapsed_rtl';
} else {
collapsedimage = 't/collapsed';
'top' : 0,
'left' : 0,
'backgroundColor' : 'white',
- 'text-align' : 'center'
+ 'textAlign' : 'center'
})
.setAttribute('class', 'lightbox')
.hide();
return (arrReturnElements)
}
+/**
+ * Return whether we are in right to left mode or not.
+ *
+ * @return boolean
+ */
+function right_to_left() {
+ var body = Y.one('body');
+ var rtl = false;
+ if (body && body.hasClass('dir-rtl')) {
+ rtl = true;
+ }
+ return rtl;
+}
+
function openpopup(event, args) {
if (event) {
Minify::setCache(null, false);
$options = array(
+ // JSMin is not GNU GPL compatible, use the plus version instead.
+ 'minifiers' => array(Minify::TYPE_JS => array('JSMinPlus', 'minify')),
'bubbleCssImports' => false,
// Don't gzip content we just want text for storage
'encodeOutput' => false,
+++ /dev/null
-<?php
-
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * @package core
- * @subpackage lib
- * @copyright Martin Langhoff <martin@catalyst.net.nz>
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-defined('MOODLE_INTERNAL') || die();
-
-/**
- * This class abstracts PHP's PECL memcached
- * API to provide
- *
- * - get()
- * - set()
- * - delete()
- * - getforfill()
- * - releaseforfill()
- *
- * Author: Martin Langhoff <martin@catalyst.net.nz>
- *
- * Note: do NOT store booleans here. With memcached, a false value
- * is indistinguisable from a "not found in cache" response.
- *
- * @package moodlecore
- * @copyright Martin Langhoff <martin@catalyst.net.nz>
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- **/
-class memcached {
-
- function memcached() {
- global $CFG;
-
- if (!function_exists('memcache_connect')) {
- debugging("Memcached is set to true but the memcached extension is not installed");
- return false;
- }
- $this->_cache = new Memcache;
-
- $hosts = explode(',', $CFG->memcachedhosts);
- if (count($hosts) === 1 && !empty($CFG->memcachedpconn)) {
- // the faster pconnect is only available
- // for single-server setups
- // NOTE: PHP-PECL client is buggy and pconnect()
- // will segfault if the server is unavailable
- $this->_cache->pconnect($hosts[0]);
- } else {
- // multi-host setup will share key space
- foreach ($hosts as $host) {
- $host = trim($host);
- $this->_cache->addServer($host);
- }
- }
-
- $this->prefix = $CFG->dbname .'|' . $CFG->prefix . '|';
- }
-
- function status() {
- if (is_object($this->_cache)) {
- return true;
- }
- return false;
- }
-
- function set($key, $value, $ttl=0) {
-
- // we may have acquired a lock via getforfill
- // release if it exists
- @$this->_cache->delete($this->prefix . $key . '_forfill');
-
- return $this->_cache->set($this->prefix . $key, $value, false);
- }
-
- function get($key) {
- $rec = $this->_cache->get($this->prefix . $key);
- return $rec;
- }
-
- function delete($key) {
- return $this->_cache->delete($this->prefix . $key);
- }
-
- /**
- * In the simple case, this function will
- * get the cached value if available. If the entry
- * is not cached, it will try to get an exclusive
- * lock that announces that this process will
- * populate the cache.
- *
- * If we fail to get the lock -- this means another
- * process is doing it.
- * so we wait (block) for a few microseconds while we wait for
- * the cache to be filled or the lock to timeout.
- *
- * If you get a false from this call, you _must_
- * populate the cache ASAP or indicate that
- * you won't by calling releaseforfill().
- *
- * This technique forces serialisation and so helps deal
- * with thundering herd scenarios where a lot of clients
- * ask the for the same idempotent (and costly) operation.
- * The implementation is based on suggestions in this message
- * http://marc.theaimsgroup.com/?l=git&m=116562052506776&w=2
- *
- * @param $key string
- * @return mixed on cache hit, NULL otherwise
- */
- function getforfill ($key) {
-
- $rec = $this->_cache->get($this->prefix . $key);
- if ($rec) {
- return $rec;
- }
- if ($this->_cache->add($this->prefix . $key . '_forfill', 'true', false, 1)) {
- // we obtained the _forfill lock
- // our caller will compute and set the value
- return false;
- }
- // someone else has the lock
- // "block" till we can get the value
- // actually, loop .05s waiting for it
- for ($n=0;$n<5;$n++) {
- usleep(10000);
- $rec = $this->_cache->get($this->prefix . $key);
- if ($rec) {
- return $rec;
- }
- }
- return false;
- }
-
- /**
- * Release the exclusive lock obtained by
- * getforfill(). See getforfill()
- * for more details.
- *
- * @param $key string
- * @return bool
- */
- function releaseforfill ($key) {
- return $this->_cache->delete($this->prefix . $key . '_forfill');
- }
-}
if (isset($defaultpreferences->{$defaultpreference})) {
$permitted = $defaultpreferences->{$defaultpreference};
} else {
- //MDL-25114 They supplied an $eventdata->component $eventdata->name combination which doesn't
- //exist in the message_provider table (thus there is no default settings for them)
- $preferrormsg = get_string('couldnotfindpreference', 'message', $defaultpreference);
- throw new coding_exception($preferrormsg,'blah');
+ // MDL-25114 They supplied an $eventdata->component $eventdata->name combination which doesn't
+ // exist in the message_provider table (thus there is no default settings for them).
+ $preferrormsg = "Could not load preference $defaultpreference. Make sure the component and name you supplied
+ to message_send() are valid.";
+ throw new coding_exception($preferrormsg);
}
// Find out if user has configured this output
function message_get_providers_for_user($userid) {
global $DB, $CFG;
- $systemcontext = context_system::instance();
-
$providers = get_message_providers();
- // Remove all the providers we aren't allowed to see now
- foreach ($providers as $providerid => $provider) {
- if (!empty($provider->capability)) {
- if (!has_capability($provider->capability, $systemcontext, $userid)) {
- unset($providers[$providerid]); // Not allowed to see this
- continue;
+ // Ensure user is not allowed to configure instantmessage if it is globally disabled.
+ if (!$CFG->messaging) {
+ foreach ($providers as $providerid => $provider) {
+ if ($provider->name == 'instantmessage') {
+ unset($providers[$providerid]);
+ break;
}
}
+ }
- // Ensure user is not allowed to configure instantmessage if it is globally disabled.
- if (!$CFG->messaging && $provider->name == 'instantmessage') {
+ // If the component is an enrolment plugin, check it is enabled
+ foreach ($providers as $providerid => $provider) {
+ list($type, $name) = normalize_component($provider->component);
+ if ($type == 'enrol' && !enrol_is_enabled($name)) {
unset($providers[$providerid]);
+ }
+ }
+
+ // Now we need to check capabilities. We need to eliminate the providers
+ // where the user does not have the corresponding capability anywhere.
+ // Here we deal with the common simple case of the user having the
+ // capability in the system context. That handles $CFG->defaultuserroleid.
+ // For the remaining providers/capabilities, we need to do a more complex
+ // query involving all overrides everywhere.
+ $unsureproviders = array();
+ $unsurecapabilities = array();
+ $systemcontext = context_system::instance();
+ foreach ($providers as $providerid => $provider) {
+ if (empty($provider->capability) || has_capability($provider->capability, $systemcontext, $userid)) {
+ // The provider is relevant to this user.
continue;
}
- // If the component is an enrolment plugin, check it is enabled
- list($type, $name) = normalize_component($provider->component);
- if ($type == 'enrol') {
- if (!enrol_is_enabled($name)) {
- unset($providers[$providerid]);
- continue;
- }
+ $unsureproviders[$providerid] = $provider;
+ $unsurecapabilities[$provider->capability] = 1;
+ unset($providers[$providerid]);
+ }
+
+ if (empty($unsureproviders)) {
+ // More complex checks are not required.
+ return $providers;
+ }
+
+ // Now check the unsure capabilities.
+ list($capcondition, $params) = $DB->get_in_or_equal(
+ array_keys($unsurecapabilities), SQL_PARAMS_NAMED);
+ $params['userid'] = $userid;
+
+ $sql = "SELECT DISTINCT rc.capability, 1
+
+ FROM {role_assignments} ra
+ JOIN {context} actx ON actx.id = ra.contextid
+ JOIN {role_capabilities} rc ON rc.roleid = ra.roleid
+ JOIN {context} cctx ON cctx.id = rc.contextid
+
+ WHERE ra.userid = :userid
+ AND rc.capability $capcondition
+ AND rc.permission > 0
+ AND (".$DB->sql_concat('actx.path', "'/'")." LIKE ".$DB->sql_concat('cctx.path', "'/%'").
+ " OR ".$DB->sql_concat('cctx.path', "'/'")." LIKE ".$DB->sql_concat('actx.path', "'/%'").")";
+
+ if (!empty($CFG->defaultfrontpageroleid)) {
+ $frontpagecontext = context_course::instance(SITEID);
+
+