Compare commits

...

86 Commits

Author SHA1 Message Date
Eloy Lafuente (stronk7) 572729aaa5 on-demand release 1.9.19+ 2013-05-13 12:30:23 +02:00
Dan Poltawski bfae08a46d Merge branch 'mdl19_MDL-35958' of git://github.com/danmarsden/moodle into MOODLE_19_STABLE 2013-05-06 11:01:20 +01:00
Adrian Greeve 3d1141b0ee MDL-38225 - data: Database entries are now linked correctly.
This was a regression that was fixed in the 2.x versions but not 1.9
2013-02-27 08:45:53 +08:00
Dan Poltawski 0e2be52d69 weekly release 1.9.19+ 2013-01-25 15:59:35 +08:00
Eloy Lafuente (stronk7) 237f06b3d0 weekly release 1.9.19+ 2013-01-11 22:16:54 +01:00
Eloy Lafuente (stronk7) 4493e62d1d weekly release 1.9.19+ 2013-01-11 12:27:34 +01:00
Eloy Lafuente (stronk7) cb8004dabd weekly release 1.9.19+ 2012-12-20 21:08:53 +01:00
Paul Nicholls a292ea9761 MDL-27619: Prevent teachers from turning course Outcomes into site-wide ones
Similar to the issue which allowed teachers to create site-wide scales by editing a course-specific scale (MDL-24682), teachers could also promote a course-specific scale to a site-wide (standard) by editing it.  As with MDL-24682, removing the course ID check (leaving just the capability check) prevents this unauthorised creation of site-wide (standard) outcomes.
2012-11-27 10:41:14 +13:00
Eloy Lafuente (stronk7) 1033e1e2f2 weekly release 1.9.19+ 2012-11-09 19:31:54 +01:00
Dan Poltawski b52204405e weekly release 1.9.19+ 2012-11-09 18:01:40 +08:00
Dan Poltawski 342d7cf4bf Merge branch 'MDL-36346_19' of git://github.com/pauln/moodle into MOODLE_19_STABLE 2012-11-06 16:37:01 +08:00
Paul Nicholls 72225da176 MDL-36346 - YUI2 SWF vulnerability 2012-11-06 14:09:01 +13:00
Dan Marsden 9b4660e0ba MDL-35958 mod_data: backport of MDL-34448 members of seperate groups can see database entries for other groups. 2012-10-15 11:31:52 +13:00
Petr Škoda 6ab3a85252 MDL-35469 fix Gecko based browser checks
The problem is that latest firefox versions stopped using dates because they lost the meaning over the time.
2012-10-09 15:59:03 +02:00
Eloy Lafuente (stronk7) 1c2857e2e4 weekly release 1.9.19+ 2012-08-31 11:32:51 +02:00
Eloy Lafuente (stronk7) 224a8644b0 weekly release 1.9.19+ 2012-08-23 19:23:19 +02:00
Eloy Lafuente (stronk7) 41246701c2 weekly release 1.9.19+ 2012-08-16 17:23:39 +02:00
Eloy Lafuente (stronk7) 15d529c1c3 weekly release 1.9.19+ 2012-08-09 20:49:25 +02:00
Aparup Banerjee 905ff1fc36 weekly release 1.9.19+ 2012-07-26 14:42:17 +08:00
Dan Poltawski af72d273df weekly release 1.9.19+ 2012-07-19 13:49:10 +08:00
Dan Poltawski 8907e85ab5 weekly release 1.9.19+ 2012-07-12 16:09:38 +08:00
Sam Hemelryk 9016f02312 Moodle 1.9.19 release 2012-07-06 11:30:14 +12:00
Sam Hemelryk 2b190b1359 weekly release 1.9.18+ 2012-07-06 10:10:27 +12:00
Eloy Lafuente (stronk7) 007182c2ae weekly release 1.9.18+ 2012-07-02 00:49:21 +02:00
Eloy Lafuente (stronk7) aeabf66c16 weekly release 1.9.18+ 2012-06-24 18:32:30 +02:00
Eloy Lafuente (stronk7) 7e2eb109ee weekly release 1.9.18+ 2012-06-15 20:25:45 +02:00
Eloy Lafuente (stronk7) ef2a66a993 weekly release 1.9.18+ 2012-06-12 02:57:49 +02:00
David Monllaó 6b1280f163 MDL-31823 - Remote hosts users created via mnet enrolments marked as confirmed 2012-06-04 10:38:46 +02:00
Eloy Lafuente (stronk7) 3286ed2048 weekly release 1.9.18+ 2012-06-01 09:46:19 +02:00
Eloy Lafuente (stronk7) f19f76ae9a weekly release 1.9.18+ 2012-05-25 12:47:48 +02:00
Dan Poltawski e1d726afcf Merge branch 'w21_MDL-28676_m19_mysqli' of git://github.com/skodak/moodle into MOODLE_19_STABLE 2012-05-25 16:38:31 +08:00
Gordon Bateson ad69341954 CONTRIB-3662 Hotpot: fix fatal error during restore and general tidy up of spacing 2012-05-24 11:52:00 +08:00
Petr Skoda ef69fa6e29 MDL-28676 add hack mysqli php ext requirement for upgrades to 2.x
The mysql extension is not supported in Moodle 2.x, this hack should inform admins that they must add mysqli support before doing 2.x upgrades.
2012-05-19 18:58:33 +02:00
Eloy Lafuente (stronk7) c56ff4a8f7 weekly release 1.9.18+ 2012-05-19 12:20:58 +02:00
Gordon Bateson bb2714e517 CONTRIB-3469 - latest version of the HotPot module. 2012-05-17 10:30:58 +08:00
Adrian Greeve 36c45da5ce MDL-32126 - data - Improvements in the advanced search code. 2012-05-14 08:36:33 +08:00
Eloy Lafuente (stronk7) 628d7c0f9b Moodle release 1.9.18 2012-05-12 03:19:00 +02:00
Eloy Lafuente (stronk7) e9771fda98 weekly release 1.9.17+ 2012-05-11 12:15:18 +02:00
Dan Poltawski a9375cc95d Merge branch 'MDL-18335b_m19' of git://github.com/rwijaya/moodle into MOODLE_19_STABLE 2012-05-07 15:32:53 +08:00
Eloy Lafuente (stronk7) be0f5bf384 weekly release 1.9.17+ 2012-05-04 13:14:11 +02:00
Rossiani Wijaya 4928e13799 MDL-18335 calendar event: fixed role capability checking to create new event 2012-04-30 17:07:15 +08:00
Eloy Lafuente (stronk7) ad964b8a7b weekly release 1.9.17+ 2012-04-27 12:51:26 +02:00
Dan Poltawski a2624c32c2 weekly release 1.9.17+ 2012-04-19 17:51:51 +08:00
Sam Hemelryk 96d8c696ce Merge branch 'm19_MDL-32388' of git://github.com/danmarsden/moodle into MOODLE_19_STABLE 2012-04-16 12:22:50 +12:00
Dan Poltawski 0bbd045329 weekly release 1.9.17+ 2012-04-12 13:22:59 +08:00
Dan Marsden 6db00e4208 MDL-32388 SCORM: Fix chrome pop-ups 2012-04-11 21:10:35 +12:00
Rajesh Taneja db52f45c68 MDL-31746 calendar: Fixed up validation inconsistencies when creating/editing an event 2012-04-10 17:50:58 +12:00
David Mudrak 516878be1e MDL-24403 Fixing the print_error() calls to use the existing string 2012-04-06 11:22:18 +02:00
Yevhenii Vlasenko cf81547d49 MDL-24403 Adding a missing error string 2012-04-06 11:21:40 +02:00
Aparup Banerjee 58be0534b2 weekly release 1.9.17+ 2012-04-05 16:51:44 +08:00
Eloy Lafuente (stronk7) 09f011a628 weekly release 1.9.17+ 2012-03-29 13:21:26 +02:00
Dan Poltawski a30670f7b1 Revert "MDL-31746 calendar: insufficient parameter cleaning"
This reverts commit b0b228f7b9.
2012-03-29 12:20:37 +08:00
Ciaran Irvine b0b228f7b9 MDL-31746 calendar: insufficient parameter cleaning 2012-03-28 14:48:16 +08:00
Dan Poltawski 2763a7d713 Revert "MDL-31746 calendar: insufficient parameter cleaning"
This reverts commit f253646408.
2012-03-28 14:46:42 +08:00
Ciaran Irvine f253646408 MDL-31746 calendar: insufficient parameter cleaning 2012-03-26 23:23:18 +08:00
Dan Poltawski 7d20a8a05c Revert "MDL-31746 calendar: insufficient parameter cleaning"
Potential SQL injection with this solution

