$userserrors++;
continue;
}
-
+ if ($user->username !== clean_param($user->username, PARAM_USERNAME)) {
+ $upt->track('status', get_string('invalidusername', 'error', 'username'), 'error');
+ $upt->track('username', $errorstr, 'error');
+ $userserrors++;
+ }
if ($existinguser = $DB->get_record('user', array('username'=>$user->username, 'mnethostid'=>$CFG->mnet_localhost_id))) {
$upt->track('id', $existinguser->id, 'normal', false);
}
$data->courseid = $this->get_courseid();
- $newitemid = $DB->insert_record('grade_settings', $data);
- //$this->set_mapping('grade_setting', $oldid, $newitemid);
+ if (!$DB->record_exists('grade_settings', array('courseid' => $data->courseid, 'name' => $data->name))) {
+ $newitemid = $DB->insert_record('grade_settings', $data);
+ } else {
+ $newitemid = $data->id;
+ }
+
+ $this->set_mapping('grade_setting', $oldid, $newitemid);
}
/**
$this->cm->groupmode = $this->course->groupmode;
$this->cm->groupingid = $this->course->defaultgroupingid;
+ // Set the correct default for completion tracking.
+ $this->cm->completion = COMPLETION_TRACKING_NONE;
+ $completion = new completion_info($this->course);
+ if ($completion->is_enabled()) {
+ if (plugin_supports('mod', $this->cm->modulename, FEATURE_MODEDIT_DEFAULT_COMPLETION, true)) {
+ $this->cm->completion = COMPLETION_TRACKING_MANUAL;
+ }
+ }
+
if (!$this->cm->id = add_course_module($this->cm)) {
throw new coding_exception("Unable to create the course module");
}
* @param object role is a record from the mdl_role table.
* @return array
*/
- protected function find_ext_enrolments ($ldapconnection, $memberuid, $role) {
+ protected function find_ext_enrolments (&$ldapconnection, $memberuid, $role) {
global $CFG;
require_once($CFG->libdir.'/ldaplib.php');
// Get all contexts and look for first matching user
$ldap_contexts = explode(';', $ldap_contexts);
$ldap_pagedresults = ldap_paged_results_supported($this->get_config('ldap_version'));
- $ldap_cookie = '';
foreach ($ldap_contexts as $context) {
$context = trim($context);
if (empty($context)) {
continue;
}
+ $ldap_cookie = '';
$flat_records = array();
do {
if ($ldap_pagedresults) {
*/
public function unassign_role_from_user($userid, $roleid) {
global $DB;
- require_capability('moodle/role:assign', $this->context);
- $user = $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST);
- try {
- role_unassign($roleid, $user->id, $this->context->id, '', NULL);
- } catch (Exception $e) {
+ // Admins may unassign any role, others only those they could assign.
+ if (!is_siteadmin() and !array_key_exists($roleid, $this->get_assignable_roles())) {
if (defined('AJAX_SCRIPT')) {
- throw $e;
+ throw new moodle_exception('invalidrole');
}
return false;
}
+ $user = $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST);
+ $ras = $DB->get_records('role_assignments', array('contextid'=>$this->context->id, 'userid'=>$user->id, 'roleid'=>$roleid));
+ foreach ($ras as $ra) {
+ if ($ra->component) {
+ if (strpos($ra->component, 'enrol_') !== 0) {
+ continue;
+ }
+ if (!$plugin = enrol_get_plugin(substr($ra->component, 6))) {
+ continue;
+ }
+ if ($plugin->roles_protected()) {
+ continue;
+ }
+ }
+ role_unassign($ra->roleid, $ra->userid, $ra->contextid, $ra->component, $ra->itemid);
+ }
return true;
}
public function get_user_roles($userid) {
$roles = array();
$ras = get_user_roles($this->context, $userid, true, 'c.contextlevel DESC, r.sortorder ASC');
+ $plugins = $this->get_enrolment_plugins(false);
foreach ($ras as $ra) {
if ($ra->contextid != $this->context->id) {
if (!array_key_exists($ra->roleid, $roles)) {
if (array_key_exists($ra->roleid, $roles) && $roles[$ra->roleid] === false) {
continue;
}
- $roles[$ra->roleid] = ($ra->itemid == 0 and $ra->component === '');
+ $changeable = true;
+ if ($ra->component) {
+ $changeable = false;
+ if (strpos($ra->component, 'enrol_') === 0) {
+ $plugin = substr($ra->component, 6);
+ if (isset($plugins[$plugin])) {
+ $changeable = !$plugins[$plugin]->roles_protected();
+ }
+ }
+ }
+
+ $roles[$ra->roleid] = $changeable;
}
return $roles;
}
$userroles = $this->get_other_users($sort, $direction, $page, $perpage);
$roles = $this->get_all_roles();
+ $plugins = $this->get_enrolment_plugins(false);
$context = $this->get_context();
$now = time();
}
$a = new stdClass;
$a->role = $roles[$userrole->roleid]->localname;
- $changeable = ($userrole->component == '');
if ($contextid == $this->context->id) {
+ $changeable = true;
+ if ($userrole->component) {
+ $changeable = false;
+ if (strpos($userrole->component, 'enrol_') === 0) {
+ $plugin = substr($userrole->component, 6);
+ if (isset($plugins[$plugin])) {
+ $changeable = !$plugin[$plugin]->roles_protected();
+ }
+ }
+ }
$roletext = get_string('rolefromthiscourse', 'enrol', $a);
} else {
$changeable = false;
// Roles
$details['roles'] = array();
foreach ($this->get_user_roles($user->id) as $rid=>$rassignable) {
- $details['roles'][$rid] = array('text'=>$allroles[$rid]->localname, 'unchangeable'=>(!$rassignable || !isset($assignable[$rid])));
+ $unchangeable = !$rassignable;
+ if (!is_siteadmin() and !isset($assignable[$rid])) {
+ $unchangeable = true;
+ }
+ $details['roles'][$rid] = array('text'=>$allroles[$rid]->localname, 'unchangeable'=>$unchangeable);
}
// Users
$manager = new course_enrolment_manager($PAGE, $course, $filter);
$table = new course_enrolment_other_users_table($manager, $PAGE);
$PAGE->set_url('/enrol/otherusers.php', $manager->get_url_params()+$table->get_url_params());
+navigation_node::override_active_url(new moodle_url('/enrol/otherusers.php', array('id' => $id)));
$userdetails = array (
'picture' => false,
// get list of roles
$rolesoutput = '';
foreach ($roles as $roleid=>$role) {
- if ($canassign && !$role['unchangeable']) {
+ if ($canassign and (is_siteadmin() or isset($assignableroles[$roleid])) and !$role['unchangeable']) {
$strunassign = get_string('unassignarole', 'role', $role['text']);
$icon = html_writer::empty_tag('img', array('alt'=>$strunassign, 'src'=>$iconenrolremove));
$url = new moodle_url($pageurl, array('action'=>'unassign', 'role'=>$roleid, 'user'=>$userid));
$root = true;
}
- $row_count_offset = 0;
-
- if (empty($category_total_item) && !$this->moving) {
- $row_count_offset = -1;
- }
-
$levelclass = "level$level";
$courseclass = '';
$headercell->scope = 'row';
$headercell->attributes['title'] = $object->stripped_name;
$headercell->attributes['class'] = 'cell rowspan ' . $levelclass;
- $headercell->rowspan = $row_count+1+$row_count_offset;
+ $headercell->rowspan = $row_count + 1;
$row->cells[] = $headercell;
foreach ($this->columns as $column) {
'courseid' => new external_value(PARAM_INT, 'id of course'),
'name' => new external_value(PARAM_TEXT, 'multilang compatible name, course unique'),
'description' => new external_value(PARAM_RAW, 'grouping description text'),
- 'descriptionformat' => new external_format_value('descripiton', VALUE_DEFAULT)
+ 'descriptionformat' => new external_format_value('description', VALUE_DEFAULT)
)
), 'List of grouping object. A grouping has a courseid, a name and a description.'
)
$string['invaliduser'] = 'Invalid user';
$string['invaliduserid'] = 'Invalid user id';
$string['invaliduserfield'] = 'Invalid user field: {$a}';
+$string['invalidusername'] = 'The given username contains invalid characters';
$string['invalidxmlfile'] = '"{$a}" is not a valid XML file';
$string['iplookupfailed'] = 'Cannot find geo information about this IP address {$a}';
$string['iplookupprivate'] = 'Cannot display lookup of private IP address';
}\r
\r
function _unhtmlentities($string) {\r
+ return textlib::entities_to_utf8($string); // Moodle hack\r
$string = preg_replace('~&#x([0-9a-f]+);~ei', 'chr(hexdec("\\1"))', $string);\r
$string = preg_replace('~&#([0-9]+);~e', 'chr(\\1)', $string);\r
\r
* Modified config file to use moodle $CFG.
* Moved static files to /tinymce/ subfolder.
* MDL-25736 - French spellchecker fixes.
-
-Commits:
-https://github.com/moodle/custom-tinymce_spellchecker_php/commits/MOODLE_22_2.0.6b
+* Fix htmlentities conversion in GoogleSpell.php
$categoryids[] = $category->key;
}
}
- list($categoriessql, $params) = $DB->get_in_or_equal($categoryids, SQL_PARAMS_NAMED);
- $params['limit'] = (!empty($CFG->navcourselimit))?$CFG->navcourselimit:20;
- $sql = "SELECT cc.id, COUNT(c.id) AS coursecount
- FROM {course_categories} cc
- JOIN {course} c ON c.category = cc.id
- WHERE cc.id {$categoriessql}
- GROUP BY cc.id
- HAVING COUNT(c.id) > :limit";
- $excessivecategories = $DB->get_records_sql($sql, $params);
- foreach ($categories as &$category) {
- if (array_key_exists($category->key, $excessivecategories) && !$this->can_add_more_courses_to_category($category)) {
- $url = new moodle_url('/course/category.php', array('id'=>$category->key));
- $category->add(get_string('viewallcourses'), $url, self::TYPE_SETTING);
+ if ($categoryids) {
+ list($categoriessql, $params) = $DB->get_in_or_equal($categoryids, SQL_PARAMS_NAMED);
+ $params['limit'] = (!empty($CFG->navcourselimit))?$CFG->navcourselimit:20;
+ $sql = "SELECT cc.id, COUNT(c.id) AS coursecount
+ FROM {course_categories} cc
+ JOIN {course} c ON c.category = cc.id
+ WHERE cc.id {$categoriessql}
+ GROUP BY cc.id
+ HAVING COUNT(c.id) > :limit";
+ $excessivecategories = $DB->get_records_sql($sql, $params);
+ foreach ($categories as &$category) {
+ if (array_key_exists($category->key, $excessivecategories) && !$this->can_add_more_courses_to_category($category)) {
+ $url = new moodle_url('/course/category.php', array('id'=>$category->key));
+ $category->add(get_string('viewallcourses'), $url, self::TYPE_SETTING);
+ }
}
}
}
*
* @param stdClass $instance the instance of the source of the RSS feed
* @param string $sql the SQL used to produce the RSS feed
+ * @param array $params the parameters used in the SQL query
* @return string the name of the RSS file
*/
-function rss_get_file_name($instance, $sql) {
- return $instance->id.'_'.md5($sql);
+function rss_get_file_name($instance, $sql, $params = array()) {
+ if ($params) {
+ // If a parameters array is passed, then we want to
+ // serialize it and then concatenate it with the sql.
+ // The reason for this is to generate a unique filename
+ // for queries using the same sql but different parameters.
+ asort($parms);
+ $serializearray = serialize($params);
+ return $instance->id.'_'.md5($sql . $serializearray);
+ } else {
+ return $instance->id.'_'.md5($sql);
+ }
}
/**
* @return void
*/
public function test_entities_to_utf8() {
- $str = "Žluťoučký koníček";
- $this->assertSame(textlib::entities_to_utf8($str), "Žluťoučký koníček");
+ $str = "Žluťoučký koníček©"&<>§«";
+ $this->assertSame("Žluťoučký koníček©\"&<>§«", textlib::entities_to_utf8($str));
}
/**
* @return void
*/
public function test_utf8_to_entities() {
- $str = "Žluťoučký koníček";
- $this->assertSame(textlib::utf8_to_entities($str), "Žluťoučký koníček");
- $this->assertSame(textlib::utf8_to_entities($str, true), "Žluťoučký koníček");
+ $str = "Žluťoučký koníček©"&<>§«";
+ $this->assertSame("Žluťoučký koníček©"&<>§«", textlib::utf8_to_entities($str));
+ $this->assertSame("Žluťoučký koníček©"&<>§«", textlib::utf8_to_entities($str, true));
+ $str = "Žluťoučký koníček©"&<>§«";
+ $this->assertSame("Žluťoučký koníček©\"&<>§«", textlib::utf8_to_entities($str, false, true));
+ $this->assertSame("Žluťoučký koníček©\"&<>§«", textlib::utf8_to_entities($str, true, true));
}
/**
return $encoded;
}
+ /**
+ * Returns HTML entity transliteration table.
+ * @return array with (html entity => utf-8) elements
+ */
+ protected static function get_entities_table() {
+ static $trans_tbl = null;
+
+ // Generate/create $trans_tbl
+ if (!isset($trans_tbl)) {
+ if (version_compare(phpversion(), '5.3.4') < 0) {
+ $trans_tbl = array();
+ foreach (get_html_translation_table(HTML_ENTITIES) as $val=>$key) {
+ $trans_tbl[$key] = textlib::convert($val, 'ISO-8859-1', 'utf-8');
+ }
+
+ } else if (version_compare(phpversion(), '5.4.0') < 0) {
+ $trans_tbl = get_html_translation_table(HTML_ENTITIES, ENT_COMPAT, 'UTF-8');
+ $trans_tbl = array_flip($trans_tbl);
+
+ } else {
+ $trans_tbl = get_html_translation_table(HTML_ENTITIES, ENT_COMPAT | ENT_HTML401, 'UTF-8');
+ $trans_tbl = array_flip($trans_tbl);
+ }
+ }
+
+ return $trans_tbl;
+ }
+
/**
* Converts all the numeric entities &#nnnn; or &#xnnn; to UTF-8
* Original from laurynas dot butkus at gmail at:
* @param string $str input string
* @param boolean $htmlent convert also html entities (defaults to true)
* @return string encoded UTF-8 string
- *
- * NOTE: we could have used typo3 entities_to_utf8() here
- * but the direct alternative used runs 400% quicker
- * and uses 0.5Mb less memory, so, let's use it
- * (tested against 10^6 conversions)
*/
public static function entities_to_utf8($str, $htmlent=true) {
- static $trans_tbl; // Going to use static transliteration table
+ static $callback1 = null ;
+ static $callback2 = null ;
+
+ if (!$callback1 or !$callback2) {
+ $callback1 = create_function('$matches', 'return textlib::code2utf8(hexdec($matches[1]));');
+ $callback2 = create_function('$matches', 'return textlib::code2utf8($matches[1]);');
+ }
- // Replace numeric entities
- $result = preg_replace('~&#x([0-9a-f]+);~ei', 'textlib::code2utf8(hexdec("\\1"))', $str);
- $result = preg_replace('~&#([0-9]+);~e', 'textlib::code2utf8(\\1)', $result);
+ $result = (string)$str;
+ $result = preg_replace_callback('/&#x([0-9a-f]+);/i', $callback1, $result);
+ $result = preg_replace_callback('/&#([0-9]+);/', $callback2, $result);
// Replace literal entities (if desired)
if ($htmlent) {
- // Generate/create $trans_tbl
- if (!isset($trans_tbl)) {
- $trans_tbl = array();
- foreach (get_html_translation_table(HTML_ENTITIES) as $val=>$key) {
- $trans_tbl[$key] = utf8_encode($val);
- }
- }
+ $trans_tbl = self::get_entities_table();
+ // It should be safe to search for ascii strings and replace them with utf-8 here.
$result = strtr($result, $trans_tbl);
}
// Return utf8-ised string
* @return string converted string
*/
public static function utf8_to_entities($str, $dec=false, $nonnum=false) {
- // Avoid some notices from Typo3 code
- $oldlevel = error_reporting(E_PARSE);
+ static $callback = null ;
+
if ($nonnum) {
- $str = self::typo3()->entities_to_utf8((string)$str, true);
+ $str = self::entities_to_utf8($str, true);
}
+
+ // Avoid some notices from Typo3 code
+ $oldlevel = error_reporting(E_PARSE);
$result = self::typo3()->utf8_to_entities((string)$str);
+ error_reporting($oldlevel);
+
if ($dec) {
- $result = preg_replace('/&#x([0-9a-f]+);/ie', "'&#'.hexdec('$1').';'", $result);
+ if (!$callback) {
+ $callback = create_function('$matches', 'return \'&#\'.(hexdec($matches[1])).\';\';');
+ }
+ $result = preg_replace_callback('/&#x([0-9a-f]+);/i', $callback, $result);
}
- // Restore original debug level
- error_reporting($oldlevel);
+
return $result;
}
case FORMAT_WIKI:
// there should not be any of these any more!
$text = wikify_links($text);
- return strtr(strip_tags($text), array_flip(get_html_translation_table(HTML_ENTITIES)));
+ return textlib::entities_to_utf8(strip_tags($text), true);
break;
case FORMAT_HTML:
case FORMAT_MARKDOWN:
default:
$text = wikify_links($text);
- return strtr(strip_tags($text), array_flip(get_html_translation_table(HTML_ENTITIES)));
+ return textlib::entities_to_utf8(strip_tags($text), true);
break;
}
}
};
/**
+ * Deprecated since 2.5, will be removed in 2.7.
+ * Please don't use this function.
+ * Use the filemanager instead. (/lib/form/filemanager.js)
* This fucntion is called for each file picker on page.
*/
M.data_filepicker.init = function(Y, options) {
+ if (M.cfg.developerdebug) {
+ Y.log("You are using a deprecated function call (M.data_filepicker). Please look at rewriting your call to use M.form_filemanager");
+ }
options.formcallback = M.data_filepicker.callback;
if (!M.core_filepicker.instances[options.client_id]) {
M.core_filepicker.init(Y, options);
};
/**
+ * Deprecated since 2.5, will be removed in 2.7.
+ * Please don't use this function.
+ * Use the filemanager instead. (/lib/form/filemanager.js)
* This fucntion is called for each file picker on page.
*/
M.data_imagepicker.init = function(Y, options) {
+ if (M.cfg.developerdebug) {
+ Y.log("You are using a deprecated function call (M.data_imagepicker). Please look at rewriting your call to use M.form_filemanager");
+ }
options.formcallback = M.data_imagepicker.callback;
if (!M.core_filepicker.instances[options.client_id]) {
M.core_filepicker.init(Y, options);
require_once('../../config.php');
require_once('lib.php');
require_once("$CFG->libdir/rsslib.php");
+require_once("$CFG->libdir/form/filemanager.php");
$id = optional_param('id', 0, PARAM_INT); // course module id
$d = optional_param('d', 0, PARAM_INT); // database id
$html .= '<input type="hidden" name="field_'.$this->field->id.'_file" value="'.$itemid.'" />';
$options = new stdClass();
- $options->maxbytes = $this->field->param3;
+ $options->areamaxbytes = $this->field->param3;
+ $options->maxbytes = $this->field->param3;
+ $options->maxfiles = 1; // Limit to one file for the moment, this may be changed if requested as a feature in the future.
$options->itemid = $itemid;
$options->accepted_types = '*';
$options->return_types = FILE_INTERNAL;
$options->context = $PAGE->context;
- $fp = new file_picker($options);
- // print out file picker
- $html .= $OUTPUT->render($fp);
+ $fm = new form_filemanager($options);
+ // Print out file manager.
+
+ $output = $PAGE->get_renderer('core', 'files');
+ $html .= $output->render($fm);
$html .= '</fieldset>';
$html .= '</div>';
- $module = array('name'=>'data_filepicker', 'fullpath'=>'/mod/data/data.js', 'requires'=>array('core_filepicker'));
- $PAGE->requires->js_init_call('M.data_filepicker.init', array($fp->options), true, $module);
+ $module = array(
+ 'name'=>'form_filemanager',
+ 'fullpath'=>'/lib/form/filemanager.js',
+ 'requires' => array('core_filepicker', 'base', 'io-base', 'node',
+ 'json', 'core_dndupload', 'panel', 'resize-plugin', 'dd-plugin'),
+ 'strings' => array(
+ array('error', 'moodle'), array('info', 'moodle'), array('confirmdeletefile', 'repository'),
+ array('draftareanofiles', 'repository'), array('entername', 'repository'), array('enternewname', 'repository'),
+ array('invalidjson', 'repository'), array('popupblockeddownload', 'repository'),
+ array('unknownoriginal', 'repository'), array('confirmdeletefolder', 'repository'),
+ array('confirmdeletefilewithhref', 'repository'), array('confirmrenamefolder', 'repository'),
+ array('confirmrenamefile', 'repository')
+ )
+ );
+
+ $PAGE->requires->js_init_call('M.form_filemanager.init', array($fm->options), true, $module);
return $html;
}
$str = '<div title="'.s($this->field->description).'">';
$str .= '<fieldset><legend><span class="accesshide">'.$this->field->name.'</span></legend>';
+ $str .= '<noscript>';
if ($file) {
$src = file_encode_url($CFG->wwwroot.'/pluginfile.php/', $this->context->id.'/mod_data/content/'.$content->id.'/'.$file->get_filename());
$str .= '<img width="'.s($this->previewwidth).'" height="'.s($this->previewheight).'" src="'.$src.'" alt="" />';
}
+ $str .= '</noscript>';
$options = new stdClass();
+ $options->areamaxbytes = $this->field->param3;
$options->maxbytes = $this->field->param3;
+ $options->maxfiles = 1; // Only one picture permitted.
$options->itemid = $itemid;
$options->accepted_types = array('web_image');
$options->return_types = FILE_INTERNAL;
$options->filename = $file->get_filename();
$options->filepath = '/';
}
- $fp = new file_picker($options);
- $str .= $OUTPUT->render($fp);
+ $fm = new form_filemanager($options);
+ // Print out file manager.
+
+ $output = $PAGE->get_renderer('core', 'files');
+ $str .= $output->render($fm);
$str .= '<div class="mdl-left">';
$str .= '<input type="hidden" name="field_'.$this->field->id.'_file" value="'.$itemid.'" />';
$str .= '</fieldset>';
$str .= '</div>';
- $module = array('name'=>'data_imagepicker', 'fullpath'=>'/mod/data/data.js', 'requires'=>array('core_filepicker'));
- $PAGE->requires->js_init_call('M.data_imagepicker.init', array($fp->options), true, $module);
+ $module = array(
+ 'name'=>'form_filemanager',
+ 'fullpath'=>'/lib/form/filemanager.js',
+ 'requires' => array('core_filepicker', 'base', 'io-base', 'node',
+ 'json', 'core_dndupload', 'panel', 'resize-plugin', 'dd-plugin'),
+ 'strings' => array(
+ array('error', 'moodle'), array('info', 'moodle'), array('confirmdeletefile', 'repository'),
+ array('draftareanofiles', 'repository'), array('entername', 'repository'), array('enternewname', 'repository'),
+ array('invalidjson', 'repository'), array('popupblockeddownload', 'repository'),
+ array('unknownoriginal', 'repository'), array('confirmdeletefolder', 'repository'),
+ array('confirmdeletefilewithhref', 'repository'), array('confirmrenamefolder', 'repository'),
+ array('confirmrenamefile', 'repository')
+ )
+ );
+
+ $PAGE->requires->js_init_call('M.form_filemanager.init', array($fm->options), true, $module);
+
return $str;
}
$link = true;
} else {
$modcontext = context_module::instance($cm->id);
- $link = forum_user_can_post($forum, $discussion, $USER, $cm, $course, $modcontext);
+ $link = forum_user_can_see_discussion($forum, $discussion, $modcontext, $USER);
}
$discussion->forum = $forum->id;
}
//the sql that will retreive the data for the feed and be hashed to get the cache filename
- $sql = forum_rss_get_sql($forum, $cm);
+ list($sql, $params) = forum_rss_get_sql($forum, $cm);
// Hash the sql to get the cache file name.
- // If the forum is Q and A then we need to cache the files per user. This can
- // have a large impact on performance, so we want to only do it on this type of forum.
- if ($forum->type == 'qanda') {
- $filename = rss_get_file_name($forum, $sql . $USER->id);
- } else {
- $filename = rss_get_file_name($forum, $sql);
- }
+ $filename = rss_get_file_name($forum, $sql, $params);
$cachedfilepath = rss_get_file_full_name('mod_forum', $filename);
//Is the cache out of date?
}
//if the cache is more than 60 seconds old and there's new stuff
$dontrecheckcutoff = time()-60;
- if ( $dontrecheckcutoff > $cachedfilelastmodified && forum_rss_newstuff($forum, $cm, $cachedfilelastmodified)) {
+ if ($dontrecheckcutoff > $cachedfilelastmodified && forum_rss_newstuff($forum, $cm, $cachedfilelastmodified)) {
//need to regenerate the cached version
- $result = forum_rss_feed_contents($forum, $sql, $modcontext);
+ $result = forum_rss_feed_contents($forum, $sql, $params, $modcontext);
if (!empty($result)) {
$status = rss_save_file('mod_forum',$filename,$result);
}
function forum_rss_newstuff($forum, $cm, $time) {
global $DB;
- $sql = forum_rss_get_sql($forum, $cm, $time);
+ list($sql, $params) = forum_rss_get_sql($forum, $cm, $time);
+ if ($DB->count_records_sql($sql, $params) > 0) {
+ return true;
+ }
- $recs = $DB->get_records_sql($sql, null, 0, 1);//limit of 1. If we get even 1 back we have new stuff
- return ($recs && !empty($recs));
+ return false;
}
/**
* @return string the SQL query to be used to get the Discussion/Post details from the forum table of the database
*/
function forum_rss_get_sql($forum, $cm, $time=0) {
- $sql = null;
-
- if (!empty($forum->rsstype)) {
- if ($forum->rsstype == 1) { //Discussion RSS
- $sql = forum_rss_feed_discussions_sql($forum, $cm, $time);
- } else { //Post RSS
- $sql = forum_rss_feed_posts_sql($forum, $cm, $time);
- }
+ if ($forum->rsstype == 1) { // Discussion RSS
+ return forum_rss_feed_discussions_sql($forum, $cm, $time);
+ } else { // Post RSS
+ return forum_rss_feed_posts_sql($forum, $cm, $time);
}
-
- return $sql;
}
/**
$modcontext = null;
$now = round(time(), -2);
- $params = array($cm->instance);
+ $params = array();
$modcontext = context_module::instance($cm->id);
}
}
- //do we only want new posts?
+ // Do we only want new posts?
if ($newsince) {
- $newsince = " AND p.modified > '$newsince'";
+ $params['newsince'] = $newsince;
+ $newsince = " AND p.modified > :newsince";
} else {
$newsince = '';
}
- //get group enforcing SQL
- $groupmode = groups_get_activity_groupmode($cm);
+ // Get group enforcing SQL.
+ $groupmode = groups_get_activity_groupmode($cm);
$currentgroup = groups_get_activity_group($cm);
- $groupselect = forum_rss_get_group_sql($cm, $groupmode, $currentgroup, $modcontext);
+ list($groupselect, $groupparams) = forum_rss_get_group_sql($cm, $groupmode, $currentgroup, $modcontext);
- if ($groupmode && $currentgroup) {
- $params['groupid'] = $currentgroup;
- }
+ // Add the groupparams to the params array.
+ $params = array_merge($params, $groupparams);
$forumsort = "d.timemodified DESC";
$postdata = "p.id AS postid, p.subject, p.created as postcreated, p.modified, p.discussion, p.userid, p.message as postmessage, p.messageformat AS postformat, p.messagetrust AS posttrust";
WHERE d.forum = {$forum->id} AND p.parent = 0
$timelimit $groupselect $newsince
ORDER BY $forumsort";
- return $sql;
+ return array($sql, $params);
}
/**
function forum_rss_feed_posts_sql($forum, $cm, $newsince=0) {
$modcontext = context_module::instance($cm->id);
- //get group enforcement SQL
- $groupmode = groups_get_activity_groupmode($cm);
+ // Get group enforcement SQL.
+ $groupmode = groups_get_activity_groupmode($cm);
$currentgroup = groups_get_activity_group($cm);
+ $params = array();
- $groupselect = forum_rss_get_group_sql($cm, $groupmode, $currentgroup, $modcontext);
+ list($groupselect, $groupparams) = forum_rss_get_group_sql($cm, $groupmode, $currentgroup, $modcontext);
- if ($groupmode && $currentgroup) {
- $params['groupid'] = $currentgroup;
- }
+ // Add the groupparams to the params array.
+ $params = array_merge($params, $groupparams);
- //do we only want new posts?
+ // Do we only want new posts?
if ($newsince) {
- $newsince = " AND p.modified > '$newsince'";
+ $params['newsince'] = $newsince;
+ $newsince = " AND p.modified > :newsince";
} else {
$newsince = '';
}
$groupselect
ORDER BY p.created desc";
- return $sql;
+ return array($sql, $params);
}
/**
*/
function forum_rss_get_group_sql($cm, $groupmode, $currentgroup, $modcontext=null) {
$groupselect = '';
+ $params = array();
if ($groupmode) {
if ($groupmode == VISIBLEGROUPS or has_capability('moodle/site:accessallgroups', $modcontext)) {
$params['groupid'] = $currentgroup;
}
} else {
- //seprate groups without access all
+ // Separate groups without access all.
if ($currentgroup) {
$groupselect = "AND (d.groupid = :groupid OR d.groupid = -1)";
$params['groupid'] = $currentgroup;
}
}
- return $groupselect;
+ return array($groupselect, $params);
}
/**
* It returns false if something is wrong
*
* @param stdClass $forum the forum object
- * @param string $sql The SQL used to retrieve the contents from the database
+ * @param string $sql the SQL used to retrieve the contents from the database
+ * @param array $params the SQL parameters used
* @param object $context the context this forum relates to
* @return bool|string false if the contents is empty, otherwise the contents of the feed is returned
*
* @Todo MDL-31129 implement post attachment handling
*/
-function forum_rss_feed_contents($forum, $sql) {
+function forum_rss_feed_contents($forum, $sql, $params, $context) {
global $CFG, $DB, $USER;
-
$status = true;
- $params = array();
- //$params['forumid'] = $forum->id;
$recs = $DB->get_recordset_sql($sql, $params, 0, $forum->rssarticles);
//set a flag. Are we displaying discussions or posts?
if (!$cm = get_coursemodule_from_instance('forum', $forum->id, $forum->course)) {
print_error('invalidcoursemodule');
}
- $context = context_module::instance($cm->id);
$formatoptions = new stdClass();
$items = array();
$params[] = "cmi.interactions_%.id";
$rs = $DB->get_recordset_select("scorm_scoes_track", $select, $params, 'element');
$keywords = array("cmi.interactions_", ".id");
- foreach ($rs as $record) {
- $num = trim(str_ireplace($keywords, '', $record->element));
- if (is_numeric($num) && $num > $count) {
- $count = $num;
+ if ($rs->valid()) {
+ // Done as interactions start at 0 (do only if we have something to report).
+ $count++;
+ foreach ($rs as $record) {
+ $num = trim(str_ireplace($keywords, '', $record->element));
+ if (is_numeric($num) && $num > $count) {
+ $count = $num;
+ }
}
}
- //done as interactions start at 0
- $count++;
$rs->close(); // closing recordset
return $count;
}
*/
class qformat_learnwise extends qformat_default {
- function provide_import() {
+ public function provide_import() {
return true;
}
+ public function export_file_extension() {
+ return '.xml';
+ }
+
protected function readquestions($lines) {
$questions = array();
$currentquestion = array();
return $questions;
}
- function readquestion($lines) {
+ protected function readquestion($lines) {
$text = implode(' ', $lines);
- $text = str_replace(array('\t','\n','\r','\''), array('','','','\\\''), $text);
+ $text = str_replace(array('\t','\n','\r'), array('','',''), $text);
$startpos = strpos($text, '<question type');
$endpos = strpos($text, '</question>');
preg_match("/<question type=[\"\']([^\"\']+)[\"\']>/i", $text, $matches);
$type = strtolower($matches[1]); // multichoice or multianswerchoice
- $questiontext = $this->unhtmlentities($this->stringbetween($text, '<text>', '</text>'));
- $questionhint = $this->unhtmlentities($this->stringbetween($text, '<hint>', '</hint>'));
+ $questiontext = textlib::entities_to_utf8($this->stringbetween($text, '<text>', '</text>'));
+ $questionhint = textlib::entities_to_utf8($this->stringbetween($text, '<hint>', '</hint>'));
$questionaward = $this->stringbetween($text, '<award>', '</award>');
$optionlist = $this->stringbetween($text, '<answer>', '</answer>');
if ($type == 'multichoice') {
foreach ($optionlist as $option) {
+ if (trim($option) === '') {
+ continue;
+ }
$correct = $this->stringbetween($option, ' correct="', '">');
$answer = $this->stringbetween($option, '">', '</option>');
$optionscorrect[$n] = $correct;
- $optionstext[$n] = $this->unhtmlentities($answer);
+ $optionstext[$n] = textlib::entities_to_utf8($answer);
++$n;
}
} else if ($type == 'multianswerchoice') {
$optionsaward = array();
foreach ($optionlist as $option) {
+ if (trim($option) === '') {
+ continue;
+ }
preg_match("/correct=\"([^\"]*)\"/i", $option, $correctmatch);
preg_match("/award=\"([^\"]*)\"/i", $option, $awardmatch);
$answer = $this->stringbetween($option, '">', '</option>');
$optionscorrect[$n] = $correct;
- $optionstext[$n] = $this->unhtmlentities($answer);
+ $optionstext[$n] = textlib::entities_to_utf8($answer);
$optionsaward[$n] = $award;
++$n;
}
$question = $this->defaultquestion();
$question->qtype = 'multichoice';
$question->name = $this->create_default_question_name($questiontext, get_string('questionname', 'question'));
+ $this->add_blank_combined_feedback($question);
$question->questiontext = $questiontext;
+ $question->questiontextformat = FORMAT_HTML;
$question->single = ($type == 'multichoice') ? 1 : 0;
- $question->feedback[] = '';
$question->fraction = array();
$question->answer = array();
for ($n = 0; $n < count($optionstext); ++$n) {
if ($optionstext[$n]) {
- if (!isset($numcorrect)) { // single answer
+ if (!isset($numcorrect)) {
+ // Single answer.
if ($optionscorrect[$n] == 'yes') {
$fraction = (int) $questionaward;
} else {
$fraction = 0;
}
- } else { // mulitple answers
+ } else {
+ // Multiple answers.
if ($optionscorrect[$n] == 'yes') {
$fraction = $optionsaward[$n] / $totalaward;
} else {
}
}
$question->fraction[] = $fraction;
- $question->answer[] = $optionstext[$n];
- $question->feedback[] = ''; // no feedback in this type
+ $question->answer[] = array('text' => $optionstext[$n], 'format' => FORMAT_HTML);
+ $question->feedback[] = array('text' => '', 'format' => FORMAT_HTML); // No feedback in this type.
}
}
return $question;
}
- function stringbetween($text, $start, $end) {
+ /**
+ * Extract the substring of $text between $start and $end.
+ * @param string $text text to analyse.
+ * @param string $start opening delimiter.
+ * @param string $end closing delimiter.
+ * @return string the requested substring.
+ */
+ protected function stringbetween($text, $start, $end) {
$startpos = strpos($text, $start) + strlen($start);
$endpos = strpos($text, $end);
return substr($text, $startpos, $endpos - $startpos);
}
}
-
- function unhtmlentities($string) {
- $transtable = get_html_translation_table(HTML_ENTITIES);
- $transtable = array_flip($transtable);
- return strtr($string, $transtable);
- }
-
}
-
-
*/
$string['pluginname'] = 'Learnwise format';
-$string['plugidnname_help'] = 'This format enables the import of multiple choice questions saved in Learnwise\'s XML format.';
+$string['pluginname_help'] = 'This format enables the import of multiple choice questions saved in Learnwise\'s XML format.';