This reverts commit 47013fc0bb.
2012-03-26 23:11:30 +08:00
Ciaran Irvine 47013fc0bb MDL-31746 calendar: insufficient parameter cleaning
Reviewed-by: Alastair Munro <alastair.munro@totaralms.com>
Signed-off-by: Dan Poltawski <dan@moodle.com>
2012-03-26 13:57:11 +08:00
Rajesh Taneja 038131c8b5 MDL-31745 blog: Fixed up encoding issue within blog 2012-03-26 11:54:01 +13:00
Sam Hemelryk 8925a12934 weekly release 1.9.17+ 2012-03-23 12:16:58 +13:00
Eloy Lafuente (stronk7) 83668c6efa weekly release 1.9.17+ 2012-03-15 11:50:41 +01:00
Eloy Lafuente (stronk7) 86e74d3eaf Moodle release 1.9.17 2012-03-11 15:55:59 +01:00
Eloy Lafuente (stronk7) 076b2ce86c weekly release 1.9.16+ 2012-03-09 11:16:53 +01:00
Eloy Lafuente (stronk7) b3391165f1 Merge branch 'wip-MDL-31248-MOODLE_19_STABLE-v3' of git://github.com/abgreeve/moodle into MOODLE_19_STABLE 2012-03-09 09:49:52 +01:00
Eloy Lafuente (stronk7) cf9b51f4f1 Revert "MDL-31248 - lib - Alteration to the rc4encrypt function to allow for old password use."
This reverts commit f8adbd6a02.
2012-03-09 09:40:40 +01:00
Eloy Lafuente (stronk7) f4f2b26ec5 Revert "MDL-31248 - lib - prevent moodle_strtolower() silent discard to lead to false-correct usernames"
This reverts commit c67bc65cbe.
2012-03-09 09:40:38 +01:00
Eloy Lafuente (stronk7) 281afcd067 Revert "MDL-31248 - lib - Gah, erroneus condition fixed."
This reverts commit e85a54d931.
2012-03-09 09:40:32 +01:00
Adrian Greeve b48d546c97 MDL-31248 - lib - Retaining the old password key and creating a new cookie prefix. 2012-03-09 13:35:22 +08:00
Eloy Lafuente (stronk7) e85a54d931 MDL-31248 - lib - Gah, erroneus condition fixed.
For sure that leaded to accept anything as valid username
for cookies in 19_STABLE. That explains why garbled username were
being transformed into "invented" usernames, instead of blank.
2012-03-08 12:27:44 +01:00
Eloy Lafuente (stronk7) c67bc65cbe MDL-31248 - lib - prevent moodle_strtolower() silent discard to lead to false-correct usernames 2012-03-08 11:42:13 +01:00
Adrian Greeve f8adbd6a02 MDL-31248 - lib - Alteration to the rc4encrypt function to allow for old password use. 2012-03-08 08:15:45 +08:00
Eloy Lafuente (stronk7) 2c39e251b4 weekly release 1.9.16+ 2012-03-01 11:34:39 +01:00
Eloy Lafuente (stronk7) cd20b15196 weekly release 1.9.16+ 2012-02-23 11:41:24 +01:00
Eloy Lafuente (stronk7) a364ab036c weekly release 1.9.16+ 2012-02-17 01:53:52 +01:00
Eloy Lafuente (stronk7) 46d0e6fb17 MDL-25185 - data - whitespace fixes 2012-02-13 16:20:20 +01:00
Sam Hemelryk 7eb1327487 Merge branch 'wip-MDL-25185-MOODLE_19_STABLE' of git://github.com/abgreeve/moodle into MOODLE_19_STABLE 2012-02-13 17:34:09 +13:00
Eloy Lafuente (stronk7) f5dc0e4110 weekly release 1.9.16+ 2012-02-13 01:21:39 +01:00
Adrian Greeve 312ada2856 MDL-25185 - data - Allowing data from the database to be exported according to group roles. 2012-02-03 07:49:27 +08:00
Eloy Lafuente (stronk7) 4f87a0dccc weekly release 1.9.16+ 2012-02-02 12:16:03 +01:00
Eloy Lafuente (stronk7) 2726791626 weekly release 1.9.16+ 2012-01-27 02:24:07 +01:00
Eloy Lafuente (stronk7) 8db39dc10a weekly release 1.9.16+ 2012-01-19 13:31:02 +01:00
Eloy Lafuente (stronk7) ebd57374cb Merge branch 'w03_MDL-31213_m19_attributesmess' of git://github.com/skodak/moodle into MOODLE_19_STABLE 2012-01-17 12:38:56 +01:00
Petr Skoda c444939ec7 MDL-31213 fix incorrect modifications of quickforms attributes 2012-01-17 11:17:35 +01:00
Tim Gus bc6e8366a9 MDL-31055 backport disabledIf fix from 2.0. (MDL-27045) 2012-01-16 15:22:21 +08:00
Eloy Lafuente (stronk7) 09249fe5c9 weekly release 1.9.16+ 2012-01-12 11:29:47 +01:00
Eloy Lafuente (stronk7) 863b49bd9c Merge branch 'MDL-29294_19' of git://github.com/timhunt/moodle into MOODLE_19_STABLE 2012-01-08 22:59:52 +01:00
Tim Hunt 4d06e61a53 MDL-29294 qtype match restore problem on Oracle. 2011-12-28 11:44:51 +00:00
43 changed files with 1322 additions and 211 deletions
+5 -6
View File
@@ -672,7 +672,7 @@
$querystring = '';
foreach($_GET as $var => $val) {
$var = clean_param($var, PARAM_ALPHANUM); // See MDL-22631
$val = clean_param($val, PARAM_CLEAN);
$val = urlencode(clean_param($val, PARAM_CLEAN));
if(!$first) {
$first = true;
if ($var != 'filterselect' && $var != 'filtertype') {
@@ -683,13 +683,13 @@
}
} else {
if ($var != 'filterselect' && $var != 'filtertype') {
$querystring .= '&amp;'.$var.'='.$val;
$querystring .= '&'.$var.'='.$val;
$hasparam = true;
}
}
}
if (isset($hasparam)) {
$querystring .= '&amp;';
$querystring .= '&';
} else {
$querystring = '?';
}
@@ -697,9 +697,8 @@
$querystring = '?';
}
return strip_querystring(qualified_me()) . $querystring. 'filtertype='.
$filtertype.'&amp;filterselect='.$filterselect.'&amp;';
return s(strip_querystring(qualified_me()) . $querystring. 'filtertype='.
$filtertype.'&filterselect='.$filterselect.'&', true);
}
/**
+73 -44
View File
@@ -103,6 +103,7 @@
}
$form = null;
$err = array();
switch($action) {
case 'delete':
@@ -129,23 +130,7 @@
}
if($form = data_submitted() and confirm_sesskey()) {
$form->name = clean_param(strip_tags($form->name,'<lang><span>'), PARAM_CLEAN);
$form->timestart = make_timestamp($form->startyr, $form->startmon, $form->startday, $form->starthr, $form->startmin);
if($form->duration == 1) {
$form->timeduration = make_timestamp($form->endyr, $form->endmon, $form->endday, $form->endhr, $form->endmin) - $form->timestart;
if($form->timeduration < 0) {
$form->timeduration = 0;
}
}
else if($form->duration == 2) {
$form->timeduration = $form->minutes * MINSECS;
}
else {
$form->timeduration = 0;
}
// validate form and set error if any.
validate_form($form, $err);
if (count($err) == 0) {
@@ -194,27 +179,13 @@
$title = get_string('newevent', 'calendar');
$form = data_submitted();
if(!empty($form) && !empty($form->name) && confirm_sesskey()) {
$form->name = clean_text(strip_tags($form->name, '<lang><span>'));
$form->timestart = make_timestamp($form->startyr, $form->startmon, $form->startday, $form->starthr, $form->startmin);
if($form->duration == 1) {
$form->timeduration = make_timestamp($form->endyr, $form->endmon, $form->endday, $form->endhr, $form->endmin) - $form->timestart;
if($form->timeduration < 0) {
$form->timeduration = 0;
}
}
else if ($form->duration == 2) {
$form->timeduration = $form->minutes * MINSECS;
}
else {
$form->timeduration = 0;
}
if(!calendar_add_event_allowed($form)) {
error('You are not authorized to do this');
}
// validate form and set error if any.
validate_form($form, $err);
if (count($err) == 0) {
if (!calendar_add_event_allowed($form)) {
error('You are not authorized to do this');
}
$form->timemodified = time();
/// Get the event id for the log record.
@@ -568,11 +539,44 @@
function validate_form(&$form, &$err) {
$cleanform = new stdClass();
//first clean the form values
$cleanform->name = clean_param(strip_tags(trim($form->name), '<lang><span>'),PARAM_CLEAN);
$cleanform->description = addslashes(clean_param($form->description, PARAM_CLEANHTML));
$cleanform->duration = clean_param($form->duration, PARAM_INT);
$cleanform->startmon = clean_param($form->startmon, PARAM_INT);
$cleanform->startday = clean_param($form->startday, PARAM_INT);
$cleanform->startyr = clean_param($form->startyr, PARAM_INT);
$cleanform->starthr = clean_param($form->starthr, PARAM_INT);
$cleanform->startmin = clean_param($form->startmin, PARAM_INT);
$cleanform->endmon = clean_param($form->endmon, PARAM_INT);
$cleanform->endday = clean_param($form->endday, PARAM_INT);
$cleanform->endyr = clean_param($form->endyr, PARAM_INT);
$cleanform->endhr = clean_param($form->endhr, PARAM_INT);
$cleanform->endmin = clean_param($form->endmin, PARAM_INT);
$cleanform->minutes = clean_param($form->minutes, PARAM_INT);
$cleanform->courseid = clean_param($form->courseid, PARAM_INT);
$cleanform->format = clean_param($form->format, PARAM_INT);
$cleanform->course = clean_param($form->course, PARAM_INT);
$cleanform->action = clean_param($form->action, PARAM_ALPHA);
$form->name = trim($form->name);
$form->description = trim($form->description);
// These values are only required for new event.
if ($cleanform->action === 'new') {
$cleanform->repeat = clean_param($form->repeat, PARAM_INT);
$cleanform->repeats = clean_param($form->repeats, PARAM_INT);
$cleanform->groupid = clean_param($form->groupid, PARAM_INT);
$cleanform->userid = clean_param($form->userid, PARAM_INT);
$cleanform->modulename = clean_param($form->modulename, PARAM_SAFEDIR);
$cleanform->eventtype = clean_param($form->eventtype, PARAM_ALPHA);
$cleanform->instance = clean_param($form->instance, PARAM_INT);
$cleanform->type = clean_param($form->type, PARAM_ALPHA);
} else {
$cleanform->id = clean_param($form->id, PARAM_INT);
}
// set form with clean and valid values only.
$form = $cleanform;
if(empty($form->name)) {
if (empty($form->name)) {
$err['name'] = get_string('errornoeventname', 'calendar');
}
/* Allow events without a description
@@ -580,28 +584,53 @@ function validate_form(&$form, &$err) {
$err['description'] = get_string('errornodescription', 'calendar');
}
*/
if(!checkdate($form->startmon, $form->startday, $form->startyr)) {
if (!checkdate($form->startmon, $form->startday, $form->startyr)) {
$err['timestart'] = get_string('errorinvaliddate', 'calendar');
}
if($form->duration == 2 and !checkdate($form->endmon, $form->endday, $form->endyr)) {
if ($form->duration == 1 and !checkdate($form->endmon, $form->endday, $form->endyr)) {
$err['timeduration'] = get_string('errorinvaliddate', 'calendar');
}
if($form->duration == 2 and !($form->minutes > 0 and $form->minutes < 1000)) {
if ($form->duration == 2 and !($form->minutes > 0 and $form->minutes < 1000)) {
$err['minutes'] = get_string('errorinvalidminutes', 'calendar');
}
if (!empty($form->repeat) and !($form->repeats > 1 and $form->repeats < 100)) {
$err['repeats'] = get_string('errorinvalidrepeats', 'calendar');
}
if(!empty($form->courseid)) {
// set start time and duration
$form->timestart = make_timestamp($form->startyr, $form->startmon, $form->startday, $form->starthr, $form->startmin);
if ($form->duration == 1) {
$form->timeduration = make_timestamp($form->endyr, $form->endmon, $form->endday, $form->endhr, $form->endmin) - $form->timestart;
// Duration should be set for time in future.
if ($form->timeduration <= 0) {
$err['timeduration'] = get_string('errorinvaliddate', 'calendar');
$form->timeduration = 0;
}
}
else if ($form->duration == 2) {
$form->timeduration = $form->minutes * MINSECS;
}
else {
$form->timeduration = 0;
}
if (!empty($form->courseid)) {
// Timestamps must be >= course startdate
$course = get_record('course', 'id', $form->courseid);
if($course === false) {
if ($course === false) {
error('Event belongs to invalid course');
}
else if($form->timestart < $course->startdate) {
$err['timestart'] = get_string('errorbeforecoursestart', 'calendar');
}
}
if (!empty($form->modulename)) {
// Check that passed modulename actually exists (possible SQL Injection route)
$module = get_record('modules', 'name', $form->modulename);
if ($module === false) {
error('Invalid module name');
}
}
}
function calendar_add_event_allowed($event) {
+1
View File
@@ -1582,6 +1582,7 @@ function calendar_get_allowed_types(&$allowed) {
if(!empty($SESSION->cal_course_referer) && $SESSION->cal_course_referer != SITEID) {
$course = get_record('course', 'id', $SESSION->cal_course_referer);
$coursecontext = get_context_instance(CONTEXT_COURSE, $SESSION->cal_course_referer);
$allowed->user = has_capability('moodle/calendar:manageownentries', $coursecontext);
if(has_capability('moodle/calendar:manageentries', $coursecontext)) {
$allowed->courses = array($course->id => 1);
+1
View File
@@ -315,6 +315,7 @@ class enrolment_plugin_mnet {
$userrecord->firstname = addslashes($user['firstname']);
$userrecord->lastname = addslashes($user['lastname']);
$userrecord->mnethostid = $MNET_REMOTE_CLIENT->id;
$userrecord->confirmed = 1;
if ($userrecord->id = insert_record('user', $userrecord)) {
$userrecord = get_record('user','id', $userrecord->id);
+1 -1
View File
@@ -539,7 +539,7 @@
$file = basename($file);
if (!unzip_file("$basedir$wdir/$file")) {
print_error("unzipfileserror","error");
print_error("cannotunzipfile", "error");
}
echo "<div style=\"text-align:center\"><form action=\"index.php\" method=\"get\">";
+1 -1
View File
@@ -115,7 +115,7 @@ class edit_outcome_form extends moodleform {
if (empty($courseid)) {
$mform->hardFreeze('standard');
} else if (empty($outcome->courseid) and !has_capability('moodle/grade:manage', get_context_instance(CONTEXT_SYSTEM))) {
} else if (!has_capability('moodle/grade:manage', get_context_instance(CONTEXT_SYSTEM))) {
$mform->hardFreeze('standard');
} else if ($coursecount and empty($outcome->courseid)) {
+1
View File
@@ -139,5 +139,6 @@ $string['wrongdestpath'] = 'Wrong destination path';
$string['wrongsourcebase'] = 'Wrong source URL base';
$string['wrongzipfilename'] = 'Wrong ZIP file name';
$string['youcannotdeletecategory'] = 'You cannot delete category \'$a\' because you can neither delete the contents, nor move them elsewhere.';
$string['zipfileserror'] = 'Cannot create zip file';
?>
+1 -1
View File
@@ -495,7 +495,7 @@
$file = basename($file);
if (!unzip_file("$basedir/$wdir/$file")) {
print_error("unzipfileserror","error");
print_error("cannotunzipfile", "error");
}
echo "<center><form action=\"coursefiles.php\" method=\"get\">\n";
+11
View File
@@ -482,6 +482,17 @@ function environment_check_php_extensions($version) {
$result->setErrorCode(NO_PHP_EXTENSIONS_SECTION_FOUND);
return array($result);
}
/// Hack alert: inject extra mysqli dependency, mysql PHP extension is not supported in Moodle 2.x, warn only ppl using MySQL.
global $CFG;
set_dbfamily();
if ($CFG->dbfamily === 'mysql') {
$mver = normalize_version($version);
if (version_compare($mver, '2.0', 'ge')) {
$data['#']['PHP_EXTENSIONS']['0']['#']['PHP_EXTENSION'][] = array('#' => '', '@' => array('name' => 'mysqli', 'level' => 'required'));
}
}
/// Iterate over extensions checking them and creating the needed environment_results
foreach($data['#']['PHP_EXTENSIONS']['0']['#']['PHP_EXTENSION'] as $extension) {
$result = new environment_results('php_extension');
+7 -2
View File
@@ -19,9 +19,14 @@ class MoodleQuickForm_password extends HTML_QuickForm_password{
if (empty($CFG->xmlstrictheaders)) {
// no standard mform in moodle should allow autocomplete of passwords
// this is valid attribute in html5, sorry, we have to ignore validation errors in legacy xhtml 1.0
$attributes = (array)$attributes;
if (!isset($attributes['autocomplete'])) {
if (empty($attributes)) {
$attributes = array('autocomplete'=>'off');
} else if (is_array($attributes)) {
$attributes['autocomplete'] = 'off';
} else {
if (strpos($attributes, 'autocomplete') === false) {
$attributes .= ' autocomplete="off" ';
}
}
}
+7 -2
View File
@@ -19,9 +19,14 @@ class MoodleQuickForm_passwordunmask extends MoodleQuickForm_password {
if (empty($CFG->xmlstrictheaders)) {
// no standard mform in moodle should allow autocomplete of passwords
// this is valid attribute in html5, sorry, we have to ignore validation errors in legacy xhtml 1.0
$attributes = (array)$attributes;
if (!isset($attributes['autocomplete'])) {
if (empty($attributes)) {
$attributes = array('autocomplete'=>'off');
} else if (is_array($attributes)) {
$attributes['autocomplete'] = 'off';
} else {
if (strpos($attributes, 'autocomplete') === false) {
$attributes .= ' autocomplete="off" ';
}
}
}
+8 -3
View File
@@ -110,9 +110,14 @@ class moodleform {
if (empty($CFG->xmlstrictheaders)) {
// no standard mform in moodle should allow autocomplete with the exception of user signup
// this is valid attribute in html5, sorry, we have to ignore validation errors in legacy xhtml 1.0
$attributes = (array)$attributes;
if (!isset($attributes['autocomplete'])) {
if (empty($attributes)) {
$attributes = array('autocomplete'=>'off');
} else if (is_array($attributes)) {
$attributes['autocomplete'] = 'off';
} else {
if (strpos($attributes, 'autocomplete') === false) {
$attributes .= ' autocomplete="off" ';
}
}
}
@@ -1496,7 +1501,7 @@ function validate_' . $this->_formName . '(frm) {
} else if (is_a($element, 'HTML_QuickForm_hidden')) {
return array();
} else if (method_exists($element, 'getPrivateName')) {
} else if (method_exists($element, 'getPrivateName') && !($element instanceof HTML_QuickForm_advcheckbox)) {
return array($element->getPrivateName());
} else {
+68 -29
View File
@@ -2741,13 +2741,13 @@ function set_moodle_cookie($thing) {
return;
}
$cookiename = 'MOODLEID_'.$CFG->sessioncookie;
$cookiename = 'MOODLEID1_'.$CFG->sessioncookie;
$days = 60;
$seconds = DAYSECS*$days;
setCookie($cookiename, '', time() - HOURSECS, $CFG->sessioncookiepath, $CFG->sessioncookiedomain, $CFG->cookiesecure);
setCookie($cookiename, rc4encrypt($thing), time()+$seconds, $CFG->sessioncookiepath, $CFG->sessioncookiedomain, $CFG->cookiesecure);
setCookie($cookiename, rc4encrypt($thing, true), time()+$seconds, $CFG->sessioncookiepath, $CFG->sessioncookiedomain, $CFG->cookiesecure);
}
/**
@@ -2759,12 +2759,12 @@ function set_moodle_cookie($thing) {
function get_moodle_cookie() {
global $CFG;
$cookiename = 'MOODLEID_'.$CFG->sessioncookie;
$cookiename = 'MOODLEID1_'.$CFG->sessioncookie;
if (empty($_COOKIE[$cookiename])) {
return '';
} else {
$thing = rc4decrypt($_COOKIE[$cookiename]);
$thing = rc4decrypt($_COOKIE[$cookiename], true);
return ($thing == 'guest') ? '': $thing; // Ignore guest account
}
}
@@ -6024,25 +6024,33 @@ function get_list_of_currencies() {
/**
* rc4encrypt
*
* @param string $data ?
* @return string
* @todo Finish documenting this function
* @param string $data Data to encrypt.
* @param bool $usesecurekey Lets us know if we are using the old or new password.
* @return string The now encrypted data.
*/
function rc4encrypt($data) {
$password = get_site_identifier();
return endecrypt($password, $data, '');
function rc4encrypt($data, $usesecurekey = false) {
if (!$usesecurekey) {
$passwordkey = 'nfgjeingjk';
} else {
$passwordkey = get_site_identifier();
}
return endecrypt($passwordkey, $data, '');
}
/**
* rc4decrypt
*
* @param string $data ?
* @return string
* @todo Finish documenting this function
* @param string $data Data to decrypt.
* @param bool $usesecurekey Lets us know if we are using the old or new password.
* @return string The now decrypted data.
*/
function rc4decrypt($data) {
$password = get_site_identifier();
return endecrypt($password, $data, 'de');
function rc4decrypt($data, $usesecurekey = false) {
if (!$usesecurekey) {
$passwordkey = 'nfgjeingjk';
} else {
$passwordkey = get_site_identifier();
}
return endecrypt($passwordkey, $data, 'de');
}
/**
@@ -6373,9 +6381,14 @@ function check_php_version($version='4.1.0') {
case 'Firefox': /// Mozilla Firefox browsers
if (preg_match("/Firefox\/([0-9\.]+)/i", $agent, $match)) {
if (version_compare($match[1], $version) >= 0) {
if (strpos($agent, 'Iceweasel') === false and strpos($agent, 'Firefox') === false) {
return false;
}
if (empty($version)) {
return true; // no version specified
}
if (preg_match("/(Iceweasel|Firefox)\/([0-9\.]+)/i", $agent, $match)) {
if (version_compare($match[2], $version) >= 0) {
return true;
}
}
@@ -6383,19 +6396,45 @@ function check_php_version($version='4.1.0') {
case 'Gecko': /// Gecko based browsers
if (substr_count($agent, 'Camino')) {
// MacOS X Camino support
$version = 20041110;
// Do not look for dates any more, we expect real Firefox version here.
if (empty($version)) {
$version = 1;
} else if ($version > 20000000) {
// This is just a guess, it is not supposed to be 100% accurate!
if (preg_match('/^201/', $version)) {
$version = 3.6;
} else if (preg_match('/^200[7-9]/', $version)) {
$version = 3;
} else if (preg_match('/^2006/', $version)) {
$version = 2;
} else {
$version = 1.5;
}
}
// the proper string - Gecko/CCYYMMDD Vendor/Version
// Faster version and work-a-round No IDN problem.
if (preg_match("/Gecko\/([0-9]+)/i", $agent, $match)) {
if ($match[1] > $version) {
return true;
if (preg_match("/(Iceweasel|Firefox)\/([0-9\.]+)/i", $agent, $match)) {
// Use real Firefox version if specified in user agent string.
if (version_compare($match[2], $version) >= 0) {
return true;
}
} else if (preg_match("/Gecko\/([0-9\.]+)/i", $agent, $match)) {
// Gecko might contain date or Firefox revision, let's just guess the Firefox version from the date.
$browserver = $match[1];
if ($browserver > 20000000) {
// This is just a guess, it is not supposed to be 100% accurate!
if (preg_match('/^201/', $browserver)) {
$browserver = 3.6;
} else if (preg_match('/^200[7-9]/', $browserver)) {
$browserver = 3;
} else if (preg_match('/^2006/', $version)) {
$browserver = 2;
} else {
$browserver = 1.5;
}
}
if (version_compare($browserver, $version) >= 0) {
return true;
}
}
break;
Binary file not shown.
Binary file not shown.
+14 -1
View File
@@ -60,6 +60,7 @@ if($mform->is_cancelled()) {
print_header_simple($data->name, '', $nav,
'', '', true, update_module_button($cm->id, $course->id, get_string('modulename', 'data')),
navmenu($course, $cm), '', '');
groups_print_activity_menu($cm, "$CFG->wwwroot/mod/data/export.php?d=$d");
print_heading(format_string($data->name));
// these are for the tab display
@@ -83,13 +84,25 @@ foreach($fields as $key => $field) {
$exportdata[0][] = $field->field->name;
}
}
$groupid = groups_get_activity_group($cm);
$datarecords = get_records('data_records', 'dataid', $data->id);
ksort($datarecords);
$line = 1;
foreach($datarecords as $record) {
// get content indexed by fieldid
if( $content = get_records('data_content', 'recordid', $record->id, 'fieldid', 'fieldid, content, content1, content2, content3, content4') ) {
if($groupid) {
$select = "SELECT c.fieldid, c.content, c.content1, c.content2, c.content3, c.content4
FROM {$CFG->prefix}data_content c, {$CFG->prefix}data_records r
WHERE c.recordid = $record->id
AND r.id = c.recordid
AND r.groupid = $groupid";
} else {
$select = "SELECT fieldid, content, content1, content2, content3, content4
FROM {$CFG->prefix}data_content
WHERE recordid = $record->id";
}
if( $content = get_records_sql($select) ) {
foreach($fields as $field) {
$contents = '';
if(isset($content[$field->field->id])) {
+166
View File
@@ -2152,5 +2152,171 @@ function data_get_extra_capabilities() {
return array('moodle/site:accessallgroups', 'moodle/site:viewfullnames');
}
/**
* Get all of the record ids from a database activity.
*
* @param int $dataid The dataid of the database module.
* @return array $idarray An array of record ids
*/
function data_get_all_recordids($dataid, $selectdata = '') {
global $CFG;
$initsql = "SELECT r.id
FROM {$CFG->prefix}data_records r
WHERE r.dataid = {$dataid}";
if ($selectdata != '') {
$initsql .= $selectdata;
}
$initsql .= ' GROUP BY r.id';
$initrecord = get_recordset_sql($initsql);
$idarray = array();
foreach ($initrecord as $data) {
$idarray[] = $data['id'];
}
$initrecord->close();
return $idarray;
}
/**
* Get the ids of all the records that match that advanced search criteria.
* This goes and loops through each criterion one at a time until it either
* runs out of records or returns a subset of records.
*
* @param array $recordids An array of record ids.
* @param array $searcharray Contains information for the advanced search criteria
* @param int $dataid The data id of the database.
* @return array $recordids An array of record ids.
*/
function data_get_advance_search_ids($recordids, $searcharray, $dataid) {
$searchcriteria = array_keys($searcharray);
// Loop through and reduce the IDs one search criteria at a time.
foreach ($searchcriteria as $key) {
$recordids = data_get_recordids($key, $searcharray, $dataid, $recordids);
// If we don't have anymore IDs then stop.
if (!$recordids) {
break;
}
}
return $recordids;
}
/**
* Gets the record IDs given the search criteria
*
* @param string $alias Record alias.
* @param array $searcharray Criteria for the search.
* @param int $dataid Data ID for the database
* @param array $recordids An array of record IDs.
* @return array $nestarray An arry of record IDs
*/
function data_get_recordids($alias, $searcharray, $dataid, $recordids) {
global $CFG;
$nestsearch = $searcharray[$alias];
// searching for content outside of mdl_data_content
if ($alias < 0) {
$alias = '';
}
$recordidsstring = implode(',', $recordids);
$nestselect = "SELECT c$alias.recordid
FROM {$CFG->prefix}data_content c$alias,
{$CFG->prefix}data_fields f,
{$CFG->prefix}data_records r,
{$CFG->prefix}user u ";
$nestwhere = "WHERE u.id = r.userid
AND f.id = c$alias.fieldid
AND r.id = c$alias.recordid
AND r.dataid = $dataid
AND c$alias.recordid IN ($recordidsstring)
AND ";
$params['dataid'] = $dataid;
if (!empty($nestsearch->sql)) {
$nestsql = $nestselect . $nestwhere . $nestsearch->sql;
} else {
$sql = $nestsearch->field . ' ' . sql_ilike() . " '%$nestsearch->data%'";
$nestsql = $nestselect . $nestwhere . $sql . ' GROUP BY c' . $alias . '.recordid';
}
$nestrecords = get_recordset_sql($nestsql);
$nestarray = array();
foreach ($nestrecords as $data) {
$nestarray[] = $data['recordid'];
}
// Close the record set and free up resources.
$nestrecords->close();
return $nestarray;
}
/**
* Returns an array with an sql string for advanced searches and the parameters that go with them.
*
* @param int $sort DATA_*
* @param stdClass $data Data module object
* @param array $recordids An array of record IDs.
* @param string $selectdata Information for the select part of the sql statement.
* @param string $sortorder Additional sort parameters
* @return string An sql string.
*/
function data_get_advanced_search_sql($sort, $data, $recordids, $selectdata, $sortorder) {
global $CFG;
// Sorting by time created.
if ($sort == 0) {
$nestselectsql = "SELECT r.id, r.approved, r.timecreated, r.timemodified, r.userid, u.firstname, u.lastname
FROM {$CFG->prefix}data_content c,
{$CFG->prefix}data_records r,
{$CFG->prefix}user u ";
$groupsql = ' GROUP BY r.id, r.approved, r.timecreated, r.timemodified, r.userid, u.firstname, u.lastname ';
} else {
// Sorting through 'Other' criteria
if ($sort <= 0) {
switch ($sort) {
case DATA_LASTNAME:
$sortcontentfull = "u.lastname";
break;
case DATA_FIRSTNAME:
$sortcontentfull = "u.firstname";
break;
case DATA_APPROVED:
$sortcontentfull = "r.approved";
break;
case DATA_TIMEMODIFIED:
$sortcontentfull = "r.timemodified";
break;
case DATA_TIMEADDED:
default:
$sortcontentfull = "r.timecreated";
}
} else {
// Sorting with user entered data fields.
$sortfield = data_get_field_from_id($sort, $data);
$sortcontent = sql_compare_text('c.' . $sortfield->get_sort_field());
$sortcontentfull = $sortfield->get_sort_sql($sortcontent);
}
$nestselectsql = "SELECT r.id, r.approved, r.timecreated, r.timemodified, r.userid, u.firstname, u.lastname, $sortcontentfull
AS sortorder
FROM {$CFG->prefix}data_content c,
{$CFG->prefix}data_records r,
{$CFG->prefix}user u ";
$groupsql = ' GROUP BY r.id, r.approved, r.timecreated, r.timemodified, r.userid, u.firstname, u.lastname, ' .$sortcontentfull;
}
$nestfromsql = 'WHERE c.recordid = r.id
AND r.dataid = ' . $data->id . '
AND r.userid = u.id';
// Find the field we are sorting on
if ($sort > 0 or data_get_field_from_id($sort, $data)) {
$nestfromsql .= " AND c.fieldid = $sort";
}
// If there are no record IDs then return an sql statment that will return no rows.
if (count($recordids) != 0) {
$recordidsstring = implode(',', $recordids);
$insql = " IN ($recordidsstring) ";
} else {
$insql = " = -1";
}
$nestfromsql .= ' AND c.recordid ' . $insql . $selectdata . $groupsql;
$nestfromsql = "$nestfromsql $selectdata";
return "$nestselectsql $nestfromsql $sortorder";
}
?>
+28 -9
View File
@@ -300,6 +300,14 @@
groups_print_activity_menu($cm, $returnurl);
$currentgroup = groups_get_activity_group($cm);
$groupmode = groups_get_activity_groupmode($cm);
// If a student is not part of a group and seperate groups is enabled, we don't
// want them seeing all records.
if ($currentgroup == 0 && $groupmode == 1 && !has_capability('mod/data:manageentries', $context)) {
$canviewallrecords = false;
} else {
$canviewallrecords = true;
}
// deletect entries not approved yet and show hint instead of not found error
if ($record and $data->approval and !$record->approved and $record->userid != $USER->id and !has_capability('mod/data:manageentries', $context)) {
@@ -439,7 +447,13 @@
if ($currentgroup) {
$groupselect = " AND (r.groupid = '$currentgroup' OR r.groupid = 0)";
} else {
$groupselect = ' ';
if ($canviewallrecords) {
$groupselect = ' ';
} else {
// If separate groups are enabled and the user isn't in a group or
// a teacher, manager, admin etc, then just show them entries for 'All participants'.
$groupselect = " AND r.groupid = 0";
}
}
$ilike = sql_ilike(); //Be case-insensitive
@@ -507,7 +521,7 @@
$sortcontent = sql_compare_text('c.' . $sortfield->get_sort_field());
$sortcontentfull = $sortfield->get_sort_sql($sortcontent);
$what = ' DISTINCT r.id, r.approved, r.timecreated, r.timemodified, r.userid, u.firstname, u.lastname, '.$sortcontentfull.' AS _order ';
$what = ' DISTINCT r.id, r.approved, r.timecreated, r.timemodified, r.userid, u.firstname, u.lastname, '.$sortcontentfull.' AS sortorder ';
$count = ' COUNT(DISTINCT c.recordid) ';
$tables = $CFG->prefix.'data_content c,'.$CFG->prefix.'data_records r,'.$CFG->prefix.'data_content cs, '.$CFG->prefix.'user u ';
$where = 'WHERE c.recordid = r.id
@@ -515,7 +529,7 @@
AND r.dataid = '.$data->id.'
AND r.userid = u.id
AND cs.recordid = r.id ';
$sortorder = ' ORDER BY _order '.$order.' , r.id ASC ';
$sortorder = ' ORDER BY sortorder '.$order.' , r.id ASC ';
$searchselect = '';
// If requiredentries is not reached, only show current user's entries
@@ -543,13 +557,21 @@
/// To actually fetch the records
$fromsql = "FROM $tables $advtables $where $advwhere $groupselect $approveselect $searchselect $advsearchselect";
$sqlselect = "SELECT $what $fromsql $sortorder";
$sqlcount = "SELECT $count $fromsql"; // Total number of records when searching
$sqlmax = "SELECT $count FROM $tables $where $groupselect $approveselect"; // number of all recoirds user may see
/// Work out the paging numbers and counts
$selectdata = $groupselect . $approveselect;
$recordids = data_get_all_recordids($data->id, $selectdata);
$newrecordids = data_get_advance_search_ids($recordids, $search_array, $data->id);
$totalcount = count($newrecordids);
if (!empty($advanced)) {
$sqlselect = data_get_advanced_search_sql($sort, $data, $newrecordids, $selectdata, $sortorder);
} else {
$sqlselect = "SELECT $what $fromsql $sortorder";
}
$totalcount = count_records_sql($sqlcount);
if (empty($searchselect) && empty($advsearchselect)) {
$maxcount = $totalcount;
} else {
@@ -559,14 +581,11 @@
if ($record) { // We need to just show one, so where is it in context?
$nowperpage = 1;
$mode = 'single';
$page = 0;
// TODO: Improve this because we are executing $sqlselect twice (here and some lines below)!
if ($allrecordids = get_fieldset_sql($sqlselect)) {
$page = (int)array_search($record->id, $allrecordids);
unset($allrecordids);
}
} else if ($mode == 'single') { // We rely on ambient $page settings
$nowperpage = 1;
@@ -0,0 +1,17 @@
<h1>Add quiz chain</h1>
<div class="indent">
<p>
<b>No</b><br />
Only one quiz will be added to the course
</p>
<p>
<b>Yes</b><br />
If the &quot;File name&quot; is a file, it is treated as the start of a chain
of Hot Potatoes quizzes and all quizzes in the chain will be added to the course
with identical settings.<br />
<br />
If the &quot;File name&quot; is a folder, all Hot Potatoes quizzes in the folder
will be added to the course as a chain of quizzes with identical settings.
</p>
</div>
@@ -0,0 +1,8 @@
<h1>Item Response Analysis</h1>
<p>This table lists the responses to each question and the frequency of each response.</p>
<ul>
<li>The frequencies of <b>correct answers</b> are shown in <font color="red"><b>red text</b></font>.</li>
<li>The frequencies of <b>wrong answers</b> are shown in <font color="blue"><b>blue text</b></font>.</li>
<li>The frequencies of <b>ignored answers</b> are shown in <font color="brown"><b>brown text</b></font>.</li>
<li>The frequencies of <b>numeric data</b> are shown in <font color="green"><b>green text</b></font>.</li>
</ul>
@@ -0,0 +1,19 @@
<h1>Enable click reporting</h1>
<div class="indent">
<p>
<b>Yes</b><br />
A separate record is stored in the database each time a
&quot;hint&quot;, &quot;clue&quot; or &quot;check&quot;
button is clicked. This allows the teacher to see a very
detailed report showing the state of the quiz at each click.
However, it may also mean that the size of the database grows
very quickly, because several &quot;click&quot; records may
be stored for each attempt at a quiz.
</p>
<p>
<b>No</b><br />
Only one record per attempt at a quiz is stored in the Moodle database.
</p>
</div>
<p>By the default this option is disabled.</p>
@@ -0,0 +1,74 @@
<h1>Click Trail</h1>
<p>
This table shows details of every click by every student
during completed attempts at a particular Hot Potatoes quiz.
</p>
<p>
Please note that this report is very wide and can be very
long, so it is intended to be downloaded and viewed using
a spreadsheet program, such as Microsoft Excel.
</p>
<p>
Each row in the table contains the following information:
</p>
<p>
<b>Which click?</b><br />
The following details identify to which click in which attempt
by which student at which quiz in which section of which course
this row refers:
</p>
<ul>
<li>Course name, Section number, Exercise number, Exercise name, Exercise type, Number of questions</li>
<li>Student's full name, Login date, Login time, Logoff time</li>
<li>Attempt number, Attempt start time, Attempt finish time</li>
<li>Click number, Click time, Click type</li>
</ul>
<p>
<b>Which questions were affected?</b><br />
The following details are shown of which questions,
if any, were affected by the current click:
</p>
<ul>
<li>questions which were checked, or given a hint or clue on the current click</li>
<li>the status of each question after the current click
<ul>
<li><b>0</b> means &quot;correct&quot;</li>
<li><b>X</b> means &quot;wrong&quot;</li>
<li><b>-</b> means &quot;not attempted&quot;</li>
</ul>
</li>
<li>new answers which were received on the current click (answers that did not change are not shown)</li>
<li>questions for which new answers were received on the current click</li>
<li>questions for which new answers were received, or for which a hint or clue was given, on the current click</li>
</ul>
<p>
<b>How many questions were affected?</b><br />
The following details are shown of the total number
of questions, if any, affected by the current click
and the total number of questions affected so far
in the quiz:
</p>
<ul>
<li>the number of questions attempted</li>
<li>the number of questions not attempted</li>
<li>the number of questions whose status is &quot;right&quot;</li>
<li>the number of questions whose status is &quot;wrong&quot;</li>
<li>the number of questions for which hints have been given</li>
<li>the number of questions for which clues have been given</li>
<li>the number of questions for which new answers have been received</li>
<li>the number of questions for which new answers have been received, or for which a hint or clue has been given</li>
</ul>
<p>
<b>Scores</b><br />
The following details are shown about scores for this click
and for the quiz so far:
</p>
<ul>
<li>the raw score</li>
<li>the maximum score</li>
<li>the score as a percentage</li>
</ul>
@@ -0,0 +1,17 @@
<h1>Force Moodle to use Moodle-compatible media players</h1>
<div class="indent">
<p>
<b>No</b><br />
Moodle will not change the settings of any media players in the quiz
</p>
<p>
<b>Yes</b><br />
Moodle will force the quiz to use Moodle-compatible media players to play files like:
<ul><li>avi</li><li>mpeg</li><li>mpg</li><li>mp3</li><li>mov</li><li>wmv</li></ul>
</p>
</div>
<p>
More information:
<a href="help.php?module=hotpot&amp;file=mediaplayers.html">Relative URLs, media players and Hot Potatoes</a>
</p>
@@ -0,0 +1,16 @@
<h2>Hot Potatoes</h2>
<ul>
<li><a href="help.php?module=hotpot&amp;file=addquizchain.html">Add quiz chain</a></li>
<li><a href="help.php?module=hotpot&amp;file=analysistable.html">Analysis table</a></li>
<li><a href="help.php?module=hotpot&amp;file=clickreporting.html">Click trail report</a></li>
<li><a href="help.php?module=hotpot&amp;file=forceplugins.html">Force media plugins</a></li>
<li><a href="help.php?module=hotpot&amp;file=mediaplayers.html">Media players, relative URLs and Hot Potatoes</a></li>
<li><a href="help.php?module=hotpot&amp;file=navigation.html">Navigation</a></li>
<li><a href="help.php?module=hotpot&amp;file=outputformat.html">Output format</a></li>
<li><a href="help.php?module=hotpot&amp;file=reportcontent.html">Report content</a></li>
<li><a href="help.php?module=hotpot&amp;file=reportformat.html">Report format</a></li>
<li><a href="help.php?module=hotpot&amp;file=responsestable.html">Responses table</a></li>
<li><a href="help.php?module=hotpot&amp;file=shownextquiz.html">Show next quiz</a></li>
<li><a href="help.php?module=hotpot&amp;file=studentfeedback.html">Student feedback</a></li>
<li><a href="help.php?module=hotpot&amp;file=updatequizchain.html">Update quiz chain</a></li>
</ul>
@@ -0,0 +1,28 @@
<h1>Relative URLs, media players and Hot Potatoes</h1>
<h2>Definitions</h2>
<div class="indent">
<p><i>URL</i><br />
the address of an internet resource, such as a webpage, image or sound file.
</p>
<p>
<i>absolute URL</i><br />
a URL that begins with &quot;http://&quot; is called an absolute URL.
Wherever it is used, it always refers to the same target resource.
</p>
<p>
<i>relative URL</i><br />
a URL that does not begin with &quot;http://&quot; is called a relative URL.
It can be combined with the absolute URL of a &quot;base&quot; page, to get
the absolute URL of the target resource.
</p>
</div>
<h2>Relative URLs in Hot Potatoes quizzes</h2>
<p>Relative URLs are a convenient way to specify images, sounds and videos in a Hot Potatoes quiz, because they allow the quiz to be viewed and tested on a local PC, before being uploaded to a Moodle site. When the quiz is uploaded to the Moodle site, the multimedia files must also be uploaded, so that they are available when the quiz is administered via Moodle.</p>
<p>For security reasons, Moodle does not allow direct access to course files. All requests for files in a given course go through a guardian script which verfies that the person requesting the file is enrolled in the course. However, this mechanism can break relative links used in the quiz, because the normal rules for deriving an absolute URL from a relative URL do not work.</p>
<p>The solution is simple enough: <font color="red"><b>all relative URLs must be converted to absolute URLs </b></font> by the time the quiz reaches the browser. In the case of Hot Potatoes quizzes, the URLs will be converted by Moodle, so content creators do not have to bother with this tedious and error-prone task. </p>
<h2>Media players in Hot Potatoes quizzes </h2>
<p>Some media players will not accept the media file if it comes via the script which guards the course files. In this situation, it is necessary to replace the media player with one that is known to be compatible with Moodle. You can do this yourself by modifying the reference to the media player in the quiz, or you can force Moodle to do it by setting the &quot;Force media plugins&quot; option on the quiz's settings page to &quot;Yes&quot;.</p>
@@ -0,0 +1,8 @@
<p><img src="<?php echo $CFG->wwwroot?>/mod/hotpot/icon.gif" alt="" />&nbsp;<b>Hot Potatoes</b></p>
<div class="indent">
This module, the &quot;HotPot&quot; module, allows teachers to administer
<a href="http://web.uvic.ca/hrd/halfbaked/" target="_blank">Hot Potatoes</a> quizzes via Moodle.
The quizzes are created on the teacher's computer and then uploaded to the Moodle course.<br />
After students have attempted the quizzes, a number of reports are available which show how
individual questions were answered and some statistical trends in the scores.
</div>
@@ -0,0 +1,40 @@
<h1>Navigation</h1>
<p>
You can specify different navigation aids for a Hot Potatoes Quiz.
</p>
<div class="indent">
<p>
<b>Moodle navigation bar</b><br />
The standard Moodle navigation bar will be displayed in the same
window as the quiz at the top of the page.
</p>
<p>
<b>Moodle navigation frame</b><br />
The standard Moodle navigation bar will be displayed in a separate
frame at the top of the quiz.
</p>
<p>
<b>Embedded IFRAME</b><br />
The standard Moodle navigation bar will be displayed in the same
window as the quiz and the quiz will be embedded in an IFRAME.
</p>
<p>
<b>Hot Potatoes quiz buttons </b><br />
The quiz will be displayed with the navigation buttons, if any,
defined in the quiz.
</p>
<p>
<b>A single &quot;Give Up&quot; button</b><br />
The quiz will be displayed with a single &quot;Give Up&quot; button
at the top of the page.
</p>
<p>
<b>None</b><br />
The quiz will be displayed with no navigation aids. i.e. neither
a Moodle navigation bar nor any Hot Potatoes navigation buttons.
When all questions on the current quiz have been answered correctly,
Moodle will either return to the course page or display the next quiz,
depending on the setting of the &quot;Show next quiz?&quot; field
for the current quiz.
</p>
</div>
@@ -0,0 +1,39 @@
<h1>Output Format</h1>
<p>
You can specify different formats to display the quiz
</p>
<div class="indent">
<p>
<b>best</b><br />
The quiz will be displayed in the best format for the browser.
</p>
<p>
<b>v6+</b><br />
The quiz will be displayed in a drag and drop format for v6+ browsers
</p>
<p>
<b>v6</b><br />
The quiz will be displayed in format for v6 browsers
</p>
<p>
<b>v5</b><br />
The quiz will be displayed in a format for v5 browsers
</p>
<p>
<b>v4</b><br />
The quiz will be displayed in a format for v4 browsers
</p>
<p>
<b>v3</b><br />
The quiz will be displayed in a format for v3 browsers
</p>
<p>
<b>Flash</b><br />
The quiz will be displayed in using Flash
</p>
<p>
<b>mobile</b><br />
The quiz will be displayed in a format suitable for viewing on
small mobile devices such as cell phones
</p>
</div>
@@ -0,0 +1,13 @@
<h1>Remove grade item</h1>
<div class="indent">
<p>
<b>No</b><br />
The grade item for this activity in the Moodle gradebook will not be removed
</p>
<p>
<b>Yes</b><br />
If the maximum grade for this Hot Potatoes quiz is set to zero,
then the grade item for this activity will be removed from the Moodle gradebook
</p>
</div>
@@ -0,0 +1,109 @@
<h1>Report Content</h1>
<p>You can specify different content for the Hot Potatoes reports.</p>
<h2>Selecting the type of report</h2>
<div class="indent">
<p>
<b>Overview</b><br />
This report is a list of all attempts at this quiz.
It shows the picture and name of each user, along with their
grade for the quiz and the score, time and duration of each attempt.
Attempts may be selected and then deleted if required.
</p>
<p>
<b>Simple statistics</b><br />
This report is a list of all attempts at this quiz,
except &quot;in progress&quot; attempts.
It shows the picture and name of each user, along with their
grade for the quiz, and the score of each question in each attempt.
It also gives the average scores of the individual
questions and the quiz as a whole.
</p>
<p>
<b>Detailed statistics</b><br />
This report shows full details of all attempts at this quiz,
except &quot;in progress&quot; attempts.
The report contains the following tables:
</p>
<ul>
<li>the <a href="help.php?module=hotpot&amp;file=responsestable.html">responses table</a>,
which shows how each user responded to each question in each of their attempts at the quiz.</li>
<li>the <a href="help.php?module=hotpot&amp;file=analysistable.html">item analysis table</a>,
which lists the responses to each question and the frequency of each response.</li>
</ul>
<p>
<b>Click trail report</b><br />
This report shows details of every click by every student in all attempts at this quiz,
except &quot;in progress&quot; attempts.
The report can be very large and is intended to be downloaded and viewed in a spreadsheet
program, such as Microsoft Excel.
Details of the columns in this report are available in the
<a href="help.php?module=hotpot&amp;file=clickreporttable.html">click trail table</a>
help file.
</p>
<p>
The click trail report is only available if
<a href="help.php?module=hotpot&amp;file=clickreporting.html">click reporting</a>
has been enabled for this HotPot activity.
</p>
</div>
<h2>Selecting users</h2>
<div class="indent">
<p>
<b>All users</b><br />
The report will show responses by all users who have attempted this quiz.
This includes users who are not currently enrolled on the course,
the &quot;guest&quot; user, course creators and Moodle administrators.
</p>
<p>
<b>All participants</b><br />
The report will show responses by all students and teachers who are currently
enrolled on this course, as well as responses by the &quot;guest&quot; user,
course creators and Moodle administrators.
</p>
<p>
<b>Group: group name</b><br />
The report will show responses by all students in the group selected.
The group options will not appear on the drop-down menu if there are
no groups defined for this course.
</p>
<p>
<b>Enrolled students</b><br />
The report will show responses by students currently enrolled in this course.
Teacher's responses will not be included in the report.
</p>
<p>
<b>Single student</b><br />
The report will show responses by a single student selected from a drop-down list
of students' names.
</p>
</div>
<h2>Selecting grades</h2>
<div class="indent">
<p>
<b>All attempts</b><br />
The report will include the responses from all the attempts by each user.
</p>
<p>
<b>Best attempt</b><br />
The report will only include the responses from the highest scoring attempt by each user.
</p>
<p>
<b>First attempt</b><br />
The report will only include the responses from the first attempt by each user.
</p>
<p>
<b>Last attempt</b><br />
The report will only include the responses from the most recent attempt by each user.
</p>
</div>
@@ -0,0 +1,60 @@
<h1>Report Format</h1>
<p>
You can specify different output formats for the Hot Potatoes reports.
</p>
<h2>Report Format</h2>
<div class="indent">
<p>
<b>HTML</b><br />
the report will be generated in HTML format suitable for displaying in a web browser
</p>
<p>
<b>Excel</b><br />
the report will be generated as an &quot;.xls&quot; file which can be opened by
a spreadsheet program, such as Microsoft Excel
</p>
<p>
<b>Text</b><br />
the report will be generated a text file which can be opened by a text editor
</p>
</div>
<h2>Encoding</h2>
<div class="indent">
<p>
A list of encodings may be offered which allows you to force the report values
into a specific encoding if your spreadsheet program requires it.
For example, Microsoft Excel requires the &quot;SJIS&quot; encoding for Japanese.
The list of possible encodings can be adjusted by the site administrator on the
&quot;Settings&quot; page for the HotPot module
</p>
</div>
<h2>Wrap data</h2>
<div class="indent">
<p>
<b>Yes</b><br />
long data values will be wrapped to fit into table cells.
This may make some rows very tall
</p>
<p>
<b>No</b><br />
data values will not be wrapped
</p>
</div>
<h2>Show legend</h2>
<div class="indent">
<p>
<b>Yes</b><br />
in the main report, questions and answers will be represented by letters.
A legend will be generated which shows which letters represent which questions or answers
</p>
<p>
<b>No</b><br />
questions and answers will appear in full in the report and no legend will be generated
</p>
</div>
@@ -0,0 +1,22 @@
<h1>Individual Responses</h1>
<p>
This table shows how each user responded to each
question in each of their attempts at the quiz.
</p>
<p>
The responses are color-coded as follows:
</p>
<ul>
<li><font color="red"><b>Correct answers</b></font></li>
<li><font color="brown"><b>Ignored answers</b></font> (if any)</li>
<li><font color="blue"><b>Wrong answers</b></font> (if any)</li>
<li><font color="green"><b>score% (hints,clues,checks)</b></font>
<ul>
<li><b>score</b> is the percentage score for this question</li>
<li><b>hints</b> is the number hints requested</li>
<li><b>clues</b> indicates whether the clue was shown (=1) or not (=0)</li>
<li><b>checks</b> is the number checks performed on this question.
A value of "-1" means that the student clicked the "Show answer" button</li>
</ul>
</li>
</ul>
@@ -0,0 +1,17 @@
<h1>Show next quiz</h1>
<div class="indent">
<p>
<b>No</b><br />
When the Hot Potatoes quiz is finished, Moodle will
record the results and return to the main page for the
current course
</p>
<p>
<b>Yes</b><br />
When the Hot Potatoes quiz is finished, Moodle will
record the results and then display the next Hot Potatoes
quiz in the current section. If there is no such quiz,
Moodle will return to the main page for the current course
</p>
</div>
@@ -0,0 +1,38 @@
<h1>Student feedback</h1>
<p>
If this option is enabled, a link to a popup feedback window will be displayed
whenever the student clicks on the &quot;Check&quot; button. The feedback window
allows students to send feedback to the teacher regarding the quiz.
<p>
</p>
This option can have the following settings:
</p>
<div class="indent">
<p>
<b>None</b><br />
no feedback window will be displayed
</p>
<p>
<b>Web page</b><br />
a web page will be displayed in the feedback window.
You will need to enter the URL of the web page, for example:
<tt>http://myserver.com/feedbackform.html</tt>
</p>
<p>
<b>Feedback form</b><br />
a form suitable for sending to a standard form-to-email script,
such as formmail.pl, will be displayed in the feedback window.
You should also enter the URL of the form script, for example:
<tt>http://myserver.com/cgi-bin/formmail.pl</tt>
</p>
<p>
<b>Moodle forum</b><br />
the forum index for this Moodle course will be displayed
</p>
<p>
<b>Moodle messaging</b><br />
the Moodle instant messaging window will be displayed.
If the course has several teachers, the student will be
prompted to select a teacher before the messaging page appears.
</p>
</div>
@@ -0,0 +1,13 @@
<h1>Update next quiz</h1>
<div class="indent">
<p>
<b>No</b><br />
Only the current quiz will be updated
</p>
<p>
<b>Yes</b><br />
If this quiz is part of a chain of Hot Potatoes quizzes, then all quizzes
in the chain will be assigned identical settings to the current quiz.
</p>
</div>
+160
View File
@@ -0,0 +1,160 @@
<?PHP // $Id$
// hotpot.php - created with Moodle 1.7 beta + (2006101003)
$string['abandoned'] = 'Abandoned';
$string['addquizchain'] = 'Add quiz chain';
$string['allusers'] = 'All users';
$string['alwaysopen'] = 'Always open';
$string['attemptsall'] = 'All attempts';
$string['attemptsbest'] = 'Best attempt';
$string['attemptsfirst'] = 'First attempt';
$string['attemptslast'] = 'Last attempt';
$string['average'] = 'Average';
$string['checks'] = 'Checks';
$string['clickreporting'] = 'Enable click reporting';
$string['clues'] = 'Clues';
$string['completed'] = 'Completed';
$string['configexcelencodings'] = 'A list of encodings, separated by commas, that can be used to force report values into a specific encoding for spreadsheet programs. For example, Microsoft Excel requires the &quot;SJIS&quot; encoding for Japanese';
$string['configshowtimes'] = 'Should the time taken to process records be displayed in listings and reports? This is only really necessary if you are trying to find out why your server is running slowly.';
$string['copiedtoclipboard'] = 'The contents of this page have been copied to the clipboard';
$string['copytoclipboard'] = 'Copy to Clipboard';
$string['correct'] = 'Correct';
$string['deleteabandoned'] = 'Delete abandoned';
$string['deleteabandonedcheck'] = 'Do you really want to delete all $a abandoned attempts?';
$string['deleteallattempts'] = 'Delete all attempts';
$string['displaycoursenext'] = 'Display Course page next';
$string['displayhotpotnext'] = 'Display Hot Potatoes quiz next';
$string['displayindexnext'] = 'Display HotPot index next';
$string['enterafilename'] = 'Please enter a file name';
$string['error_couldnotopenfolder'] = 'Could not access the folder &quot;$a&quot;';
$string['error_couldnotopensourcefile'] = 'Could not open the source file \"$a\"';
$string['error_couldnotopentemplate'] = 'Could not open template for &quot;$a&quot; format';
$string['error_invalidquiztype'] = 'Quiz type is missing or invalid';
$string['error_nocourseorfilename'] = 'Could not create XML tree: missing course or file name';
$string['error_nofeedbackurlformmail'] = 'Please enter a URL for the form processing script';
$string['error_nofeedbackurlwebpage'] = 'Please enter a URL for the webpage';
$string['error_nofilename'] = 'Please enter a file name';
$string['error_noquizzesfound'] = 'No Hot Potatoes quizzes found';
$string['error_notfileorfolder'] = '&quot;$a&quot; is not file or folder';
$string['excelencodings'] = 'Excel encodings';
$string['feedbackformmail'] = 'Feedback form';
$string['feedbackmoodleforum'] = 'Moodle forum';
$string['feedbackmoodlemessaging'] = 'Moodle messaging';
$string['feedbacknone'] = 'None';
$string['feedbackwebpage'] = 'Web page';
$string['filetype'] = 'File type';
$string['forceplugins'] = 'Force media plugins';
$string['giveup'] = 'Give Up';
$string['hints'] = 'Hints';
$string['hotpot:attempt'] = 'Attempt a quiz';
$string['hotpot:deleteattempt'] = 'Delete quiz attempts';
$string['hotpot:grade'] = 'Modify grades';
$string['hotpot:view'] = 'Use quiz';
$string['hotpot:viewreport'] = 'View reports';
$string['hotpotcloses'] = 'Hot Potatoes quiz closes';
$string['hotpotopens'] = 'Hot Potatoes quiz opens';
$string['ignored'] = 'Ignored';
$string['inprogress'] = 'In progress';
$string['location'] = 'File location';
$string['modulename'] = 'Hot Potatoes Quiz';
$string['modulenameplural'] = 'Hot Potatoes Quizzes';
$string['navigation'] = 'Navigation';
$string['navigation_bar'] = 'Moodle navigation bar';
$string['navigation_buttons'] = 'Hot Potatoes quiz buttons';
$string['navigation_frame'] = 'Moodle navigation frame';
$string['navigation_give_up'] = 'A single &quot;Give Up&quot; button';
$string['navigation_iframe'] = 'Embedded IFRAME';
$string['navigation_none'] = 'None';
$string['neverclosed'] = 'Never closed';
$string['noactivity'] = 'No activity';
$string['noresponses'] = 'No information about individual questions and responses was found.';
$string['outputformat'] = 'Output format';
$string['outputformat_best'] = 'best';
$string['outputformat_flash'] = 'Flash';
$string['outputformat_mobile'] = 'mobile';
$string['outputformat_v3'] = 'v3';
$string['outputformat_v4'] = 'v4';
$string['outputformat_v5'] = 'v5';
$string['outputformat_v5_plus'] = 'v5+';
$string['outputformat_v6'] = 'v6';
$string['outputformat_v6_plus'] = 'v6+';
$string['penalties'] = 'Penalties';
$string['questionshort'] = 'Q-$a';
$string['quiztype'] = 'Quiz type';
$string['rawdetails'] = 'Raw attempt details';
$string['regrade'] = 'Regrade';
$string['regradecheck'] = 'Do you really want to regrade &quot;$a&quot;?';
$string['regraderequired'] = 'Regrade required';
$string['removegradeitem'] = 'Remove grade item';
$string['reportanswers'] = 'Answers';
$string['reportattemptfinish'] = 'Att. finish';
$string['reportattemptnumber'] = 'Attempt';
$string['reportattemptstart'] = 'Att. start';
$string['reportbutton'] = 'Generate report';
$string['reportchanges'] = 'Changes';
$string['reportchecks'] = 'Checks';
$string['reportclick'] = 'Click trail report';
$string['reportclicknumber'] = 'Click';
$string['reportclicktime'] = 'Click time';
$string['reportclicktype'] = 'Click type';
$string['reportclues'] = 'Clues';
$string['reportcontent'] = 'Content';
$string['reportcorrectsymbol'] = 'O';
$string['reportcoursename'] = 'Course name';
$string['reportencoding'] = 'Encoding';
$string['reportevents'] = 'Events';
$string['reportexercisename'] = 'Ex. name';
$string['reportexercisenumber'] = 'Exercise';
$string['reportexercisetype'] = 'Ex. type';
$string['reportformat'] = 'Format';
$string['allmycourses'] = 'All my courses'; //necessary for 1.6 and older
$string['allusers'] = 'All users';
$string['reportformatexcel'] = 'Excel';
$string['reportformathtml'] = 'HTML';
$string['reportformattext'] = 'Text';
$string['reporthints'] = 'Hints';
$string['reporthotpotscore'] = 'Hotpot score';
$string['reportlegend'] = 'Legend';
$string['reportlogindate'] = 'Login date';
$string['reportlogintime'] = 'Login time';
$string['reportlogofftime'] = 'Logoff time';
$string['reportmaxscore'] = 'Max score';
$string['reportnottried'] = 'Not tried';
$string['reportnottriedsymbol'] = '-';
$string['reportnumberofquestions'] = 'No. of q\'s';
$string['reportpercentscore'] = '%% Score';
$string['reportquestionstried'] = 'Q\'s tried';
$string['reportrawscore'] = 'Raw score';
$string['reportright'] = 'Right';
$string['reportsectionnumber'] = 'Section';
$string['reportshowanswer'] = 'Show answers';
$string['reportshowlegend'] = 'Show legend';
$string['reportsofar'] = '$a so far';
$string['reportstatus'] = 'Status';
$string['reportstudentid'] = 'Student id';
$string['reportthisclick'] = '$a this click';
$string['reporttimerecorded'] = 'Responses recorded';
$string['reportwrapdata'] = 'Wrap data';
$string['reportwrong'] = 'Wrong';
$string['reportwrongsymbol'] = 'X';
$string['resultssaved'] = 'Quiz results were saved';
$string['score'] = 'Score';
$string['showhtmlsource'] = 'Show HTML source';
$string['shownextquiz'] = 'Show next quiz';
$string['showtimes'] = 'Show processing times';
$string['showxmlsource'] = 'Show XML source';
$string['showxmltree'] = 'Show XML tree';
$string['specifictime'] = 'Specific time';
$string['studentfeedback'] = 'Student feedback';
$string['textsourcefilename'] = 'Use file name';
$string['textsourcefilepath'] = 'Use file path';
$string['textsourcequiz'] = 'Get from quiz';
$string['textsourcespecific'] = 'Specific text';
$string['thiscourse'] = 'This course'; //necessary for 1.6 and older
$string['timedout'] = 'Timed out';
$string['updatequizchain'] = 'Update quiz chain';
$string['weighting'] = 'Weighting';
$string['wrong'] = 'Wrong';
?>
+9 -5
View File
@@ -1097,7 +1097,7 @@ function hotpot_get_recent_mod_activity(&$activities, &$index, $sincetime, $cour
}
}
function hotpot_print_recent_mod_activity($activity, $course, $detail=false) {
function hotpot_print_recent_mod_activity($activity, $courseid, $detail=false) {
/// Basically, this function prints the results of "hotpot_get_recent_activity"
global $CFG, $THEME, $USER;
@@ -1108,10 +1108,14 @@ function hotpot_print_recent_mod_activity($activity, $course, $detail=false) {
$bgcolor = '';
}
if (is_object($courseid) && isset($courseid->id)) {
$courseid = $courseid->id; // shouldn't happen !!
}
print '<table border="0" cellpadding="3" cellspacing="0">';
print '<tr><td'.$bgcolor.' class="forumpostpicture" width="35" valign="top">';
print_user_picture($activity->user->userid, $course, $activity->user->picture);
print_user_picture($activity->user->userid, $courseid, $activity->user->picture);
print '</td><td width="100%"><font size="2">';
if ($detail) {
@@ -1123,7 +1127,7 @@ function hotpot_print_recent_mod_activity($activity, $course, $detail=false) {
$href = "$CFG->wwwroot/mod/hotpot/view.php?hp=$activity->instance";
print '<a href="'.$href.'">'.$activity->name.'</a> - ';
}
if (has_capability('mod/hotpot:viewreport',get_context_instance(CONTEXT_COURSE, $course))) {
if (has_capability('mod/hotpot:viewreport',get_context_instance(CONTEXT_COURSE, $courseid))) {
// score (with link to attempt details)
$href = "$CFG->wwwroot/mod/hotpot/review.php?hp=$activity->instance&attempt=".$activity->content->attemptid;
print '<a href="'.$href.'">('.hotpot_format_score($activity->content).')</a> ';
@@ -1133,7 +1137,7 @@ function hotpot_print_recent_mod_activity($activity, $course, $detail=false) {
}
// link to user
$href = "$CFG->wwwroot/user/view.php?id=$activity->user->userid&course=$course";
$href = "$CFG->wwwroot/user/view.php?id=$activity->user->userid&course=$courseid";
print '<a href="'.$href.'">'.$activity->user->fullname.'</a> ';
// time and date
@@ -1805,7 +1809,7 @@ class hotpot_xml_quiz extends hotpot_xml_tree {
$quoteopen = '("|&quot;|&amp;quot;)'; // open quote
$quoteclose = '\\5'; // close quote (to match open quote)
$tags = array('script'=>'src', 'link'=>'href', 'a'=>'href','img'=>'src','param'=>'value', 'object'=>'data', 'embed'=>'src');
$tags = array('script'=>'src', 'link'=>'href', 'a'=>'href','img'=>'src','param'=>'value', 'object'=>'data', 'embed'=>'src', '(?:table|th|td)' =>'background');
foreach ($tags as $tag=>$attribute) {
if ($tag=='param') {
$url = '\S+?\.\S+?'; // must include a filename and have no spaces
+55 -53
View File
@@ -1,39 +1,39 @@
<?PHP //$Id$
<?php
//This php script contains all the stuff to restore hotpot mods
//-----------------------------------------------------------
// This is the "graphical" structure of the hotpot mod:
//-----------------------------------------------------------
//
// hotpot
// (CL, pk->id,
// fk->course, files)
// |
// +--------------+---------------+
// | |
// hotpot_attempts hotpot_questions
// (UL, pk->id, (UL, pk->id,
// fk->hotpot) fk->hotpot, text)
// | | |
// +-------------------+----------+ |
// | | |
// hotpot_details hotpot_responses |
// (UL, pk->id, (UL, pk->id, |
// fk->attempt) fk->attempt, question, |
// correct, wrong, ignored) |
// | |
// +-------+-------+
// |
// hotpot_strings
// (UL, pk->id)
//
// Meaning: pk->primary key field of the table
// fk->foreign key to link with parent
// nt->nested field (recursive data)
// CL->course level info
// UL->user level info
// files->table may have files
//
//-----------------------------------------------------------
//-----------------------------------------------------------
// This is the "graphical" structure of the hotpot mod:
//-----------------------------------------------------------
//
// hotpot
// (CL, pk->id,
// fk->course, files)
// |
// +--------------+---------------+
// | |
// hotpot_attempts hotpot_questions
// (UL, pk->id, (UL, pk->id,
// fk->hotpot) fk->hotpot, text)
// | | |
// +-------------------+----------+ |
// | | |
// hotpot_details hotpot_responses |
// (UL, pk->id, (UL, pk->id, |
// fk->attempt) fk->attempt, question, |
// correct, wrong, ignored) |git
// | |
// +-------+-------+
// |
// hotpot_strings
// (UL, pk->id)
//
// Meaning: pk->primary key field of the table
// fk->foreign key to link with parent
// nt->nested field (recursive data)
// CL->course level info
// UL->user level info
// files->table may have files
//
//-----------------------------------------------------------
require_once ("$CFG->dirroot/mod/hotpot/lib.php");
@@ -359,17 +359,19 @@ function hotpot_restore_record(&$restore, $status, &$xml, $table, $foreign_keys,
}
// check all "not null" fields have been set
foreach ($table_columns[$table] as $column) {
if ($column->not_null) {
$name = $column->name;
if ($name=='id' || (isset($record->$name) && ! is_null($record->$name))) {
// do nothing
} else if (isset($column->default_value)) {
$record->$name = $column->default_value;
} else if (preg_match('/int|decimal|double|float|time|year/i', $column->type)) {
$record->$name = 0;
} else {
$record->$name = '';
if (isset($table_columns[$table]) && is_array($table_columns[$table])) {
foreach ($table_columns[$table] as $column) {
if ($column->not_null) {
$name = $column->name;
if ($name=='id' || (isset($record->$name) && ! is_null($record->$name))) {
// do nothing
} else if (isset($column->default_value)) {
$record->$name = $column->default_value;
} else if (preg_match('/int|decimal|double|float|time|year/i', $column->type)) {
$record->$name = 0;
} else {
$record->$name = '';
}
}
}
}
@@ -433,11 +435,11 @@ function hotpot_restore_logs($restore, $log) {
$status = true;
}
}
break;
break;
case "view all":
$log->url = "index.php?id=".$log->course;
$status = true;
break;
break;
case "report":
if ($log->cmid) {
//Get the new_id of the module (to recode the info field)
@@ -448,7 +450,7 @@ function hotpot_restore_logs($restore, $log) {
$status = true;
}
}
break;
break;
case "attempt":
case "submit":
case "review":
@@ -467,13 +469,13 @@ function hotpot_restore_logs($restore, $log) {
}
}
}
break;
break;
default:
// Oops, unknown $log->action
if (!defined('RESTORE_SILENTLY')) {
print "<p>action (".$log->module."-".$log->action.") unknown. Not restored</p>";
}
break;
break;
} // end switch
return $status ? $log : false;
}
@@ -486,7 +488,7 @@ function hotpot_decode_content_links($content, $restore) {
$start = $matches[0][$i][1];
$length = strlen($matches[0][$i][0]);
$replace = hotpot_decode_content_link(
// $scriptname, $paramname, $paramvalue, $restore
// $scriptname, $paramname, $paramvalue, $restore
$matches[2][$i][0], $matches[3][$i][0], $matches[4][$i][0], $restore
);
$content = substr_replace($content, $replace, $start, $length);
@@ -530,4 +532,4 @@ function hotpot_decode_content_link($scriptname, $paramname, $paramvalue, &$rest
return "$CFG->wwwroot/mod/hotpot/$scriptname.php?$paramname=$new_id";
}
?>
?>
+15 -9
View File
@@ -141,7 +141,7 @@
// HP5 v5
$get_html = empty($framename) ? true : false;
}
if ($get_html) {
if (HOTPOT_FIRST_ATTEMPT) {
@@ -356,14 +356,20 @@
$body .= ""
. '<script type="text/javascript">'."\n"
. "//<![CDATA[\n"
. " var s = (typeof(window.onload)=='function') ? onload.toString() : '';\n"
. " if (s.indexOf('".$matches[3]."')<0) {\n"
. " if (s=='') {\n" // no previous onload
. " window.onload = new Function('".$matches[3]."');\n"
. " } else {\n"
. " window.onload_hotpot = onload;\n"
. " window.onload = new Function('window.onload_hotpot();'+'".$matches[3]."');\n"
. " }\n"
. " var re = new RegExp('\\\\s+', 'g');\n"
. " if (typeof(window.onload)=='function') {\n"
. " var s = onload.toString();\n"
. " s = s.replace(re, '');\n"
. " } else {\n"
. " var s = '';\n"
. " }\n"
. " if (s.indexOf('".$matches[3]."'.replace(re, ''))<0) {\n"
. " if (s=='') {\n" // no previous onload
. " window.onload = new Function('".$matches[3]."');\n"
. " } else {\n"
. " window.onload_hotpot = onload;\n"
. " window.onload = new Function('window.onload_hotpot();'+'".$matches[3]."');\n"
. " }\n"
. " }\n"
. "//]]>\n"
. "</script>\n"
+7 -7
View File
@@ -297,19 +297,19 @@
//<![CDATA[
scorm_resize(<?php echo $scorm->width.", ". $scorm->height; ?>);
function openpopup(url,name,options,width,height) {
fullurl = "<?php echo $CFG->wwwroot.'/mod/scorm/' ?>" + url;
windowobj = window.open(fullurl,name,options);
if ((width==100) && (height==100)) {
// Fullscreen
windowobj.moveTo(0,0);
}
if (width<=100) {
width = Math.round(screen.availWidth * width / 100);
}
if (height<=100) {
height = Math.round(screen.availHeight * height / 100);
}
windowobj.resizeTo(width,height);
options += ",width="+width+",height="+height;
fullurl = "<?php echo $CFG->wwwroot.'/mod/scorm/' ?>" + url;
windowobj = window.open(fullurl,name,options);
if ((width==100) && (height==100)) {
// Fullscreen
windowobj.moveTo(0,0);
}
windowobj.focus();
return windowobj;
}
+140 -33
View File
@@ -42,7 +42,7 @@ class qformat_hotpot extends qformat_default {
break;
default:
// shouldn't happen !!
$courseid = 0;
$courseid = 0;
}
require_once($CFG->libdir.'/filelib.php');
$baseurl = get_file_url($courseid).'/';
@@ -81,7 +81,12 @@ class qformat_hotpot extends qformat_default {
$questions = array();
switch ($xml->quiztype) {
case 'jcloze':
$this->process_jcloze($xml, $questions);
if (strpos($source, '<gap-fill><question-record>')) {
$startwithgap = true;
} else {
$startwithgap = false;
}
$this->process_jcloze($xml, $questions, $startwithgap);
break;
case 'jcross':
$this->process_jcross($xml, $questions);
@@ -114,7 +119,7 @@ class qformat_hotpot extends qformat_default {
}
}
function process_jcloze(&$xml, &$questions) {
function process_jcloze(&$xml, &$questions, $startwithgap) {
// define default grade (per cloze gap)
$defaultgrade = 1;
$gap_count = 0;
@@ -144,10 +149,27 @@ class qformat_hotpot extends qformat_default {
$question->usecase = 0; // Ignore case
$question->image = ""; // No images with this format
}
$question->qtype = MULTIANSWER;
$question->qtype = MULTIANSWER;
$question->name = $this->hotpot_get_title($xml, $x);
$question->questiontext = $this->hotpot_get_reading($xml);
$question->questiontext = '';
// add get dropdown list, if any
if (intval($xml->xml_value('hotpot-config-file,'.$xml->quiztype.',use-drop-down-list'))) {
$dropdownlist = $this->hotpot_jcloze_wordlist($xml);
$answertype = MULTICHOICE;
} else {
$dropdownlist = false;
$answertype = SHORTANSWER;
// add wordlist, if required (not required if we are using dropdowns)
if (intval($xml->xml_value('hotpot-config-file,'.$xml->quiztype.',include-word-list'))) {
$question->questiontext .= '<p>'.implode(' ', $this->hotpot_jcloze_wordlist($xml)).'</p>';
}
}
// add reading, if any
$question->questiontext .= $this->hotpot_get_reading($xml);
// setup answer arrays
if ($moodle_14) {
@@ -160,71 +182,130 @@ class qformat_hotpot extends qformat_default {
}
$q = 0;
while ($text = $xml->xml_value($tags, $exercise."[$q]")) {
// add next bit of text
$question->questiontext .= $this->hotpot_prepare_str($text);
$looping = true;
while ($looping) {
// get next bit of text
$questiontext = $xml->xml_value($tags, $exercise."[$q]");
$questiontext = $this->hotpot_prepare_str($questiontext);
// check for a gap
// get next gap
$gap = '';
$question_record = $exercise."['question-record'][$q]['#']";
if ($xml->xml_value($tags, $question_record)) {
// add gap
$gap_count ++;
$positionkey = $q+1;
$question->questiontext .= '{#'.$positionkey.'}';
$gap = '{#'.$positionkey.'}';
// initialize answer settings
if ($moodle_14) {
$question->answers[$q]->positionkey = $positionkey;
$question->answers[$q]->answertype = SHORTANSWER;
$question->answers[$q]->answertype = $answertype;
$question->answers[$q]->norm = $defaultgrade;
$question->answers[$q]->alternatives = array();
} else {
$wrapped = new stdClass();
$wrapped->qtype = SHORTANSWER;
$wrapped->qtype = $answertype;
$wrapped->usecase = 0;
$wrapped->defaultgrade = $defaultgrade;
$wrapped->questiontextformat = 0;
$wrapped->answer = array();
$wrapped->fraction = array();
$wrapped->feedback = array();
// required for multichoice
$wrapped->single = 1;
$wrapped->answernumbering = 0;
$wrapped->shuffleanswers = 0;
$wrapped->correctfeedback = '';
$wrapped->partiallycorrectfeedback = '';
$wrapped->incorrectfeedback = '';
// array of answers
$answers = array();
}
// add answers
$a = 0;
while (($answer=$question_record."['answer'][$a]['#']") && $xml->xml_value($tags, $answer)) {
$text = $this->hotpot_prepare_str($xml->xml_value($tags, $answer."['text'][0]['#']"));
$correct = $xml->xml_value($tags, $answer."['correct'][0]['#']");
$feedback = $this->hotpot_prepare_str($xml->xml_value($tags, $answer."['feedback'][0]['#']"));
if (strlen($text)) {
// set score (0=0%, 1=100%)
$fraction = empty($correct) ? 0 : 1;
// store answer
if ($dropdownlist) {
$a = 0;
$correcttext = '';
$correctfeedback = '';
while (($answer=$question_record."['answer'][$a]['#']") && $xml->xml_value($tags, $answer)) {
if (intval($xml->xml_value($tags, $answer."['correct'][0]['#']"))) {
$correcttext = $this->hotpot_prepare_str($xml->xml_value($tags, $answer."['text'][0]['#']"));
$correctfeedback = $this->hotpot_prepare_str($xml->xml_value($tags, $answer."['feedback'][0]['#']"));
break;
}
$a++;
}
foreach ($dropdownlist as $a => $answer) {
if ($answer==$correcttext) {
$fraction = 1;
$feedback = $correctfeedback;
} else {
$fraction = 0;
$feedback = '';
}
if ($moodle_14) {
$question->answers[$q]->alternatives[$a] = new stdClass();
$question->answers[$q]->alternatives[$a]->answer = $text;
$question->answers[$q]->alternatives[$a]->answer = $answer;
$question->answers[$q]->alternatives[$a]->fraction = $fraction;
$question->answers[$q]->alternatives[$a]->feedback = $feedback;
} else {
$wrapped->answer[] = $text;
$wrapped->answer[] = $answer;
$wrapped->fraction[] = $fraction;
$wrapped->feedback[] = $feedback;
$answers[] = (empty($fraction) ? '' : '=').$text.(empty($feedback) ? '' : ('#'.$feedback));
$answers[] = ($fraction==0 ? '' : '=').$answer.($feedback=='' ? '' : ('#'.$feedback));
}
}
$a++;
} else {
$a = 0;
while (($answer=$question_record."['answer'][$a]['#']") && $xml->xml_value($tags, $answer)) {
$text = $this->hotpot_prepare_str($xml->xml_value($tags, $answer."['text'][0]['#']"));
$correct = $xml->xml_value($tags, $answer."['correct'][0]['#']");
$feedback = $this->hotpot_prepare_str($xml->xml_value($tags, $answer."['feedback'][0]['#']"));
if (strlen($text)) {
// set score (0=0%, 1=100%)
$fraction = empty($correct) ? 0 : 1;
// store answer
if ($moodle_14) {
$question->answers[$q]->alternatives[$a] = new stdClass();
$question->answers[$q]->alternatives[$a]->answer = $text;
$question->answers[$q]->alternatives[$a]->fraction = $fraction;
$question->answers[$q]->alternatives[$a]->feedback = $feedback;
} else {
$wrapped->answer[] = $text;
$wrapped->fraction[] = $fraction;
$wrapped->feedback[] = $feedback;
$answers[] = (empty($fraction) ? '' : '=').$text.(empty($feedback) ? '' : ('#'.$feedback));
}
}
$a++;
}
}
// compile answers into question text, if necessary
if ($moodle_14) {
// do nothing
} else {
$wrapped->questiontext = '{'.$defaultgrade.':SHORTANSWER:'.implode('~', $answers).'}';
$wrapped->questiontext = '{'.$defaultgrade.':'.$answertype.':'.implode('~', $answers).'}';
$question->options->questions[] = $wrapped;
}
} // end if gap
if (strlen($questiontext) || strlen($gap)) {
if ($startwithgap) {
$question->questiontext .= $gap.$questiontext;
} else {
$question->questiontext .= $questiontext.$gap;
}
} else {
$looping = false;
}
$q++;
} // end while $text
} // end while $looping
if ($q) {
// define total grade for this exercise
@@ -241,6 +322,32 @@ class qformat_hotpot extends qformat_default {
} // end while $exercise
}
function hotpot_jcloze_wordlist(&$xml) {
$wordlist = array();
$q = 0;
$tags = 'data,gap-fill,question-record';
while (($question="[$q]['#']") && $xml->xml_value($tags, $question)) {
$a = 0;
$aa = 0;
while (($answer=$question."['answer'][$a]['#']") && $xml->xml_value($tags, $answer)) {
$text = $xml->xml_value($tags, $answer."['text'][0]['#']");
$correct = $xml->xml_value($tags, $answer."['correct'][0]['#']");
if (strlen($text) && intval($correct)) {
$wordlist[] = $text;
$aa++;
}
$a++;
}
$q++;
}
$wordlist = array_unique($wordlist);
sort($wordlist);
return $wordlist;
}
function process_jcross(&$xml, &$questions) {
// xml tags to the start of the crossword exercise clue items
$tags = 'data,crossword,clues,item';
@@ -488,7 +595,7 @@ class qformat_hotpot extends qformat_default {
$a++;
}
if ($correct_answers_all_zero) {
// correct answers all have score of 0%,
// correct answers all have score of 0%,
// so reset score for correct answers 100%
foreach ($correct_answers as $aa) {
$question->fraction[$aa] = 1;
@@ -531,10 +638,10 @@ class qformat_hotpot extends qformat_default {
$tags = 'data,reading';
if ($xml->xml_value("$tags,include-reading")) {
if ($title = $xml->xml_value("$tags,reading-title")) {
$str .= "<H3>$title</H3>";
$str .= "<h3>$title</h3>";
}
if ($text = $xml->xml_value("$tags,reading-text")) {
$str .= "<P>$text</P>";
$str .= "<p>$text</p>";
}
}
return $this->hotpot_prepare_str($str);
@@ -572,7 +679,7 @@ function hotpot_charcode_to_utf8($charcode) {
return chr(($charcode >> 0x12) + 0xF0).chr((($charcode >> 0x0C) & 0x3F) + 0x80).chr((($charcode >> 0x06) & 0x3F) + 0x80).chr(($charcode & 0x3F) + 0x80);
}
// unidentified char code !!
return ' ';
return ' ';
}
function hotpot_convert_relative_urls($str, $baseurl, $filename) {
+3 -3
View File
@@ -571,9 +571,9 @@ class question_match_qtype extends default_questiontype {
//mappings in backup_ids to use them later where restoring states (user level).
//Get the match_sub from DB (by question, questiontext and answertext)
$db_match_sub = get_record ("question_match_sub","question",$new_question_id,
"questiontext",$match_sub->questiontext,
"answertext",$match_sub->answertext);
$db_match_sub = get_record('question_match_sub', 'question', $new_question_id,
sql_compare_text('questiontext', 255), $match_sub->questiontext,
'answertext', $match_sub->answertext);
//Do some output
if (($i+1) % 50 == 0) {
if (!defined('RESTORE_SILENTLY')) {
+2 -2
View File
@@ -6,10 +6,10 @@
// This is compared against the values stored in the database to determine
// whether upgrades should be performed (see lib/db/*.php)
$version = 2007101591.10; // YYYYMMDD = date of the 1.9 branch (don't change)
$version = 2007101592.05; // YYYYMMDD = date of the 1.9 branch (don't change)
// X = release number 1.9.[0,1,2,3,4,5...]
// Y.YY = micro-increments between releases
$release = '1.9.16 (Build: 20120109)'; // Human-friendly version name
$release = '1.9.19+ (Build: 20130513)'; // Human-friendly version name
?>