diff --git a/mod/hotpot/README.TXT b/mod/hotpot/README.TXT index 4818bec7f68..eed226c9a32 100644 --- a/mod/hotpot/README.TXT +++ b/mod/hotpot/README.TXT @@ -1,151 +1,105 @@ -This is v2.1.5 of the HotPot module - This module allows teachers to administer Hot Potatoes and TexToys quizzes via Moodle. - It has been tested on: - - Hot Potatoes 6 - - Moodle 1.1 thru 1.6 - - PHP 4.1 thru 5.0 - - MySQL and PostgreSQL databases - - This module may be distributed under the terms of the General Public License - (see http://www.gnu.org/licenses/gpl.txt for details) - - This software is provided "AS IS" without a warranty of any kind. - - Sponsors who have generously contributed to the development of this software: - - - Agencia de Gestio d'Ajuts Universitaris i de Recerca (AGAUR), - Autonomous Government of Catalonia, Spain - (via Josep M. Fontana, Universitat Pompeu Fabra) - - - Rikkyo Univeristy, Japan (via Paul Allum) - - - Universite de Franche-Comte, France (via Glenys Hanson) - - -================ -IMPORTANT NOTICE -================ -* Please be sure to use Hot Potatoes according to the conditions of use which are listed at the end of this file. If you restrict use via a required Moodle login, you most likely can still meet the 'freely available' condition if you make the same material on a separate URL that permits free access. Otherwise, please purchase a license. - - -TO INSTALL OR UPDATE THIS MODULE - -1. Install the core scripts of the hotpot module - - EITHER: - (a) download the zip file into the "moodle/mod" folder on your Moodle site - (b) unzip the zip file. This will create a folder called "moodle/mod/hotpot" on your Moodle site - - OR: - (a) download the zip file onto your PC - (b) upzip the zip file on your PC. This will create a "hotpot" folder on your PC - (c) create a folder called "hotpot" on your Moodle site in the "moodle/mod" folder - (d) upload the contents of the "hotpot" folder on your PC to the "moodle/mod/hotpot" folder on the Moodle site - -2. Install the messages and help files of the hotpot module - - EITHER: - (a) copy "moodle/mod/hotpot/lang/en/hotpot.php" on the Moodle site to "moodle/lang/en/hotpot.php" - (b) copy "moodle/mod/hotpot/lang/en/help/hotpot" on the Moodle site to "moodle/lang/en/help/hotpot" - (c) repeat for other languages you require from the "moodle/mod/hotpot/lang" folder - - OR: - (a) upload the "hotpot/lang/en/hotpot.php" file on your PC to "moodle/lang/en/hotpot.php" on the Moodle site - (b) create a folder called "hotpot" on your Moodle site in the "moodle/lang/en/help" folder - (c) upload the contents of the "hotpot/lang/en/help/hotpot" folder on your PC to the "moodle/lang/en/help/hotpot" folder on the Moodle site - (d) repeat for other languages you require from the "moodle/mod/hotpot/lang" folder - -3. copy and set up the file icons - [This step is not required for Moodle 1.5 and later, and is optional for Moodle 1.1 to 1.4] - - (a) copy the files in the "mod/hotpot/pix/f" folder on your Moodle site to "moodle/pix/f" - (b) open the "moodle/files/mimetypes.php" file on your Moodle site with a text editor - (c) insert the following lines just AFTER the line which reads "$mimeinfo = array (": - - // additional mimetypes for the "hotpot" module - "jcb" => array ("type"=>"text/xml", "icon"=>"jcb.gif"), - "jcl" => array ("type"=>"text/xml", "icon"=>"jcl.gif"), - "jcw" => array ("type"=>"text/xml", "icon"=>"jcw.gif"), - "jmt" => array ("type"=>"text/xml", "icon"=>"jmt.gif"), - "jmx" => array ("type"=>"text/xml", "icon"=>"jmx.gif"), - "jqz" => array ("type"=>"text/xml", "icon"=>"jqz.gif"), - "rhb" => array ("type"=>"text/xml", "icon"=>"xml.gif"), - "sqt" => array ("type"=>"text/xml", "icon"=>"xml.gif"), - - (d) save the changes and close the file - -4. enable import from Hot Potatoes XML files to Moodle's Quiz module - [This step is not required for Moodle 1.5 and later, and is optional for Moodle 1.1 to 1.4] - - (a) create a folder called "hotpot" on your Moodle site in the "moodle/mod/quiz/format" folder - (b) copy the "contents of the "moodle/mod/hotpot/quiz/format/hotpot" folder on your Moodle site to the "moodle/mod/quiz/format/hotpot" folder - (c) open the "moodle/lang/en/quiz.php" file on your Moodle site with a text editor - (d) insert the following line just BEFORE the final line which reads "?>": - - $string['hotpot'] = 'Hot Potatoes XML format'; - - (d) save the changes and close the file - - Steps (e), (f) and (g) are only required on Moodle 1.4.5 - - (e) open the "moodle/mod/quiz/import.php" file on your Moodle site with a text editor - (f) if necessary, add 'hotpot' to the "fileformats" array on lines 9-10: - - $fileformats = array('aiken','aon','blackboard','coursetestmanager', - 'gift','learnwise','missingword','webct','xml','hotpot' ); - - (g) save the changes and close the file - -5. Login to your Moodle site as an administrator. - - a) If you are installing this module for the first time, you should see a report saying that the following (prefix)_hotpot tables have been successfuly created: - hotpot - hotpot_attempts - hotpot_questions - hotpot_responses - hotpot_strings - - b) If you are updating the module, you will probably see messages indicating the progress of the update - - c) If you get error messages, please copy and save them to a file on your PC, and then ask for help on Moodle's HotPot support forum: - go to http://moodle.org - then click "Free Support", - then click "HotPot" - - -TO USE THIS MODULE: - -1. Create a Hot Potatoes quiz of any type using Version 6 of Hot Potatoes. - -2. Upload the quiz's source file (".jcl", ".jcw", ".jmt", ".jmx", ".jqz") or ".html" file to the file area of the intended course. - -3. Also upload any graphics, sound files, stylesheets or javascripts that the quiz uses - -4. On the main page for the course, confirm editing is turned on (click the "Turn editing on" button) then select "ADD / Hot Potatoes XML Quiz". - -6, The "Adding a new Hot Potatoes Quiz" page appears. Click the "Choose or Upload a file ..." button and select the desired quiz file. - -7. Review the other settings for the quiz and click "Save Changes" when you are ready - -8. You can view reports of the results via the "Hot Potatoes Quizzes" link on the "Activities menu". Students will see links to all the quizzes. Administrators and teachers will additionally see links to the statistical reports for each quiz. - -9. You can also import the questions from the Hot Potatoes source file to the Moodle Quiz database, if you installed "mod/quiz/format/hotpot/format.php" - - -============================== -HOT POTATOES CONDITIONS OF USE -============================== - -**Reproduced from the Hot Potatoes site** - -Hot Potatoes is offered free to the educational community by the University of Victoria Humanities Computing and Media Centre (formerly the Language Centre), under certain conditions. Hot Potatoes is free for use by state educational institutions which are non-profit making, on the condition that the material produced using the program is freely available to anyone via the WWW. However, you need to purchase a licence under any of the following conditions: -* You do not work for a public sector educational establishment. -* You charge money for access to the material you make with Hot Potatoes. -* You restrict access to the material in some way. (The only exception here is if you have an account on www.hotpot.net, where you ARE allowed to use password restrictions.) -* You want to use the Masher program included with the Hot Potatoes suite. - -For more information on licences, and details on how to purchase one, check out our Website at: - http://www.halfbakedsoftware.com/hotpot/ - -If you intend using the programs to generate more than a handful of exercises, please make sure you register. This costs you nothing -- see How to register for details. -Martin Holmes, Half-Baked Software and the University of Victoria HCMC, 1998-2004. +This is v2.1.5 of the HotPot module + This module allows teachers to administer Hot Potatoes and TexToys quizzes via Moodle. + It has been tested on: + - Hot Potatoes 6 + - Moodle 1.1 thru 1.6 + - PHP 4.1 thru 5.0 + - MySQL and PostgreSQL databases + This module may be distributed under the terms of the General Public License + (see http://www.gnu.org/licenses/gpl.txt for details) + This software is provided "AS IS" without a warranty of any kind. + Sponsors who have generously contributed to the development of this software: + - Agencia de Gestio d'Ajuts Universitaris i de Recerca (AGAUR), + Autonomous Government of Catalonia, Spain + (via Josep M. Fontana, Universitat Pompeu Fabra) + - Rikkyo Univeristy, Japan (via Paul Allum) + - Universite de Franche-Comte, France (via Glenys Hanson) +================ +IMPORTANT NOTICE +================ +* Please be sure to use Hot Potatoes according to the conditions of use which are listed at the end of this file. If you restrict use via a required Moodle login, you most likely can still meet the 'freely available' condition if you make the same material on a separate URL that permits free access. Otherwise, please purchase a license. +TO INSTALL OR UPDATE THIS MODULE +1. Install the core scripts of the hotpot module + EITHER: + (a) download the zip file into the "moodle/mod" folder on your Moodle site + (b) unzip the zip file. This will create a folder called "moodle/mod/hotpot" on your Moodle site + OR: + (a) download the zip file onto your PC + (b) upzip the zip file on your PC. This will create a "hotpot" folder on your PC + (c) create a folder called "hotpot" on your Moodle site in the "moodle/mod" folder + (d) upload the contents of the "hotpot" folder on your PC to the "moodle/mod/hotpot" folder on the Moodle site +2. Install the messages and help files of the hotpot module + EITHER: + (a) copy "moodle/mod/hotpot/lang/en/hotpot.php" on the Moodle site to "moodle/lang/en/hotpot.php" + (b) copy "moodle/mod/hotpot/lang/en/help/hotpot" on the Moodle site to "moodle/lang/en/help/hotpot" + (c) repeat for other languages you require from the "moodle/mod/hotpot/lang" folder + OR: + (a) upload the "hotpot/lang/en/hotpot.php" file on your PC to "moodle/lang/en/hotpot.php" on the Moodle site + (b) create a folder called "hotpot" on your Moodle site in the "moodle/lang/en/help" folder + (c) upload the contents of the "hotpot/lang/en/help/hotpot" folder on your PC to the "moodle/lang/en/help/hotpot" folder on the Moodle site + (d) repeat for other languages you require from the "moodle/mod/hotpot/lang" folder +3. copy and set up the file icons + [This step is not required for Moodle 1.5 and later, and is optional for Moodle 1.1 to 1.4] + (a) copy the files in the "mod/hotpot/pix/f" folder on your Moodle site to "moodle/pix/f" + (b) open the "moodle/files/mimetypes.php" file on your Moodle site with a text editor + (c) insert the following lines just AFTER the line which reads "$mimeinfo = array (": + // additional mimetypes for the "hotpot" module + "jcb" => array ("type"=>"text/xml", "icon"=>"jcb.gif"), + "jcl" => array ("type"=>"text/xml", "icon"=>"jcl.gif"), + "jcw" => array ("type"=>"text/xml", "icon"=>"jcw.gif"), + "jmt" => array ("type"=>"text/xml", "icon"=>"jmt.gif"), + "jmx" => array ("type"=>"text/xml", "icon"=>"jmx.gif"), + "jqz" => array ("type"=>"text/xml", "icon"=>"jqz.gif"), + "rhb" => array ("type"=>"text/xml", "icon"=>"xml.gif"), + "sqt" => array ("type"=>"text/xml", "icon"=>"xml.gif"), + (d) save the changes and close the file +4. enable import from Hot Potatoes XML files to Moodle's Quiz module + [This step is not required for Moodle 1.5 and later, and is optional for Moodle 1.1 to 1.4] + (a) create a folder called "hotpot" on your Moodle site in the "moodle/mod/quiz/format" folder + (b) copy the "contents of the "moodle/mod/hotpot/quiz/format/hotpot" folder on your Moodle site to the "moodle/mod/quiz/format/hotpot" folder + (c) open the "moodle/lang/en/quiz.php" file on your Moodle site with a text editor + (d) insert the following line just BEFORE the final line which reads "?>": + $string['hotpot'] = 'Hot Potatoes XML format'; + (d) save the changes and close the file + + Steps (e), (f) and (g) are only required on Moodle 1.4.5 + (e) open the "moodle/mod/quiz/import.php" file on your Moodle site with a text editor + (f) if necessary, add 'hotpot' to the "fileformats" array on lines 9-10: + $fileformats = array('aiken','aon','blackboard','coursetestmanager', + 'gift','learnwise','missingword','webct','xml','hotpot' ); + (g) save the changes and close the file +5. Login to your Moodle site as an administrator. + a) If you are installing this module for the first time, you should see a report saying that the following (prefix)_hotpot tables have been successfuly created: + hotpot + hotpot_attempts + hotpot_questions + hotpot_responses + hotpot_strings + b) If you are updating the module, you will probably see messages indicating the progress of the update + + c) If you get error messages, please copy and save them to a file on your PC, and then ask for help on Moodle's HotPot support forum: + go to http://moodle.org + then click "Free Support", + then click "HotPot" +TO USE THIS MODULE: +1. Create a Hot Potatoes quiz of any type using Version 6 of Hot Potatoes. +2. Upload the quiz's source file (".jcl", ".jcw", ".jmt", ".jmx", ".jqz") or ".html" file to the file area of the intended course. +3. Also upload any graphics, sound files, stylesheets or javascripts that the quiz uses +4. On the main page for the course, confirm editing is turned on (click the "Turn editing on" button) then select "ADD / Hot Potatoes XML Quiz". +6, The "Adding a new Hot Potatoes Quiz" page appears. Click the "Choose or Upload a file ..." button and select the desired quiz file. +7. Review the other settings for the quiz and click "Save Changes" when you are ready +8. You can view reports of the results via the "Hot Potatoes Quizzes" link on the "Activities menu". Students will see links to all the quizzes. Administrators and teachers will additionally see links to the statistical reports for each quiz. +9. You can also import the questions from the Hot Potatoes source file to the Moodle Quiz database, if you installed "mod/quiz/format/hotpot/format.php" +============================== +HOT POTATOES CONDITIONS OF USE +============================== +**Reproduced from the Hot Potatoes site** +Hot Potatoes is offered free to the educational community by the University of Victoria Humanities Computing and Media Centre (formerly the Language Centre), under certain conditions. Hot Potatoes is free for use by state educational institutions which are non-profit making, on the condition that the material produced using the program is freely available to anyone via the WWW. However, you need to purchase a licence under any of the following conditions: +* You do not work for a public sector educational establishment. +* You charge money for access to the material you make with Hot Potatoes. +* You restrict access to the material in some way. (The only exception here is if you have an account on www.hotpot.net, where you ARE allowed to use password restrictions.) +* You want to use the Masher program included with the Hot Potatoes suite. +For more information on licences, and details on how to purchase one, check out our Website at: + http://www.halfbakedsoftware.com/hotpot/ +If you intend using the programs to generate more than a handful of exercises, please make sure you register. This costs you nothing -- see How to register for details. +Martin Holmes, Half-Baked Software and the University of Victoria HCMC, 1998-2004. diff --git a/mod/hotpot/backuplib.php b/mod/hotpot/backuplib.php index 928a4b604b8..71e3be8bbf9 100644 --- a/mod/hotpot/backuplib.php +++ b/mod/hotpot/backuplib.php @@ -1,330 +1,267 @@ -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 - // - //----------------------------------------------------------- - - function hotpot_backup_mods($bf, $preferences) { - // $bf : resource id for b(ackup) f(ile) - // $preferences : object containing switches and settings for this backup - - $level = 3; - $status = true; - - $table = 'hotpot'; - $select = "course=$preferences->backup_course"; - - $records_tag = ''; - $records_tags = array(); - - $record_tag = 'MOD'; - $record_tags = array('MODTYPE'=>'hotpot'); - - $excluded_tags = array(); - - $more_backup = ''; - if ($preferences->mods['hotpot']->userinfo) { - $more_backup .= '$GLOBALS["hotpot_backup_string_ids"] = array();'; - $more_backup .= '$status = hotpot_backup_attempts($bf, $record, $level, $status);'; - $more_backup .= '$status = hotpot_backup_questions($bf, $record, $level, $status);'; - $more_backup .= '$status = hotpot_backup_strings($bf, $record, $level, $status);'; - $more_backup .= 'unset($GLOBALS["hotpot_backup_string_ids"]);'; // tidy up - } - - return hotpot_backup_records( - $bf, $status, $level, - $table, $select, - $records_tag, $records_tags, - $record_tag, $record_tags, - $excluded_tags, $more_backup - ); - } - function hotpot_backup_attempts($bf, &$parent, $level, $status) { - // $parent is a reference to a hotpot record - - $table = 'hotpot_attempts'; - $select = "hotpot=$parent->id"; - - $records_tag = 'ATTEMPT_DATA'; - $records_tags = array(); - - $record_tag = 'ATTEMPT'; - $record_tags = array(); - - $more_backup = ''; - $more_backup .= 'hotpot_backup_details($bf, $record, $level, $status);'; - $more_backup .= 'hotpot_backup_responses($bf, $record, $level, $status);'; - - $excluded_tags = array('hotpot'); - - return hotpot_backup_records( - $bf, $status, $level, - $table, $select, - $records_tag, $records_tags, - $record_tag, $record_tags, - $excluded_tags, $more_backup - ); - } - function hotpot_backup_details($bf, &$parent, $level, $status) { - // $parent is a reference to an attempt record - - $table = 'hotpot_details'; - $select = "attempt=$parent->id"; - - $records_tag = ''; - $records_tags = array(); - - $record_tag = ''; - $record_tags = array(); - - $more_backup = ''; - $excluded_tags = array('id','attempt'); - - return hotpot_backup_records( - $bf, $status, $level, - $table, $select, - $records_tag, $records_tags, - $record_tag, $record_tags, - $excluded_tags, $more_backup - ); - } - function hotpot_backup_responses($bf, &$parent, $level, $status) { - // $parent is a reference to an attempt record - - $table = 'hotpot_responses'; - $select = "attempt=$parent->id"; - - $records_tag = 'RESPONSE_DATA'; - $records_tags = array(); - - $record_tag = 'RESPONSE'; - $record_tags = array(); - - $more_backup = 'hotpot_backup_string_ids($record, array("correct","wrong","ignored"));'; - $excluded_tags = array('id','attempt'); - - return hotpot_backup_records( - $bf, $status, $level, - $table, $select, - $records_tag, $records_tags, - $record_tag, $record_tags, - $excluded_tags, $more_backup - ); - } - function hotpot_backup_questions($bf, &$parent, $level, $status) { - // $parent is a reference to an hotpot record - - $table = 'hotpot_questions'; - $select = "hotpot=$parent->id"; - - $records_tag = 'QUESTION_DATA'; - $records_tags = array(); - - $record_tag = 'QUESTION'; - $record_tags = array(); - - $more_backup = 'hotpot_backup_string_ids($record, array("text"));'; - $excluded_tags = array('hotpot'); - - return hotpot_backup_records( - $bf, $status, $level, - $table, $select, - $records_tag, $records_tags, - $record_tag, $record_tags, - $excluded_tags, $more_backup - ); - } - function hotpot_backup_string_ids(&$record, $fields) { - // as the questions and responses tables are backed up - // this function is called to store the ids of strings. - // The string ids are used later by "hotpot_backup_strings" - // $GLOBALS['hotpot_backup_string_ids'] was initialized in "hotpot_backup_mods" - - // store the ids of strings used in this $record's $fields - foreach ($fields as $field) { - if (empty($record->$field)) { - // do nothing - } else { - $value = $record->$field; - $ids = explode(',', "$value"); - foreach ($ids as $id) { - if (empty($id)) { - // do nothing - } else { - $GLOBALS['hotpot_backup_string_ids'][$id] = true; - } - } - } - } - } - function hotpot_backup_strings($bf, $record, $level, $status) { - // This functions backups the strings used - // in the question and responses for a single hotpot activity - // The ids of the strings were stored by "hotpot_backup_string_ids" - // $GLOBALS['hotpot_backup_string_ids'] was initialized in "hotpot_backup_mods" - - // retrieve $ids of strings to be backed up - $ids = array_keys($GLOBALS['hotpot_backup_string_ids']); - - if (empty($ids)) { - // no strings to backup - } else { - - sort($ids); - $ids = implode(',', $ids); - - $table = 'hotpot_strings'; - $select = "id IN ($ids)"; - - $records_tag = 'STRING_DATA'; - $records_tags = array(); - - $record_tag = 'STRING'; - $record_tags = array(); - - $more_backup = ''; - $excluded_tags = array(''); - - $status = hotpot_backup_records( - $bf, $status, $level, - $table, $select, - $records_tag, $records_tags, - $record_tag, $record_tags, - $excluded_tags, $more_backup - ); - } - return $status; - } - - function hotpot_backup_records(&$bf, $status, $level, $table, $select, $records_tag, $records_tags, $record_tag, $record_tags, $excluded_tags, $more_backup) { - // general purpose backup function - - // $bf : resource id of backup file - // $status : current status of backup (true or false) - // $level : current depth level in the backup XML tree - - // $table : table from which records will be selected and backed up - // $select : SQL selection string - - // $records_tag : optional XML tag which starts a group of records (and descends a level) - // $records_tags : optional XML tags to be inserted at the start of a group of records - - // $record_tag : optional XML tag which starts a record (and descends a level) - // $record_tags : optional XML tags to be inserted at the start of a record - - // $excluded_tags : fields which will NOT be backed up from the records - // $more_backup : optional PHP code to be eval(uated) for each record - - // If any of the "fwrite" statements fail, - // no further "fwrite"s will be attempted - // and the function returns "false". - // Otherwise, the function returns "true". - - if ($status && ($records = get_records_select($table, $select, 'id'))) { - - // start a group of records - if ($records_tag) { - $status = $status && fwrite($bf, start_tag($records_tag, $level, true)); - $level++; - - foreach ($records_tags as $tag) { - $status = $status && fwrite($bf, full_tag($tag, $level, false, $value)); - } - } - - foreach ($records as $record) { - - // start a single record - if ($record_tag) { - $status = $status && fwrite($bf, start_tag($record_tag, $level, true)); - $level++; - - foreach ($record_tags as $tag=>$value) { - $status = $status && fwrite($bf, full_tag($tag, $level, false, $value)); - } - } - - // backup fields in this record - $tags = get_object_vars($record); - foreach ($tags as $tag=>$value) { - if (!is_numeric($tag) && !in_array($tag, $excluded_tags)) { - $status = $status && fwrite($bf, full_tag($tag, $level, false, $value)); - } - } - - // backup related records, if required - if ($more_backup) { - eval($more_backup); - } - - // end a single record - if ($record_tag) { - $level--; - $status = $status && fwrite($bf, end_tag($record_tag, $level, true)); - } - } - - // end a group of records - if ($records_tag) { - $level--; - $status = $status && fwrite($bf, end_tag($records_tag, $level, true)); - } - } - - return $status; - } - - ////Return an array of info (name, value) - function hotpot_check_backup_mods($course, $user_data=false, $backup_unique_code) { - - // the course data - $info[0][0] = get_string('modulenameplural','hotpot'); - $info[0][1] = count_records('hotpot', 'course', $course); - - // the user_data, if requested - if ($user_data) { - global $CFG; - $table = "{$CFG->prefix}hotpot h, {$CFG->prefix}hotpot_attempts a"; - $select = "h.course = $course AND h.id = a.hotpot"; - - $info[1][0] = get_string('attempts', 'quiz'); - $info[1][1] = count_records_sql("SELECT COUNT(*) FROM $table WHERE $select"); - } - - return $info; - } - -?> +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 + // + //----------------------------------------------------------- + function hotpot_backup_mods($bf, $preferences) { + // $bf : resource id for b(ackup) f(ile) + // $preferences : object containing switches and settings for this backup + $level = 3; + $status = true; + $table = 'hotpot'; + $select = "course=$preferences->backup_course"; + $records_tag = ''; + $records_tags = array(); + $record_tag = 'MOD'; + $record_tags = array('MODTYPE'=>'hotpot'); + $excluded_tags = array(); + $more_backup = ''; + if ($preferences->mods['hotpot']->userinfo) { + $more_backup .= '$GLOBALS["hotpot_backup_string_ids"] = array();'; + $more_backup .= '$status = hotpot_backup_attempts($bf, $record, $level, $status);'; + $more_backup .= '$status = hotpot_backup_questions($bf, $record, $level, $status);'; + $more_backup .= '$status = hotpot_backup_strings($bf, $record, $level, $status);'; + $more_backup .= 'unset($GLOBALS["hotpot_backup_string_ids"]);'; // tidy up + } + return hotpot_backup_records( + $bf, $status, $level, + $table, $select, + $records_tag, $records_tags, + $record_tag, $record_tags, + $excluded_tags, $more_backup + ); + } + function hotpot_backup_attempts($bf, &$parent, $level, $status) { + // $parent is a reference to a hotpot record + $table = 'hotpot_attempts'; + $select = "hotpot=$parent->id"; + $records_tag = 'ATTEMPT_DATA'; + $records_tags = array(); + $record_tag = 'ATTEMPT'; + $record_tags = array(); + $more_backup = ''; + $more_backup .= 'hotpot_backup_details($bf, $record, $level, $status);'; + $more_backup .= 'hotpot_backup_responses($bf, $record, $level, $status);'; + $excluded_tags = array('hotpot'); + return hotpot_backup_records( + $bf, $status, $level, + $table, $select, + $records_tag, $records_tags, + $record_tag, $record_tags, + $excluded_tags, $more_backup + ); + } + function hotpot_backup_details($bf, &$parent, $level, $status) { + // $parent is a reference to an attempt record + $table = 'hotpot_details'; + $select = "attempt=$parent->id"; + $records_tag = ''; + $records_tags = array(); + $record_tag = ''; + $record_tags = array(); + $more_backup = ''; + $excluded_tags = array('id','attempt'); + return hotpot_backup_records( + $bf, $status, $level, + $table, $select, + $records_tag, $records_tags, + $record_tag, $record_tags, + $excluded_tags, $more_backup + ); + } + function hotpot_backup_responses($bf, &$parent, $level, $status) { + // $parent is a reference to an attempt record + $table = 'hotpot_responses'; + $select = "attempt=$parent->id"; + $records_tag = 'RESPONSE_DATA'; + $records_tags = array(); + $record_tag = 'RESPONSE'; + $record_tags = array(); + $more_backup = 'hotpot_backup_string_ids($record, array("correct","wrong","ignored"));'; + $excluded_tags = array('id','attempt'); + return hotpot_backup_records( + $bf, $status, $level, + $table, $select, + $records_tag, $records_tags, + $record_tag, $record_tags, + $excluded_tags, $more_backup + ); + } + function hotpot_backup_questions($bf, &$parent, $level, $status) { + // $parent is a reference to an hotpot record + $table = 'hotpot_questions'; + $select = "hotpot=$parent->id"; + $records_tag = 'QUESTION_DATA'; + $records_tags = array(); + $record_tag = 'QUESTION'; + $record_tags = array(); + $more_backup = 'hotpot_backup_string_ids($record, array("text"));'; + $excluded_tags = array('hotpot'); + return hotpot_backup_records( + $bf, $status, $level, + $table, $select, + $records_tag, $records_tags, + $record_tag, $record_tags, + $excluded_tags, $more_backup + ); + } + function hotpot_backup_string_ids(&$record, $fields) { + // as the questions and responses tables are backed up + // this function is called to store the ids of strings. + // The string ids are used later by "hotpot_backup_strings" + // $GLOBALS['hotpot_backup_string_ids'] was initialized in "hotpot_backup_mods" + // store the ids of strings used in this $record's $fields + foreach ($fields as $field) { + if (empty($record->$field)) { + // do nothing + } else { + $value = $record->$field; + $ids = explode(',', "$value"); + foreach ($ids as $id) { + if (empty($id)) { + // do nothing + } else { + $GLOBALS['hotpot_backup_string_ids'][$id] = true; + } + } + } + } + } + function hotpot_backup_strings($bf, $record, $level, $status) { + // This functions backups the strings used + // in the question and responses for a single hotpot activity + // The ids of the strings were stored by "hotpot_backup_string_ids" + // $GLOBALS['hotpot_backup_string_ids'] was initialized in "hotpot_backup_mods" + // retrieve $ids of strings to be backed up + $ids = array_keys($GLOBALS['hotpot_backup_string_ids']); + if (empty($ids)) { + // no strings to backup + } else { + sort($ids); + $ids = implode(',', $ids); + $table = 'hotpot_strings'; + $select = "id IN ($ids)"; + $records_tag = 'STRING_DATA'; + $records_tags = array(); + $record_tag = 'STRING'; + $record_tags = array(); + $more_backup = ''; + $excluded_tags = array(''); + $status = hotpot_backup_records( + $bf, $status, $level, + $table, $select, + $records_tag, $records_tags, + $record_tag, $record_tags, + $excluded_tags, $more_backup + ); + } + return $status; + } + function hotpot_backup_records(&$bf, $status, $level, $table, $select, $records_tag, $records_tags, $record_tag, $record_tags, $excluded_tags, $more_backup) { + // general purpose backup function + // $bf : resource id of backup file + // $status : current status of backup (true or false) + // $level : current depth level in the backup XML tree + // $table : table from which records will be selected and backed up + // $select : SQL selection string + // $records_tag : optional XML tag which starts a group of records (and descends a level) + // $records_tags : optional XML tags to be inserted at the start of a group of records + // $record_tag : optional XML tag which starts a record (and descends a level) + // $record_tags : optional XML tags to be inserted at the start of a record + // $excluded_tags : fields which will NOT be backed up from the records + // $more_backup : optional PHP code to be eval(uated) for each record + // If any of the "fwrite" statements fail, + // no further "fwrite"s will be attempted + // and the function returns "false". + // Otherwise, the function returns "true". + if ($status && ($records = get_records_select($table, $select, 'id'))) { + // start a group of records + if ($records_tag) { + $status = $status && fwrite($bf, start_tag($records_tag, $level, true)); + $level++; + foreach ($records_tags as $tag) { + $status = $status && fwrite($bf, full_tag($tag, $level, false, $value)); + } + } + foreach ($records as $record) { + // start a single record + if ($record_tag) { + $status = $status && fwrite($bf, start_tag($record_tag, $level, true)); + $level++; + foreach ($record_tags as $tag=>$value) { + $status = $status && fwrite($bf, full_tag($tag, $level, false, $value)); + } + } + // backup fields in this record + $tags = get_object_vars($record); + foreach ($tags as $tag=>$value) { + if (!is_numeric($tag) && !in_array($tag, $excluded_tags)) { + $status = $status && fwrite($bf, full_tag($tag, $level, false, $value)); + } + } + // backup related records, if required + if ($more_backup) { + eval($more_backup); + } + // end a single record + if ($record_tag) { + $level--; + $status = $status && fwrite($bf, end_tag($record_tag, $level, true)); + } + } + // end a group of records + if ($records_tag) { + $level--; + $status = $status && fwrite($bf, end_tag($records_tag, $level, true)); + } + } + return $status; + } + ////Return an array of info (name, value) + function hotpot_check_backup_mods($course, $user_data=false, $backup_unique_code) { + // the course data + $info[0][0] = get_string('modulenameplural','hotpot'); + $info[0][1] = count_records('hotpot', 'course', $course); + // the user_data, if requested + if ($user_data) { + global $CFG; + $table = "{$CFG->prefix}hotpot h, {$CFG->prefix}hotpot_attempts a"; + $select = "h.course = $course AND h.id = a.hotpot"; + $info[1][0] = get_string('attempts', 'quiz'); + $info[1][1] = count_records_sql("SELECT COUNT(*) FROM $table WHERE $select"); + } + return $info; + } +?> diff --git a/mod/hotpot/db/mysql.php b/mod/hotpot/db/mysql.php index 5de58505dcf..c8771989dd1 100644 --- a/mod/hotpot/db/mysql.php +++ b/mod/hotpot/db/mysql.php @@ -1,43 +1,37 @@ -prefix}hotpot_events` ADD `starttime` INT(10) unsigned NOT NULL DEFAULT '0' AFTER `time`"); - execute_sql(" ALTER TABLE `{$CFG->prefix}hotpot_events` ADD `endtime` INT(10) unsigned NOT NULL DEFAULT '0' AFTER `time`"); - } - - // update from HotPot v1 to HotPot v2 - if ($oldversion < 2005031400) { - $ok = $ok && hotpot_get_update_to_v2(); - $ok = $ok && hotpot_update_to_v2_from_v1(); - } - - // update to HotPot v2.1 - if ($oldversion < 2005090700) { - $ok = $ok && hotpot_get_update_to_v2(); - $ok = $ok && hotpot_update_to_v2_1(); - } - - // update to from HotPot v2.1.0 or v2.1.1 to HotPot v2.1.2 - if ($oldversion > 2005031419 && $oldversion < 2005090702) { - $ok = $ok && hotpot_get_update_to_v2(); - $ok = $ok && hotpot_update_to_v2_1_2(); - } - - return $ok; -} -function hotpot_get_update_to_v2() { - global $CFG; - $filepath = "$CFG->dirroot/mod/hotpot/db/update_to_v2.php"; - if (file_exists($filepath) && is_readable($filepath)) { - include_once $filepath; - $ok = true; - } else { - $ok = false; - } - return $ok; -} -?> +prefix}hotpot_events` ADD `starttime` INT(10) unsigned NOT NULL DEFAULT '0' AFTER `time`"); + execute_sql(" ALTER TABLE `{$CFG->prefix}hotpot_events` ADD `endtime` INT(10) unsigned NOT NULL DEFAULT '0' AFTER `time`"); + } + // update from HotPot v1 to HotPot v2 + if ($oldversion < 2005031400) { + $ok = $ok && hotpot_get_update_to_v2(); + $ok = $ok && hotpot_update_to_v2_from_v1(); + } + // update to HotPot v2.1 + if ($oldversion < 2005090700) { + $ok = $ok && hotpot_get_update_to_v2(); + $ok = $ok && hotpot_update_to_v2_1(); + } + // update to from HotPot v2.1.0 or v2.1.1 to HotPot v2.1.2 + if ($oldversion > 2005031419 && $oldversion < 2005090702) { + $ok = $ok && hotpot_get_update_to_v2(); + $ok = $ok && hotpot_update_to_v2_1_2(); + } + return $ok; +} +function hotpot_get_update_to_v2() { + global $CFG; + $filepath = "$CFG->dirroot/mod/hotpot/db/update_to_v2.php"; + if (file_exists($filepath) && is_readable($filepath)) { + include_once $filepath; + $ok = true; + } else { + $ok = false; + } + return $ok; +} +?> diff --git a/mod/hotpot/db/mysql.sql b/mod/hotpot/db/mysql.sql index 49887bcd1f1..36ba340fca2 100644 --- a/mod/hotpot/db/mysql.sql +++ b/mod/hotpot/db/mysql.sql @@ -1,112 +1,101 @@ -# -# Table structure for table `hotpot` -# - -CREATE TABLE prefix_hotpot ( - id int(10) unsigned NOT NULL auto_increment, - course int(10) unsigned NOT NULL default '0', - name varchar(255) NOT NULL default '', - reference varchar(255) NOT NULL default '', - summary text NOT NULL, - timeopen int(10) unsigned NOT NULL default '0', - timeclose int(10) unsigned NOT NULL default '0', - attempts smallint(6) NOT NULL default '0', - grademethod tinyint(4) NOT NULL default '1', - review tinyint(4) NOT NULL default '0', - grade int(10) NOT NULL default '0', - timecreated int(10) unsigned NOT NULL default '0', - timemodified int(10) unsigned NOT NULL default '0', - location int(4) unsigned NOT NULL default '0', - navigation int(4) unsigned NOT NULL default '1', - outputformat int(4) unsigned NOT NULL default '1', - shownextquiz int(4) unsigned NOT NULL default '0', - forceplugins int(4) unsigned NOT NULL default '0', - password varchar(255) NOT NULL default '', - subnet varchar(255) NOT NULL default '', - clickreporting tinyint(4) unsigned NOT NULL default '0', - studentfeedback tinyint(4) unsigned NOT NULL default '0', - studentfeedbackurl varchar(255) default NULL, - PRIMARY KEY (id) -) TYPE=MyISAM COMMENT='details about Hot Potatoes quizzes'; - -# -# Table structure for table `hotpot_attempts` -# - -CREATE TABLE prefix_hotpot_attempts ( - id int(10) unsigned NOT NULL auto_increment, - hotpot int(10) unsigned NOT NULL default '0', - userid int(10) unsigned NOT NULL default '0', - starttime int(10) unsigned default NULL, - endtime int(10) unsigned default NULL, - score int(6) unsigned default NULL, - penalties int(6) unsigned default NULL, - attempt int(6) unsigned NOT NULL default '0', - timestart int(10) unsigned default NULL, - timefinish int(10) unsigned default NULL, - status tinyint(4) unsigned NOT NULL default '1', - clickreportid int(10) unsigned default NULL, - PRIMARY KEY (id), - KEY prefix_hotpot_attempts_hotpot_idx (hotpot), - KEY prefix_hotpot_attempts_userid_idx (userid) -) TYPE=MyISAM COMMENT='details about Hot Potatoes quiz attempts'; - -# -# Table structure for table `hotpot_details` -# - -CREATE TABLE prefix_hotpot_details ( - id int(10) unsigned NOT NULL auto_increment, - attempt int(10) unsigned NOT NULL, - details text, - PRIMARY KEY (id), - KEY prefix_hotpot_details_attempt_idx (attempt) -) TYPE=MyISAM COMMENT='raw details (as XML) of Hot Potatoes quiz attempts'; - -# -# Table structure for table `hotpot_questions` -# - -CREATE TABLE prefix_hotpot_questions ( - id int(10) unsigned NOT NULL auto_increment, - name text NOT NULL, - type tinyint(4) unsigned default NULL, - text int(10) unsigned default NULL, - hotpot int(10) unsigned NOT NULL default '0', - PRIMARY KEY (id), - KEY prefix_hotpot_questions_name_idx (name(20)), - KEY prefix_hotpot_questions_hotpot_idx (hotpot) -) TYPE=MyISAM COMMENT='details about questions in Hot Potatatoes quiz attempts'; - -# -# Table structure for table `hotpot_responses` -# - -CREATE TABLE prefix_hotpot_responses ( - id int(10) unsigned NOT NULL auto_increment, - attempt int(10) unsigned NOT NULL default '0', - question int(10) unsigned NOT NULL default '0', - score smallint(8) default NULL, - weighting smallint(8) default NULL, - correct varchar(255) default NULL, - wrong varchar(255) default NULL, - ignored varchar(255) default NULL, - hints smallint(6) default NULL, - clues smallint(6) default NULL, - checks smallint(6) default NULL, - PRIMARY KEY (id), - KEY prefix_hotpot_responses_attempt_idx (attempt), - KEY prefix_hotpot_responses_question_idx (question) -) TYPE=MyISAM COMMENT='details about responses in Hot Potatatoes quiz attempts'; - -# -# Table structure for table `hotpot_strings` -# - -CREATE TABLE prefix_hotpot_strings ( - id int(10) unsigned NOT NULL auto_increment, - string text NOT NULL, - PRIMARY KEY (id), - KEY prefix_hotpot_strings_string_idx (string(20)) -) TYPE=MyISAM COMMENT='strings used in Hot Potatatoes questions and responses'; +# +# Table structure for table `hotpot` +# +CREATE TABLE prefix_hotpot ( + id int(10) unsigned NOT NULL auto_increment, + course int(10) unsigned NOT NULL default '0', + name varchar(255) NOT NULL default '', + reference varchar(255) NOT NULL default '', + summary text NOT NULL, + timeopen int(10) unsigned NOT NULL default '0', + timeclose int(10) unsigned NOT NULL default '0', + attempts smallint(6) NOT NULL default '0', + grademethod tinyint(4) NOT NULL default '1', + review tinyint(4) NOT NULL default '0', + grade int(10) NOT NULL default '0', + timecreated int(10) unsigned NOT NULL default '0', + timemodified int(10) unsigned NOT NULL default '0', + location int(4) unsigned NOT NULL default '0', + navigation int(4) unsigned NOT NULL default '1', + outputformat int(4) unsigned NOT NULL default '1', + shownextquiz int(4) unsigned NOT NULL default '0', + forceplugins int(4) unsigned NOT NULL default '0', + password varchar(255) NOT NULL default '', + subnet varchar(255) NOT NULL default '', + clickreporting tinyint(4) unsigned NOT NULL default '0', + studentfeedback tinyint(4) unsigned NOT NULL default '0', + studentfeedbackurl varchar(255) default NULL, + PRIMARY KEY (id) +) TYPE=MyISAM COMMENT='details about Hot Potatoes quizzes'; +# +# Table structure for table `hotpot_attempts` +# +CREATE TABLE prefix_hotpot_attempts ( + id int(10) unsigned NOT NULL auto_increment, + hotpot int(10) unsigned NOT NULL default '0', + userid int(10) unsigned NOT NULL default '0', + starttime int(10) unsigned default NULL, + endtime int(10) unsigned default NULL, + score int(6) unsigned default NULL, + penalties int(6) unsigned default NULL, + attempt int(6) unsigned NOT NULL default '0', + timestart int(10) unsigned default NULL, + timefinish int(10) unsigned default NULL, + status tinyint(4) unsigned NOT NULL default '1', + clickreportid int(10) unsigned default NULL, + PRIMARY KEY (id), + KEY prefix_hotpot_attempts_hotpot_idx (hotpot), + KEY prefix_hotpot_attempts_userid_idx (userid) +) TYPE=MyISAM COMMENT='details about Hot Potatoes quiz attempts'; +# +# Table structure for table `hotpot_details` +# +CREATE TABLE prefix_hotpot_details ( + id int(10) unsigned NOT NULL auto_increment, + attempt int(10) unsigned NOT NULL, + details text, + PRIMARY KEY (id), + KEY prefix_hotpot_details_attempt_idx (attempt) +) TYPE=MyISAM COMMENT='raw details (as XML) of Hot Potatoes quiz attempts'; +# +# Table structure for table `hotpot_questions` +# +CREATE TABLE prefix_hotpot_questions ( + id int(10) unsigned NOT NULL auto_increment, + name text NOT NULL, + type tinyint(4) unsigned default NULL, + text int(10) unsigned default NULL, + hotpot int(10) unsigned NOT NULL default '0', + PRIMARY KEY (id), + KEY prefix_hotpot_questions_name_idx (name(20)), + KEY prefix_hotpot_questions_hotpot_idx (hotpot) +) TYPE=MyISAM COMMENT='details about questions in Hot Potatatoes quiz attempts'; +# +# Table structure for table `hotpot_responses` +# +CREATE TABLE prefix_hotpot_responses ( + id int(10) unsigned NOT NULL auto_increment, + attempt int(10) unsigned NOT NULL default '0', + question int(10) unsigned NOT NULL default '0', + score smallint(8) default NULL, + weighting smallint(8) default NULL, + correct varchar(255) default NULL, + wrong varchar(255) default NULL, + ignored varchar(255) default NULL, + hints smallint(6) default NULL, + clues smallint(6) default NULL, + checks smallint(6) default NULL, + PRIMARY KEY (id), + KEY prefix_hotpot_responses_attempt_idx (attempt), + KEY prefix_hotpot_responses_question_idx (question) +) TYPE=MyISAM COMMENT='details about responses in Hot Potatatoes quiz attempts'; +# +# Table structure for table `hotpot_strings` +# +CREATE TABLE prefix_hotpot_strings ( + id int(10) unsigned NOT NULL auto_increment, + string text NOT NULL, + PRIMARY KEY (id), + KEY prefix_hotpot_strings_string_idx (string(20)) +) TYPE=MyISAM COMMENT='strings used in Hot Potatatoes questions and responses'; \ No newline at end of file diff --git a/mod/hotpot/db/postgres7.php b/mod/hotpot/db/postgres7.php index a904e1511f8..8cca5099a65 100644 --- a/mod/hotpot/db/postgres7.php +++ b/mod/hotpot/db/postgres7.php @@ -1,39 +1,33 @@ - 2005031419 && $oldversion < 2005090702) { - $ok = $ok && hotpot_get_update_to_v2(); - $ok = $ok && hotpot_update_to_v2_1_2(); - } - - return $ok; -} -function hotpot_get_update_to_v2() { - global $CFG; - $filepath = "$CFG->dirroot/mod/hotpot/db/update_to_v2.php"; - if (file_exists($filepath) && is_readable($filepath)) { - include_once $filepath; - $ok = true; - } else { - $ok = false; - } - return $ok; -} -?> + 2005031419 && $oldversion < 2005090702) { + $ok = $ok && hotpot_get_update_to_v2(); + $ok = $ok && hotpot_update_to_v2_1_2(); + } + return $ok; +} +function hotpot_get_update_to_v2() { + global $CFG; + $filepath = "$CFG->dirroot/mod/hotpot/db/update_to_v2.php"; + if (file_exists($filepath) && is_readable($filepath)) { + include_once $filepath; + $ok = true; + } else { + $ok = false; + } + return $ok; +} +?> diff --git a/mod/hotpot/db/postgres7.sql b/mod/hotpot/db/postgres7.sql index bfc643ff6e2..c58bf9c2eed 100644 --- a/mod/hotpot/db/postgres7.sql +++ b/mod/hotpot/db/postgres7.sql @@ -1,114 +1,98 @@ -# -# Table structure for table `hotpot` -# - -CREATE TABLE prefix_hotpot ( - id SERIAL PRIMARY KEY, - course INT4 NOT NULL default '0', - name VARCHAR(255) NOT NULL default '', - summary TEXT, - timeopen INT4 NOT NULL default '0', - timeclose INT4 NOT NULL default '0', - location INT2 NOT NULL default '0', - reference VARCHAR(255) NOT NULL default '', - navigation INT2 NOT NULL default '1', - outputformat INT2 NOT NULL default '1', - forceplugins INT2 NOT NULL default '0', - shownextquiz INT2 NOT NULL default '0', - microreporting INT2 NOT NULL default '0', - studentfeedback VARCHAR(255) NOT NULL default '0', - - review INT2 NOT NULL default '0', - grade INT4 NOT NULL default '0', - grademethod INT2 NOT NULL default '1', - attempts INT2 NOT NULL default '0', - - password VARCHAR(255) NOT NULL default '', - subnet VARCHAR(255) NOT NULL default '', - timecreated INT4 NOT NULL default '0', - timemodified INT4 NOT NULL default '0' -); -COMMENT ON TABLE prefix_hotpot IS 'details about Hot Potatoes quizzes'; - - -# -# Table structure for table `hotpot_attempts` -# - -CREATE TABLE prefix_hotpot_attempts ( - id SERIAL PRIMARY KEY, - hotpot INT4 NOT NULL default '0', - userid INT4 NOT NULL default '0', - groupid INT4 NOT NULL default '0', - attempt INT2 NOT NULL default '0', - score INT2, - penalties INT2, - starttime INT4, - endtime INT4, - timestart INT4 NOT NULL default '0', - timefinish INT4 NOT NULL default '0', - status INT2 NOT NULL default '1', - microreportid INT4 -); -COMMENT ON TABLE prefix_hotpot IS 'details about Hot Potatoes quiz attempts'; -CREATE INDEX prefix_hotpot_attempts_hotpot_idx ON prefix_hotpot_attempts (hotpot); -CREATE INDEX prefix_hotpot_attempts_userid_idx ON prefix_hotpot_attempts (userid); - - -# -# Table structure for table `prefix_hotpot_details` -# - -CREATE TABLE prefix_hotpot_details ( - id SERIAL PRIMARY KEY, - attempt INT4 NOT NULL default '0', - details TEXT -); -COMMENT ON TABLE prefix_hotpot_details IS 'raw details (as XML) of Hot Potatoes quiz attempts'; -CREATE INDEX prefix_hotpot_details_attempt_idx ON prefix_hotpot_details (attempt); - - -# -# Table structure for table `hotpot_questions` -# - -CREATE TABLE prefix_hotpot_questions ( - id SERIAL PRIMARY KEY, - name TEXT, - type INT2 NOT NULL default '0', - text INT4 NULL, - hotpot INT4 NOT NULL default '0' -); -COMMENT ON TABLE prefix_hotpot_questions IS 'details about questions in Hot Potatatoes quiz attempts'; -CREATE INDEX prefix_hotpot_questions_hotpot_idx ON prefix_hotpot_questions (hotpot); - -# -# Table structure for table `hotpot_responses` -# - -CREATE TABLE prefix_hotpot_responses ( - id SERIAL PRIMARY KEY, - attempt INT4 NOT NULL default '0', - question INT4 NOT NULL default '0', - score INT2, - weighting INT2, - correct VARCHAR(255), - wrong VARCHAR(255), - ignored VARCHAR(255), - hints INT2, - clues INT2, - checks INT2 -); -COMMENT ON TABLE prefix_hotpot_responses IS 'details about responses in Hot Potatatoes quiz attempts'; -CREATE INDEX prefix_hotpot_responses_attempt_idx ON prefix_hotpot_responses (attempt); -CREATE INDEX prefix_hotpot_responses_question_idx ON prefix_hotpot_responses (question); - -# -# Table structure for table `hotpot_strings` -# - -CREATE TABLE prefix_hotpot_strings ( - id SERIAL PRIMARY KEY, - string TEXT NOT NULL -); -COMMENT ON TABLE prefix_hotpot_strings IS 'strings used in Hot Potatatoes questions and responses'; +# +# Table structure for table `hotpot` +# +CREATE TABLE prefix_hotpot ( + id SERIAL PRIMARY KEY, + course INT4 NOT NULL default '0', + name VARCHAR(255) NOT NULL default '', + summary TEXT, + timeopen INT4 NOT NULL default '0', + timeclose INT4 NOT NULL default '0', + location INT2 NOT NULL default '0', + reference VARCHAR(255) NOT NULL default '', + navigation INT2 NOT NULL default '1', + outputformat INT2 NOT NULL default '1', + forceplugins INT2 NOT NULL default '0', + shownextquiz INT2 NOT NULL default '0', + microreporting INT2 NOT NULL default '0', + studentfeedback VARCHAR(255) NOT NULL default '0', + review INT2 NOT NULL default '0', + grade INT4 NOT NULL default '0', + grademethod INT2 NOT NULL default '1', + attempts INT2 NOT NULL default '0', + password VARCHAR(255) NOT NULL default '', + subnet VARCHAR(255) NOT NULL default '', + timecreated INT4 NOT NULL default '0', + timemodified INT4 NOT NULL default '0' +); +COMMENT ON TABLE prefix_hotpot IS 'details about Hot Potatoes quizzes'; +# +# Table structure for table `hotpot_attempts` +# +CREATE TABLE prefix_hotpot_attempts ( + id SERIAL PRIMARY KEY, + hotpot INT4 NOT NULL default '0', + userid INT4 NOT NULL default '0', + groupid INT4 NOT NULL default '0', + attempt INT2 NOT NULL default '0', + score INT2, + penalties INT2, + starttime INT4, + endtime INT4, + timestart INT4 NOT NULL default '0', + timefinish INT4 NOT NULL default '0', + status INT2 NOT NULL default '1', + microreportid INT4 +); +COMMENT ON TABLE prefix_hotpot IS 'details about Hot Potatoes quiz attempts'; +CREATE INDEX prefix_hotpot_attempts_hotpot_idx ON prefix_hotpot_attempts (hotpot); +CREATE INDEX prefix_hotpot_attempts_userid_idx ON prefix_hotpot_attempts (userid); +# +# Table structure for table `prefix_hotpot_details` +# +CREATE TABLE prefix_hotpot_details ( + id SERIAL PRIMARY KEY, + attempt INT4 NOT NULL default '0', + details TEXT +); +COMMENT ON TABLE prefix_hotpot_details IS 'raw details (as XML) of Hot Potatoes quiz attempts'; +CREATE INDEX prefix_hotpot_details_attempt_idx ON prefix_hotpot_details (attempt); +# +# Table structure for table `hotpot_questions` +# +CREATE TABLE prefix_hotpot_questions ( + id SERIAL PRIMARY KEY, + name TEXT, + type INT2 NOT NULL default '0', + text INT4 NULL, + hotpot INT4 NOT NULL default '0' +); +COMMENT ON TABLE prefix_hotpot_questions IS 'details about questions in Hot Potatatoes quiz attempts'; +CREATE INDEX prefix_hotpot_questions_hotpot_idx ON prefix_hotpot_questions (hotpot); +# +# Table structure for table `hotpot_responses` +# +CREATE TABLE prefix_hotpot_responses ( + id SERIAL PRIMARY KEY, + attempt INT4 NOT NULL default '0', + question INT4 NOT NULL default '0', + score INT2, + weighting INT2, + correct VARCHAR(255), + wrong VARCHAR(255), + ignored VARCHAR(255), + hints INT2, + clues INT2, + checks INT2 +); +COMMENT ON TABLE prefix_hotpot_responses IS 'details about responses in Hot Potatatoes quiz attempts'; +CREATE INDEX prefix_hotpot_responses_attempt_idx ON prefix_hotpot_responses (attempt); +CREATE INDEX prefix_hotpot_responses_question_idx ON prefix_hotpot_responses (question); +# +# Table structure for table `hotpot_strings` +# +CREATE TABLE prefix_hotpot_strings ( + id SERIAL PRIMARY KEY, + string TEXT NOT NULL +); +COMMENT ON TABLE prefix_hotpot_strings IS 'strings used in Hot Potatatoes questions and responses'; diff --git a/mod/hotpot/db/update_to_v2.php b/mod/hotpot/db/update_to_v2.php index 32e7d2e7b26..884b8022e85 100644 --- a/mod/hotpot/db/update_to_v2.php +++ b/mod/hotpot/db/update_to_v2.php @@ -1,1298 +1,1075 @@ -prefix}hotpot_attempts - GROUP BY userid, hotpot - HAVING countrecords > 1 AND minstatus=1 - "); - - if ($records) { - - // save and switch off SQL message echo - $debug = $db->debug; - $db->debug = false; - - print "adjusting status of ".count($records)." "in progress" attempts ... "; - - foreach ($records as $record) { - // get all attempts by this user at this hotpot - $attempts = get_records_sql(" - SELECT id, userid, hotpot, score, timestart, timefinish, status - FROM {$CFG->prefix}hotpot_attempts - WHERE userid = $record->userid AND hotpot=$record->hotpot - ORDER BY timestart DESC, id DESC - "); - - unset($previous_timestart); - foreach ($attempts as $attempt) { - - // if this attempt has a status of "in progress" and is not - // the most recent one in the group, set the status to "abandoned" - if ($attempt->status==1 && isset($previous_timestart)) { - - $values = 'status=3'; - if (empty($attempt->score)) { - $values .= ',score=0'; - } - if (empty($attempt->timefinish)) { - $values .= ",timefinish=$previous_timestart"; - } - execute_sql("UPDATE {$CFG->prefix}hotpot_attempts SET $values WHERE id=$attempt->id", false); - - print "."; - hotpot_flush(300); - } - $previous_timestart = $attempt->timestart; - } // end foreach $attempts - } // end foreach $records - - print $ok ? get_string('success') : 'failed'; - print "
\n"; - - // restore SQL message echo setting - $db->debug = $debug; - } - - return $ok; -} -function hotpot_update_to_v2_1() { - global $CFG, $db; - $ok = true; - - // hotpot_questions: reduce size of "type" field to "4" - $ok = $ok && hotpot_db_update_field_type('hotpot_questions', 'type', 'type', 'INTEGER', 4, 'UNSIGNED', 'NULL'); - - // hotpot_questions: change type of "name" field to "text" - $ok = $ok && hotpot_db_update_field_type('hotpot_questions', 'name', 'name', 'TEXT', '', '', 'NOT NULL', ''); - - // hotpot_questions: nullify empty and non-numeric (shouldn't be any) values in "text" field - switch (strtolower($CFG->dbtype)) { - case 'mysql' : - $NOT_REGEXP = 'NOT REGEXP'; - break; - case 'postgres7' : - $NOT_REGEXP = '!~'; - break; - default: - $NOT_REGEXP = ''; - break; - } - if ($NOT_REGEXP) { - $ok = $ok && execute_sql("UPDATE {$CFG->prefix}hotpot_questions SET text=NULL WHERE text $NOT_REGEXP '^[0-9]+$'"); - } - - // hotpot_questions: change type of "text" field to "INT(10)" - $ok = $ok && hotpot_db_update_field_type('hotpot_questions', 'text', 'text', 'INTEGER', 10, 'UNSIGNED', 'NULL'); - - // hotpot_attempts - - // hotpot_attempts: move "details" to separate table - $table = 'hotpot_details'; - if (hotpot_db_table_exists($table)) { - // do nothing - } else { - $ok = $ok && hotpot_create_table($table); - switch (strtolower($CFG->dbtype)) { - case 'mysql' : - case 'postgres7' : - $sql = " - INSERT INTO {$CFG->prefix}$table (attempt, details) - SELECT a.id AS attempt, a.details AS details - FROM {$CFG->prefix}hotpot_attempts AS a - WHERE - a.details IS NOT NULL AND a.details <> '' - AND a.details LIKE '' - "; - break; - default: - $sql = ''; - break; - } - if ($sql) { - $ok = $ok && execute_sql($sql); - } - } - - // hotpot_attempts: remove the "details" field - $ok = $ok && hotpot_db_remove_field('hotpot_attempts', 'details'); - - // hotpot_attempts: create and set status field (1=in-progress, 2=timed-out, 3=abandoned, 4=completed) - $ok = $ok && hotpot_db_update_field_type('hotpot_attempts', '', 'status', 'INTEGER', 4, 'UNSIGNED', 'NOT NULL', 1); - $ok = $ok && execute_sql("UPDATE {$CFG->prefix}hotpot_attempts SET status=1 WHERE timefinish=0 AND SCORE IS NULL"); - $ok = $ok && execute_sql("UPDATE {$CFG->prefix}hotpot_attempts SET status=3 WHERE timefinish>0 AND SCORE IS NULL"); - $ok = $ok && execute_sql("UPDATE {$CFG->prefix}hotpot_attempts SET status=4 WHERE timefinish>0 AND SCORE IS NOT NULL"); - - // hotpot_attempts: create and set clickreport fields - $ok = $ok && hotpot_db_update_field_type('hotpot', '', 'clickreporting', 'INTEGER', 4, 'UNSIGNED', 'NOT NULL', 0); - $ok = $ok && hotpot_db_update_field_type('hotpot_attempts', '', 'clickreportid', 'INTEGER', 10, 'UNSIGNED', 'NULL'); - $ok = $ok && execute_sql("UPDATE {$CFG->prefix}hotpot_attempts SET clickreportid=id WHERE clickreportid IS NULL"); - - // hotpot_attempts: create and set studentfeedback field (0=none, 1=formmail, 2=moodleforum, 3=moodlemessaging) - $ok = $ok && hotpot_db_update_field_type('hotpot', '', 'studentfeedback', 'INTEGER', 4, 'UNSIGNED', 'NOT NULL', '0'); - $ok = $ok && hotpot_db_update_field_type('hotpot', '', 'studentfeedbackurl', 'VARCHAR', 255, '', 'NULL'); - - // add indexes - $ok = $ok && hotpot_db_add_index('hotpot_attempts', 'hotpot'); - $ok = $ok && hotpot_db_add_index('hotpot_attempts', 'userid'); - $ok = $ok && hotpot_db_add_index('hotpot_details', 'attempt'); - $ok = $ok && hotpot_db_add_index('hotpot_questions', 'name', 20); - $ok = $ok && hotpot_db_add_index('hotpot_questions', 'hotpot'); - $ok = $ok && hotpot_db_add_index('hotpot_responses', 'attempt'); - $ok = $ok && hotpot_db_add_index('hotpot_responses', 'question'); - $ok = $ok && hotpot_db_add_index('hotpot_strings', 'string', 20); - - // hotpot_string: correct double-encoded HTML entities - $ok = $ok && execute_sql(" - UPDATE {$CFG->prefix}hotpot_strings - SET string = REPLACE(string, '&','&') - WHERE string LIKE '%&#%' - AND (string LIKE '<' OR string LIKE '>') - "); - - // hotpot_question: remove questions which refer to deleted hotpots - if ($ok) { - // try and get all hotpot records - if ($records = get_records('hotpot')) { - $ids = implode(',', array_keys($records)); - $sql = "DELETE FROM {$CFG->prefix}hotpot_questions WHERE hotpot NOT IN ($ids)"; - } else { - // remove all question records (because there are no valid hotpot ids) - $sql = "TRUNCATE {$CFG->prefix}hotpot_questions"; - } - print "Removing unused question records ..."; - execute_sql($sql); - } - - if ($ok) { - // remove old 'v6' templates folder (replaced by 'template' folder) - $ds = DIRECTORY_SEPARATOR; - $dir = "mod{$ds}hotpot{$ds}v6"; - print "removing old templates ($dir) ... "; - $ok = hotpot_rm("$CFG->dirroot{$ds}$dir", false); - print $ok ? get_string('success') : 'failed'; - print "
\n"; - } - - return $ok; -} -function hotpot_update_to_v2_from_v1() { - global $CFG; - $ok = true; - - // remove, alter and add fields in database - - $table = 'hotpot'; - if (hotpot_db_table_exists($table)) { - $ok = $ok && hotpot_update_fields($table); - } else { - $ok = $ok && hotpot_create_table($table); - } - - $table = 'hotpot_attempts'; - $oldtable = 'hotpot_events'; - - if (hotpot_db_table_exists($oldtable)) { - $ok = $ok && hotpot_update_fields($oldtable); - $ok = $ok && hotpot_db_append_table($oldtable, $table); - } else { - $ok = $ok && hotpot_create_table($table); - } - - // create new tables (from mysql.sql) - $ok = $ok && hotpot_create_table('hotpot_questions'); - $ok = $ok && hotpot_create_table('hotpot_responses'); - $ok = $ok && hotpot_create_table('hotpot_strings'); - - // remove redundant scripts - $files = array('coursefiles.php', 'details.php', 'dummy.html', 'hotpot.php', 'hotpot2db.php'); - foreach ($files as $file) { - $filepath = "$CFG->dirroot/mod/hotpot/$file"; - if (file_exists($filepath)) { - @unlink($filepath); // don't worry about errors - } - } - - return $ok; -} - -function hotpot_update_to_v2_from_hotpotatoes() { - global $CFG; - - $ok = true; // hope for the best! - - // check we have the minimum required hotpot module - $minimum = 2005031400; - $module = get_record("modules", "name", "hotpot"); - if (empty($module) || $module->version<$minimum) { - - if ($module) { - print ("

The update to the HotPotatoes module requires at least version $minimum of the HotPot module.

"); - print ("

The current version of the HotPot module on this site is $module->version.

"); - } - print ("

Please install the latest version of the HotPot module and then try the update again.

"); - $ok = false; - - } else { - // arrays to map foreign keys - $new = array(); - $new['hotpot'] = array(); - $new['attempt'] = array(); - $new['question'] = array(); - $new['string'] = array(); - - // save and switch off SQL message echo - global $db; - $debug = $db->debug; - $db->debug = false; - - // import hotpotatoes (and save old ids) - $ok = $ok && hotpot_update_fields('hotpotatoes'); - $ok = $ok && hotpot_transfer_records('hotpotatoes', 'hotpot', array(), 'hotpot', $new); - - // update course modules and logs - $ok = $ok && hotpot_update_course_modules('hotpotatoes', 'hotpot', $new); - - // import hotpotatoes_strings (and save old ids) - $ok = $ok && hotpot_transfer_records('hotpotatoes_strings', 'hotpot_strings', array(), 'string', $new); - - // import hotpotatoes_attempts (and save old ids) - $ok = $ok && hotpot_transfer_records('hotpotatoes_attempts', 'hotpot_attempts', array('hotpotatoes'=>'hotpot'), 'attempt', $new); - - // import hotpotatoes_questions (and save old ids) - $ok = $ok && hotpot_transfer_records('hotpotatoes_questions', 'hotpot_questions', array('hotpotatoes'=>'hotpot'), 'question', $new); - - // import hotpotatoes_responses - $ok = $ok && hotpot_transfer_records('hotpotatoes_responses', 'hotpot_responses', array('attempt'=>'attempt', 'question'=>'question'), 'response', $new); - - // restore SQL message echo setting - $db->debug = $debug; - - // remove the hotpotatoes tables, if the update went ok - if ($ok) { - // hotpot_db_remove_table('hotpotatoes'); - // hotpot_db_remove_table('hotpotatoes_attempts'); - // hotpot_db_remove_table('hotpotatoes_questions'); - // hotpot_db_remove_table('hotpotatoes_responses'); - // hotpot_db_remove_table('hotpotatoes_strings'); - } - - // hide the hotpotatoes module (see admin/modules.php)) - if ($ok && ($module = get_record("modules", "name", "hotpotatoes"))) { - set_field("modules", "visible", "0", "id", $module->id); - - print '

All HotPotatoes activities have been imported to the HotPot module.
'."\n"; - print 'The HotPotatoes module has been hidden and can safely be deleted from this Moodle site.
'."\n"; - print '     Configuration -> Modules, then click "Delete" for "Hot Potatoes XML Quiz"

'."\n"; - } - } - - if ($ok) { - print '

Thank you for using the HotPotatoes module.
'; - print 'The HotPotatoes module has been replaced by
version 2 of the HotPot module. Enjoy!

'; - } - return $ok; -} - -function hotpot_create_table($table) { - global $CFG; - $ok = true; - - static $sql; - if (empty($sql)) { // first time only - $filepath = "$CFG->dirroot/mod/hotpot/db/$CFG->dbtype.sql"; - - if (function_exists('file_get_contents')) { - $sql = file_get_contents($filepath); - - } else { // PHP < 4.3 - $sql = file($filepath); - if (is_array($sql)) { - $sql = implode('', $sql); - } - } - - if(empty($sql)) { // $sql==false - $sql = ''; - } - } - - // check table does not already exist - if (!hotpot_db_table_exists($table)) { - - // extract and execute all CREATE statements relating to this table - if (preg_match_all("/CREATE (TABLE|INDEX)(\s[^;]*)? prefix_{$table}(\s[^;]*)?;/s", $sql, $strings)) { - foreach ($strings[0] as $string) { - $ok = $ok && modify_database('', $string); - } - } else { - // no CREATE statements found for this $table - $ok = false; - } - } - return $ok; -} -function hotpot_transfer_records($oldtable, $table, $foreignkeys, $primarykey, &$new) { - global $db; - $ok = true; - - // get the records, if any - if (hotpot_db_table_exists($oldtable) && ($records = get_records($oldtable))) { - - // start progress report - $i = 0; - $count = count($records); - hotpot_update_print("Transferring $count records from "$oldtable" to "$table" ... "); - - // transfer all $records - foreach ($records as $record) { - - switch ($table) { - case 'hotpot' : - $record->summary = addslashes($record->summary); - break; - case 'hotpot_attempts' : - $record->details = addslashes($record->details); - break; - case 'hotpot_questions' : - $record->name = addslashes($record->name); - hotpot_update_string_id_list($table, $record, 'TEXT', $new); - break; - case 'hotpot_responses' : - hotpot_update_string_id_list($table, $record, 'correct', $new); - hotpot_update_string_id_list($table, $record, 'ignored', $new); - hotpot_update_string_id_list($table, $record, 'wrong', $new); - break; - case 'hotpot_strings' : - $record->string = addslashes($record->string); - break; - } - - // update foreign keys, if any - foreach ($foreignkeys as $oldkey=>$key) { - - // transfer (and update) key - $value = $record->$oldkey; - if (isset($new[$key][$value])) { - $record->$key = $new[$key][$value]; - } else { - // foreign key could not be updated - $ok = hotpot_update_print_warning($key, $value, $oldtable, $record->id) && $ok; - unset($record->id); - } - } - if ($ok && isset($record->id)) { - // store and remove old primary key - $id = $record->id; - unset($record->id); - - // add the updated record and store the new id - $new[$primarykey][$id] = insert_record($table, $record, true); - - // check id is numeric - if (!is_numeric($new[$primarykey][$id])) { - hotpot_update_print("
  • Record could not added to $table table ($oldtable id=$id)
  • \n"); - //$ok = false; - } - } - - $i++; - hotpot_update_print_progress($i); - } - // finish progress report - hotpot_update_print_ok($ok); - } - - return $ok; -} -function hotpot_update_course_modules($oldmodulename, $modulename, &$new) { - - $ok = true; - - $oldmoduleid = get_field('modules', 'id', 'name', $oldmodulename); - $moduleid = get_field('modules', 'id', 'name', $modulename); - - if (is_numeric($oldmoduleid) && is_numeric($moduleid)) { - - // get module records - if ($records = get_records('course_modules', 'module', $oldmoduleid)) { - - // start progress report - $count = count($records); - hotpot_update_print("Updating $count course modules from "$oldmodulename" to "$modulename" ... "); - - // update foreign keys in all $records - foreach ($records as $record) { - - // update instance - $instance = $record->instance; - if (isset($new[$modulename][$instance])) { - $record->instance = $new[$modulename][$instance]; - - } else if ($record->deleted) { - unset($record->id); - - } else { - // could not find new id of course module - $ok = hotpot_update_print_warning("$modulename instance", $instance, 'course_modules', $record->id) && $ok; - unset($record->id); - } - - // update module id - if ($ok && isset($record->id)) { - $record->module = $moduleid; - $ok = update_record('course_modules', $record); - } - } - - // finish progress report - hotpot_update_print_ok($ok); - } - - // update logs - $ok = $ok && hotpot_update_logs($oldmodulename, $modulename, $moduleid, $new); - } - - return $ok; -} -function hotpot_update_logs($oldmodulename, $modulename, $moduleid, &$new) { - - $table = 'log'; - $ok = true; - - // get log records for the oldmodule - if ($records = get_records($table, 'module', $oldmodulename)) { - - // start progress report - $i = 0; - $count = count($records); - hotpot_update_print("Updating $count log records ... "); - - // update foreign keys in all $records - foreach ($records as $record) { - - // update course module name - $record->module = $modulename; - - // check if module id was given (usually it is) - if ($record->cmid) { - - // update course module id, if necessary - if (isset($new[$modulename][$record->cmid])) { - $record->cmid = $new[$modulename][$record->cmid]; - } else { - // could not update course module id - $ok = hotpot_update_print_warning('cmid', $record->cmid, 'log', $record->id) && $ok; - unset($record->id); - } - - // update url and info - switch ($record->action) { - - case "add": - case "update": - case "view": - $record->url = "view.php?id=".$record->cmid; - $record->info = $moduleid; - break; - - case "view all": - // do nothing - break; - - case "report": - $record->url = "report.php?id=".$record->cmid; - $record->info = $moduleid; - break; - - case "attempt": - case "submit": - case "review": - $id = substr(strrchr($record->url,"="),1); - if (isset($new->attempt[$id])) { - $id = $new->attempt[$id]; - } - $record->url = "review.php?id=".$record->cmid."&attempt=$id"; - $record->info = $moduleid; - break; - - default: - // unknown log action - $ok = hotpot_update_print_warning('action', $record->action, 'log', $record->id) && $ok; - unset($record->id); - - } // end switch - } - if (isset($record->id)) { - $ok = $ok && update_record($table, $record); - } - - $i++; - hotpot_update_print_progress($i); - - } // end foreach - - // finish progress report - hotpot_update_print_ok($ok); - } - return $ok; -} -function hotpot_update_fields($table, $feedback=false) { - global $CFG, $db; - $ok = true; - - // check the table exists - if (hotpot_db_table_exists($table)) { - - switch ($table) { - - case 'hotpot' : - // == ADD == - hotpot_db_update_field_type($table, '', 'location', 'INTEGER', 4, 'UNSIGNED', 'NOT NULL', 0); - hotpot_db_update_field_type($table, '', 'navigation', 'INTEGER', 4, 'UNSIGNED', 'NOT NULL', 1); - hotpot_db_update_field_type($table, '', 'outputformat', 'INTEGER', 4, 'UNSIGNED', 'NOT NULL', 1); - hotpot_db_update_field_type($table, '', 'shownextquiz', 'INTEGER', 4, 'UNSIGNED', 'NOT NULL', 0); - hotpot_db_update_field_type($table, '', 'forceplugins', 'INTEGER', 4, 'UNSIGNED', 'NOT NULL', 0); - hotpot_db_update_field_type($table, '', 'password', 'VARCHAR', 255, '', 'NOT NULL', ''); - hotpot_db_update_field_type($table, '', 'subnet', 'VARCHAR', 255, '', 'NOT NULL', ''); - - // == ALTER == - hotpot_db_update_field_type($table, 'summary', 'summary', 'TEXT', '', '', 'NOT NULL', ''); - hotpot_db_update_field_type($table, 'reference', 'reference', 'VARCHAR', 255, '', 'NOT NULL', ''); - - // == REMOVE == - hotpot_db_remove_field($table, 'intro'); - hotpot_db_remove_field($table, 'attemptonlast'); - hotpot_db_remove_field($table, 'sumgrades'); - - hotpot_db_set_table_comment($table, 'details about Hot Potatoes quizzes'); - break; - - case 'hotpot_events' : - - // == ADD == - hotpot_db_update_field_type($table, '', 'hotpot', 'INTEGER', 10, 'UNSIGNED', 'NOT NULL'); - hotpot_db_update_field_type($table, '', 'attempt', 'INTEGER', 6, 'UNSIGNED', 'NOT NULL'); - hotpot_db_update_field_type($table, '', 'details', 'TEXT', '', '', '', ''); - hotpot_db_update_field_type($table, '', 'timestart', 'INTEGER', 10, 'UNSIGNED', 'NOT NULL', 0); - hotpot_db_update_field_type($table, '', 'timefinish', 'INTEGER', 10, 'UNSIGNED', 'NOT NULL', 0); - - // == ALTER == - hotpot_db_update_field_type($table, 'score', 'score', 'INTEGER', 6, 'UNSIGNED', 'NULL'); - hotpot_db_update_field_type($table, 'wrong', 'penalties', 'INTEGER', 6, 'UNSIGNED', 'NULL'); - hotpot_db_update_field_type($table, 'starttime', 'starttime', 'INTEGER', 10, 'UNSIGNED', 'NULL'); - hotpot_db_update_field_type($table, 'endtime', 'endtime', 'INTEGER', 10, 'UNSIGNED', 'NULL'); - - // save and switch off SQL message echo - $debug = $db->debug; - $db->debug = $feedback; - - // get array mapping course module ids to hotpot ids - $hotpotmoduleid = get_field('modules', 'id', 'name', 'hotpot'); - $coursemodules = get_records('course_modules', 'module', $hotpotmoduleid, 'id', 'id, instance'); - - - // get all event records - if (hotpot_db_field_exists($table, 'hotpotid')) { - $records = get_records($table, '', '', 'userid,hotpotid,time'); - } else { - $records = false; // table has already been updated - } - - if ($records) { - - $count = count($records); - hotpot_update_print("Updating $count records in $table ... "); - - $ids = array_keys($records); - foreach ($ids as $i=>$id) { - - // reference to current record - $record = &$records[$id]; - - // set timestart and timefinish (the times recorded by Moodle) - if (empty($record->timestart) && $record->time) { - $record->timestart = $record->time; - } - - if (empty($record->timefinish) && $record->timestart) { - - if ($record->starttime && $record->endtime) { - $duration = ($record->endtime - $record->starttime); - - } else { - if (($i+1)>=$count) { - $nextrecord = NULL; - } else { - $nextrecord = &$records[$ids[$i+1]]; - } - if (isset($nextrecord) && $nextrecord->userid==$record->userid && $nextrecord->hotpotid==$record->hotpotid) { - $duration = $nextrecord->time - $record->time; - } else { - $duration = NULL; - } - } - - if (isset($duration)) { - $record->timefinish = $record->timestart + $duration; - } - } - - // unset score and penalties, if quiz was abandoned - if (empty($record->endtime) || (empty($record->penalties) && empty($record->score))) { - unset($record->score); - unset($record->penalties); - } - - // get last (=previous) record - if ($i==0) { - $lastrecord = NULL; - } else { - $lastrecord = &$records[$ids[$i-1]]; - } - - // increment or reset $attempt number - if (isset($lastrecord) && $lastrecord->userid==$record->userid && $lastrecord->hotpotid==$record->hotpotid) { - $attempt++; - } else { - $attempt = 1; - } - - // set $record->$attempt, if necessary - if (empty($record->attempt) || $record->attempt<$attempt) { - $record->attempt = $attempt; - } else { - $attempt = $record->attempt; - } - - // set hotpot id and update record - if (isset($record->hotpotid) && isset($record->id)) { - if (isset($coursemodules[$record->hotpotid])) { - $record->hotpot = $coursemodules[$record->hotpotid]->instance; - hotpot_db_update_record($table, $record, true); - - } else { - // hotpotid is invalid (shouldn't happen) - $ok = hotpot_update_print_warning('hotpotid', $record->hotpotid, $table, $record->id) && $ok; - delete_records($table, 'id', $record->id); - } - } else { - // empty record (shouldn't happen) - } - - hotpot_update_print_progress($i); - } - - // finish progress report - hotpot_update_print_ok($ok); - } - - // restore SQL message echo setting - $db->debug = $debug; - - // == REMOVE == - hotpot_db_remove_field($table, 'hotpotid'); - hotpot_db_remove_field($table, 'course'); - hotpot_db_remove_field($table, 'time'); - hotpot_db_remove_field($table, 'event'); - - hotpot_db_set_table_comment($table, 'details about Hot Potatoes quiz attempts'); - - break; - - case 'hotpotatoes' : - // == ALTER == - hotpot_db_update_field_type($table, 'intro', 'summary', 'TEXT', '', '', '', 'NULL'); - break; - - } - } - return $ok; -} -function hotpot_update_string_id_list($table, &$record, $field, &$new) { - - $ok = true; - - if (isset($record->$field)) { - - $oldids = explode(',', $record->$field); - $newids = array(); - - foreach ($oldids as $id) { - - if (isset($new['string'][$id])) { - $newids[] = $new['string'][$id]; - } else if (is_numeric($id)) { - // string id could not be updated - $ok = hotpot_update_print_warning("string id in $field", $id, $table, $record->id) && $ok; - } else { - // ignore non-numeric ids (e.g. blanks) - } - } - if ($ok) { - $record->$field = implode(',', $newids); - } - } - - return $ok; -} - -/////////////////////////// -// print functions -/////////////////////////// - -function hotpot_update_print($msg=false, $n=300) { - // this function prints $msg and flush output buffer - - if ($msg) { - if (is_string($msg)) { - print $msg; - } else { - print strftime("%X", time()); - } - } - - // fill output buffer - if ($n) { - print str_repeat(" ", $n); - } - - // some browser's require newline to flush - print "\n"; - - // flush PHP's output buffer - flush(); -} -function hotpot_update_print_progress($i) { - if ($i%10==0) { - $msg = '.'; - hotpot_update_print($msg); - } -} -function hotpot_update_print_ok($ok) { - if ($ok) { - hotpot_update_print(''.get_string('success')."
    \n"); - } else { - hotpot_update_print(''.get_string('error')."
    \n"); - } -} -function hotpot_update_print_warning($field, $value, $table, $id) { - hotpot_update_print("
  • Warning: invalid $field field (value=$value) in $table (id=$id)
  • \n"); - return true; -} - -/////////////////////////// -// database functions -/////////////////////////// - -function hotpot_db_index_exists($table, $index, $feedback=false) { - global $CFG, $db; - $exists = false; - - // save and switch off SQL message echo - $debug = $db->debug; - $db->debug = $feedback; - - switch (strtolower($CFG->dbtype)) { - case 'mysql' : - $rs = $db->Execute("SHOW INDEX FROM `$table`"); - if ($rs && $rs->RecordCount()>0) { - $records = $rs->GetArray(); - foreach ($records as $record) { - if (isset($record['Key_name']) && $record['Key_name']==$index) { - $exists = true; - break; - } - } - } - break; - - case 'postgres7' : - $rs = $db->Execute("SELECT relname FROM pg_class WHERE relname = '$index' AND relkind='i'"); - if ($rs && $rs->RecordCount()>0) { - $exists = true; - } - break; - } - - // restore SQL message echo - $db->debug = $debug; - - return $exists; -} -function hotpot_db_delete_index($table, $index, $feedback=false) { - global $CFG, $db; - $ok = true; - - // check index exists - if (hotpot_db_index_exists($table, $index)) { - - switch (strtolower($CFG->dbtype)) { - case 'mysql' : - $sql = "ALTER TABLE `$table` DROP INDEX `$index`"; - break; - - case 'postgres7' : - $sql = "DROP INDEX $index"; - break; - - default: // unknown database type - $sql = ''; - break; - } - if ($sql) { - // save and switch off SQL message echo - $debug = $db->debug; - $db->debug = $feedback; - - $ok = $db->Execute($sql) ? true : false; - - // restore SQL message echo - $db->debug = $debug; - - } else { // unknown database type - $ok = false; - } - } - return $ok; -} -function hotpot_db_add_index($table, $field, $length='') { - global $CFG, $db; - - // expand $table and $index names - $table = "{$CFG->prefix}$table"; - $index = "{$table}_{$field}_idx"; - - // delete $index if it already exists - $ok = hotpot_db_delete_index($table, $index); - - switch (strtolower($CFG->dbtype)) { - case 'mysql' : - $length = empty($length) ? '' : " ($length)"; - $ok = $ok && $db->Execute("ALTER TABLE `$table` ADD INDEX `$index` (`$field`$length)"); - break; - - case 'postgres7' : - $ok = $ok && $db->Execute("CREATE INDEX $index ON $table ($field)"); - break; - - default: // unknown database type - $ok = false; - break; - } - - return $ok; -} -function hotpot_db_table_exists($table, $feedback=false) { - return hotpot_db_object_exists($table, '', $feedback); -} -function hotpot_db_field_exists($table, $field, $feedback=false) { - return - hotpot_db_object_exists($table, '', $feedback) && - hotpot_db_object_exists($table, $field, $feedback) - ; -} -function hotpot_db_object_exists($table, $field='', $feedback=false) { - - global $CFG,$db; - - // expand table name - $table = "{$CFG->prefix}$table"; - - // set $sql - switch (strtolower($CFG->dbtype)) { - case 'mysql' : - if (empty($field)) { - $sql = "SHOW TABLES LIKE '$table'"; - } else { - $sql = "SHOW COLUMNS FROM `$table` LIKE '$field'"; - } - break; - - case 'postgres7' : - if (empty($field)) { - $sql = "SELECT relname FROM pg_class WHERE relname = '$table' AND relkind='r'"; - } else { - $sql = " - SELECT attname FROM pg_attribute WHERE attname = '$field' - AND attrelid = (SELECT oid FROM pg_class WHERE relname = '$table') - "; - } - break; - } - - // save and switch off SQL message echo - $debug = $db->debug; - $db->debug = $feedback; - - // execute sql - $rs = $db->Execute($sql); - - // restore SQL message echo setting - $db->debug = $debug; - - // report error if required - if (empty($rs) && isset($CFG->debug) and $CFG->debug > 7) { - notify($db->ErrorMsg()."

    $sql"); - } - - return ($rs && $rs->RecordCount()>0); -} -function hotpot_db_remove_table($table, $feedback=true) { - global $CFG; - if (hotpot_db_table_exists($table)) { - $ok = execute_sql("DROP TABLE {$CFG->prefix}$table", $feedback); - } else { - $ok = true; - } - return $ok; -} -function hotpot_db_rename_table($oldtable, $table, $feedback=true) { - global $CFG; - if (hotpot_db_table_exists($oldtable)) { - $ok = execute_sql("ALTER TABLE {$CFG->prefix}$oldtable RENAME TO {$CFG->prefix}$table", $feedback); - } else { - $ok = true; - } - return $ok; -} -function hotpot_db_append_table($oldtable, $table, $feedback=true) { - global $CFG, $db; - - if (hotpot_db_table_exists($oldtable)) { - if (hotpot_db_table_exists($table)) { - - // expand table names - $table = "{$CFG->prefix}$table"; - $oldtable = "{$CFG->prefix}$oldtable"; - - // get field info - $fields = $db->MetaColumns($table); - $oldfields = $db->MetaColumns($oldtable); - - $fieldnames = array(); - if (!empty($fields) || !empty($oldfields)) { - foreach ($fields as $field) { - if ($field->name!='id' && isset($oldfields[strtoupper($field->name)])) { - $fieldnames[] = $field->name; - } - } - } - $fieldnames = implode(',', $fieldnames); - - if (empty($fieldnames)) { - $ok = false; - } else { - switch (strtolower($CFG->dbtype)) { - case 'mysql': - $ok = execute_sql("INSERT INTO `$table` ($fieldnames) SELECT $fieldnames FROM `$oldtable` WHERE 1"); - break; - case 'postgres7': - $ok = execute_sql("INSERT INTO $table ($fieldnames) SELECT $fieldnames FROM $oldtable"); - break; - default: - $ok = false; - break; - } - } - - } else { // $table does not exist - $ok = hotpot_db_rename_table($oldtable, $table, $feedback); - } - - } else { // $oldtable does not exist - $ok = hotpot_db_table_exists($table, $feedback); - } - return $ok; -} -function hotpot_db_set_table_comment($table, $comment, $feedback=true) { - global $CFG; - $ok = true; - - switch (strtolower($CFG->dbtype)) { - case 'mysql' : - $ok = execute_sql("ALTER TABLE {$CFG->prefix}$table COMMENT='$comment'"); - break; - case 'postgres7' : - $ok = execute_sql("COMMENT ON TABLE {$CFG->prefix}$table IS '$comment'"); - break; - } - - return $ok; -} -function hotpot_db_remove_field($table, $field, $feedback=true) { - global $CFG; - if (hotpot_db_field_exists($table, $field)) { - $ok = execute_sql("ALTER TABLE {$CFG->prefix}$table DROP COLUMN $field", $feedback); - } else { - $ok = true; - } - return $ok; -} -function hotpot_db_update_field_type($table, $oldfield, $field, $type, $size, $unsigned, $notnull, $default=NULL, $after=NULL) { - $ok = true; - global $CFG,$db; - - // check validity of arguments, and adjust if necessary - - if ($oldfield && !hotpot_db_field_exists($table, $oldfield)) { - $oldfield = ''; - } - if (empty($oldfield) && hotpot_db_field_exists($table, $field)) { - $oldfield = $field; - } - if (is_string($unsigned)) { - - $unsigned = (strtoupper($unsigned)=='UNSIGNED'); - } - if (is_string($notnull)) { - $notnull = (strtoupper($notnull)=='NOT NULL'); - } - if (isset($default)) { - if (!is_numeric($default) && strtoupper($default)!='NULL' && !preg_match("|^'.*'$|", $default)) { - $default = "'$default'"; - } - } - - // set full table name - $table = "{$CFG->prefix}$table"; - - // update the field in the database - - switch (strtolower($CFG->dbtype)) { - - case 'mysql': - - // optimize integer types - switch (strtoupper($type)) { - case 'TEXT': - $size = ''; - $unsigned = false; - break; - case 'INTEGER' : - if (!is_numeric($size)) { - $size = ''; - } else if ($size <= 4) { - $type = "TINYINT"; // 1 byte - } else if ($size <= 6) { - $type = "SMALLINT"; // 2 bytes - } else if ($size <= 8) { - $type = "MEDIUMINT"; // 3 bytes - } else if ($size <= 10) { - $type = "INTEGER"; // 4 bytes (=INT) - } else if ($size > 10) { - $type = "BIGINT"; // 8 bytes - } - break; - case 'VARCHAR': - $unsigned = false; - break; - } - - // set action - if (empty($oldfield)) { - $action = "ADD"; - } else { - $action = "CHANGE `$oldfield`"; - } - - // set fieldtype - $fieldtype = $type; - if ($size) { - $fieldtype .= "($size)"; - } - if ($unsigned) { - $fieldtype .= ' UNSIGNED'; - } - if ($notnull) { - $fieldtype .= ' NOT NULL'; - } - if (isset($default)) { - $fieldtype .= " DEFAULT $default"; - } - if (!empty($after)) { - $fieldtype .= " AFTER `$after`"; - } - - $ok = $ok && execute_sql("ALTER TABLE `$table` $action `$field` $fieldtype"); - break; - - case 'postgres7': - - // get db version - $dbinfo = $db->ServerInfo(); - $dbversion = substr($dbinfo['version'],0,3); - - // prevent conflicts with reserved words - $tmpfield = "\"temporary_{$field}_".time()."\""; - $oldfield = "\"$oldfield\""; - $field = "\"$field\""; - - switch (strtoupper($type)) { - case "INTEGER": - if (!is_numeric($size)) { - $fieldtype = "INTEGER"; - } else if ($size <= 4) { - $fieldtype = "INT2"; // 2 bytes - } else if ($size <= 10) { - $fieldtype = "INT4"; // 4 bytes (=INTEGER) - } else if ($size > 10) { - $fieldtype = "INT8"; // 8 bytes - } - break; - case "VARCHAR": - $fieldtype = "VARCHAR($size)"; - break; - default: - $fieldtype = $type; - } - - // start transaction - execute_sql("BEGIN"); - - // create temporary field - execute_sql("ALTER TABLE $table ADD COLUMN $tmpfield $fieldtype"); - - // set default - if (isset($default)) { - execute_sql("UPDATE $table SET $tmpfield = $default"); - execute_sql("ALTER TABLE $table ALTER COLUMN $tmpfield SET DEFAULT $default"); - } else { - execute_sql("ALTER TABLE $table ALTER COLUMN $tmpfield DROP DEFAULT"); - } - - // set not null - if ($dbversion >= "7.3") { - $notnull = ($notnull ? "SET NOT NULL" : "DROP NOT NULL"); - execute_sql("ALTER TABLE $table ALTER COLUMN $tmpfield $notnull"); - - } else { - execute_sql(" - UPDATE pg_attribute SET attnotnull=".($notnull ? 'TRUE' : 'FALSE')." - WHERE attname = $tmpfield - AND attrelid = (SELECT oid FROM pg_class WHERE relname = '$table') - "); - } - - // transfer $oldfield values, if necessary - if ( $oldfield != '""' ) { - execute_sql("UPDATE $table SET $tmpfield = CAST ($oldfield AS $fieldtype)"); - execute_sql("ALTER TABLE $table DROP COLUMN $oldfield"); - } - - // rename $tmpfield to $field - execute_sql("ALTER TABLE $table RENAME COLUMN $tmpfield TO $field"); - - // do the transaction - execute_sql("COMMIT"); - - // reclaim disk space (must be done outside transaction) - if ($oldfield != '""' && $dbversion >= "7.3") { - execute_sql("UPDATE $table SET $field = $field"); - execute_sql("VACUUM FULL $table"); - } - - break; - - } // end switch $CGF->dbtype - - return $ok; -} -function hotpot_db_update_record($table, $record, $forcenull=false) { - global $CFG, $db; - $ok = true; - - // set full table name - $table = "{$CFG->prefix}$table"; - - // get field names - $fields = $db->MetaColumns($table); - - if (empty($fields)) { - $ok = false; - } else { - - // get values - $values = array(); - foreach ($fields as $field) { - $fieldname = $field->name; - if ($fieldname!='id' && ($forcenull || isset($record->$fieldname))) { - $value = isset($record->$fieldname) ? "'".$record->$fieldname."'" : 'NULL'; - $values[] = "$fieldname = $value"; - } - } - $values = implode(',', $values); - - // update values (if there are any) - if ($values) { - $sql = "UPDATE $table SET $values WHERE id='$record->id'"; - $rs = $db->Execute($sql); - - if (empty($rs)) { - $ok = false; - if (isset($CFG->debug) and $CFG->debug > 7) { - notify($db->ErrorMsg()."

    $sql"); - } - } - } - } - return $ok; -} -function hotpot_rm($target, $output=true) { - $ok = true; - if (!empty($target)) { - if (is_file($target)) { - if ($output) { - print "removing file: $target ... "; - } - $ok = @unlink($target); - - } else if (is_dir($target)) { - $dir = dir($target); - while(false !== ($entry = $dir->read())) { - if ($entry!='.' && $entry!='..') { - $ok = $ok && hotpot_rm($target.DIRECTORY_SEPARATOR.$entry, $output); - } - } - $dir->close(); - if ($output) { - print "removing folder: $target ... "; - } - $ok = $ok && @rmdir($target); - - } else { // not a file or directory (probably doesn't exist) - $output = false; - } - if ($output) { - if ($ok) { - print 'OK
    '; - } else { - print 'Failed
    '; - } - } - } - return $ok; -} - -function hotpot_flush($n=0, $time=false) { - if ($time) { - $t = strftime("%X",time()); - } else { - $t = ""; - } - echo str_repeat(" ", $n) . $t . "\n"; - flush(); -} - -?> +prefix}hotpot_attempts + GROUP BY userid, hotpot + HAVING countrecords > 1 AND minstatus=1 + "); + if ($records) { + // save and switch off SQL message echo + $debug = $db->debug; + $db->debug = false; + print "adjusting status of ".count($records)." "in progress" attempts ... "; + foreach ($records as $record) { + // get all attempts by this user at this hotpot + $attempts = get_records_sql(" + SELECT id, userid, hotpot, score, timestart, timefinish, status + FROM {$CFG->prefix}hotpot_attempts + WHERE userid = $record->userid AND hotpot=$record->hotpot + ORDER BY timestart DESC, id DESC + "); + unset($previous_timestart); + foreach ($attempts as $attempt) { + // if this attempt has a status of "in progress" and is not + // the most recent one in the group, set the status to "abandoned" + if ($attempt->status==1 && isset($previous_timestart)) { + $values = 'status=3'; + if (empty($attempt->score)) { + $values .= ',score=0'; + } + if (empty($attempt->timefinish)) { + $values .= ",timefinish=$previous_timestart"; + } + execute_sql("UPDATE {$CFG->prefix}hotpot_attempts SET $values WHERE id=$attempt->id", false); + print "."; + hotpot_flush(300); + } + $previous_timestart = $attempt->timestart; + } // end foreach $attempts + } // end foreach $records + print $ok ? get_string('success') : 'failed'; + print "
    \n"; + // restore SQL message echo setting + $db->debug = $debug; + } + return $ok; +} +function hotpot_update_to_v2_1() { + global $CFG, $db; + $ok = true; + // hotpot_questions: reduce size of "type" field to "4" + $ok = $ok && hotpot_db_update_field_type('hotpot_questions', 'type', 'type', 'INTEGER', 4, 'UNSIGNED', 'NULL'); + // hotpot_questions: change type of "name" field to "text" + $ok = $ok && hotpot_db_update_field_type('hotpot_questions', 'name', 'name', 'TEXT', '', '', 'NOT NULL', ''); + // hotpot_questions: nullify empty and non-numeric (shouldn't be any) values in "text" field + switch (strtolower($CFG->dbtype)) { + case 'mysql' : + $NOT_REGEXP = 'NOT REGEXP'; + break; + case 'postgres7' : + $NOT_REGEXP = '!~'; + break; + default: + $NOT_REGEXP = ''; + break; + } + if ($NOT_REGEXP) { + $ok = $ok && execute_sql("UPDATE {$CFG->prefix}hotpot_questions SET text=NULL WHERE text $NOT_REGEXP '^[0-9]+$'"); + } + // hotpot_questions: change type of "text" field to "INT(10)" + $ok = $ok && hotpot_db_update_field_type('hotpot_questions', 'text', 'text', 'INTEGER', 10, 'UNSIGNED', 'NULL'); + // hotpot_attempts + // hotpot_attempts: move "details" to separate table + $table = 'hotpot_details'; + if (hotpot_db_table_exists($table)) { + // do nothing + } else { + $ok = $ok && hotpot_create_table($table); + switch (strtolower($CFG->dbtype)) { + case 'mysql' : + case 'postgres7' : + $sql = " + INSERT INTO {$CFG->prefix}$table (attempt, details) + SELECT a.id AS attempt, a.details AS details + FROM {$CFG->prefix}hotpot_attempts AS a + WHERE + a.details IS NOT NULL AND a.details <> '' + AND a.details LIKE '' + "; + break; + default: + $sql = ''; + break; + } + if ($sql) { + $ok = $ok && execute_sql($sql); + } + } + // hotpot_attempts: remove the "details" field + $ok = $ok && hotpot_db_remove_field('hotpot_attempts', 'details'); + // hotpot_attempts: create and set status field (1=in-progress, 2=timed-out, 3=abandoned, 4=completed) + $ok = $ok && hotpot_db_update_field_type('hotpot_attempts', '', 'status', 'INTEGER', 4, 'UNSIGNED', 'NOT NULL', 1); + $ok = $ok && execute_sql("UPDATE {$CFG->prefix}hotpot_attempts SET status=1 WHERE timefinish=0 AND SCORE IS NULL"); + $ok = $ok && execute_sql("UPDATE {$CFG->prefix}hotpot_attempts SET status=3 WHERE timefinish>0 AND SCORE IS NULL"); + $ok = $ok && execute_sql("UPDATE {$CFG->prefix}hotpot_attempts SET status=4 WHERE timefinish>0 AND SCORE IS NOT NULL"); + // hotpot_attempts: create and set clickreport fields + $ok = $ok && hotpot_db_update_field_type('hotpot', '', 'clickreporting', 'INTEGER', 4, 'UNSIGNED', 'NOT NULL', 0); + $ok = $ok && hotpot_db_update_field_type('hotpot_attempts', '', 'clickreportid', 'INTEGER', 10, 'UNSIGNED', 'NULL'); + $ok = $ok && execute_sql("UPDATE {$CFG->prefix}hotpot_attempts SET clickreportid=id WHERE clickreportid IS NULL"); + // hotpot_attempts: create and set studentfeedback field (0=none, 1=formmail, 2=moodleforum, 3=moodlemessaging) + $ok = $ok && hotpot_db_update_field_type('hotpot', '', 'studentfeedback', 'INTEGER', 4, 'UNSIGNED', 'NOT NULL', '0'); + $ok = $ok && hotpot_db_update_field_type('hotpot', '', 'studentfeedbackurl', 'VARCHAR', 255, '', 'NULL'); + // add indexes + $ok = $ok && hotpot_db_add_index('hotpot_attempts', 'hotpot'); + $ok = $ok && hotpot_db_add_index('hotpot_attempts', 'userid'); + $ok = $ok && hotpot_db_add_index('hotpot_details', 'attempt'); + $ok = $ok && hotpot_db_add_index('hotpot_questions', 'name', 20); + $ok = $ok && hotpot_db_add_index('hotpot_questions', 'hotpot'); + $ok = $ok && hotpot_db_add_index('hotpot_responses', 'attempt'); + $ok = $ok && hotpot_db_add_index('hotpot_responses', 'question'); + $ok = $ok && hotpot_db_add_index('hotpot_strings', 'string', 20); + // hotpot_string: correct double-encoded HTML entities + $ok = $ok && execute_sql(" + UPDATE {$CFG->prefix}hotpot_strings + SET string = REPLACE(string, '&','&') + WHERE string LIKE '%&#%' + AND (string LIKE '<' OR string LIKE '>') + "); + // hotpot_question: remove questions which refer to deleted hotpots + if ($ok) { + // try and get all hotpot records + if ($records = get_records('hotpot')) { + $ids = implode(',', array_keys($records)); + $sql = "DELETE FROM {$CFG->prefix}hotpot_questions WHERE hotpot NOT IN ($ids)"; + } else { + // remove all question records (because there are no valid hotpot ids) + $sql = "TRUNCATE {$CFG->prefix}hotpot_questions"; + } + print "Removing unused question records ..."; + execute_sql($sql); + } + if ($ok) { + // remove old 'v6' templates folder (replaced by 'template' folder) + $ds = DIRECTORY_SEPARATOR; + $dir = "mod{$ds}hotpot{$ds}v6"; + print "removing old templates ($dir) ... "; + $ok = hotpot_rm("$CFG->dirroot{$ds}$dir", false); + print $ok ? get_string('success') : 'failed'; + print "
    \n"; + } + return $ok; +} +function hotpot_update_to_v2_from_v1() { + global $CFG; + $ok = true; + // remove, alter and add fields in database + $table = 'hotpot'; + if (hotpot_db_table_exists($table)) { + $ok = $ok && hotpot_update_fields($table); + } else { + $ok = $ok && hotpot_create_table($table); + } + $table = 'hotpot_attempts'; + $oldtable = 'hotpot_events'; + if (hotpot_db_table_exists($oldtable)) { + $ok = $ok && hotpot_update_fields($oldtable); + $ok = $ok && hotpot_db_append_table($oldtable, $table); + } else { + $ok = $ok && hotpot_create_table($table); + } + // create new tables (from mysql.sql) + $ok = $ok && hotpot_create_table('hotpot_questions'); + $ok = $ok && hotpot_create_table('hotpot_responses'); + $ok = $ok && hotpot_create_table('hotpot_strings'); + // remove redundant scripts + $files = array('coursefiles.php', 'details.php', 'dummy.html', 'hotpot.php', 'hotpot2db.php'); + foreach ($files as $file) { + $filepath = "$CFG->dirroot/mod/hotpot/$file"; + if (file_exists($filepath)) { + @unlink($filepath); // don't worry about errors + } + } + return $ok; +} +function hotpot_update_to_v2_from_hotpotatoes() { + global $CFG; + $ok = true; // hope for the best! + // check we have the minimum required hotpot module + $minimum = 2005031400; + $module = get_record("modules", "name", "hotpot"); + if (empty($module) || $module->version<$minimum) { + if ($module) { + print ("

    The update to the HotPotatoes module requires at least version $minimum of the HotPot module.

    "); + print ("

    The current version of the HotPot module on this site is $module->version.

    "); + } + print ("

    Please install the latest version of the HotPot module and then try the update again.

    "); + $ok = false; + } else { + // arrays to map foreign keys + $new = array(); + $new['hotpot'] = array(); + $new['attempt'] = array(); + $new['question'] = array(); + $new['string'] = array(); + // save and switch off SQL message echo + global $db; + $debug = $db->debug; + $db->debug = false; + // import hotpotatoes (and save old ids) + $ok = $ok && hotpot_update_fields('hotpotatoes'); + $ok = $ok && hotpot_transfer_records('hotpotatoes', 'hotpot', array(), 'hotpot', $new); + // update course modules and logs + $ok = $ok && hotpot_update_course_modules('hotpotatoes', 'hotpot', $new); + // import hotpotatoes_strings (and save old ids) + $ok = $ok && hotpot_transfer_records('hotpotatoes_strings', 'hotpot_strings', array(), 'string', $new); + // import hotpotatoes_attempts (and save old ids) + $ok = $ok && hotpot_transfer_records('hotpotatoes_attempts', 'hotpot_attempts', array('hotpotatoes'=>'hotpot'), 'attempt', $new); + // import hotpotatoes_questions (and save old ids) + $ok = $ok && hotpot_transfer_records('hotpotatoes_questions', 'hotpot_questions', array('hotpotatoes'=>'hotpot'), 'question', $new); + // import hotpotatoes_responses + $ok = $ok && hotpot_transfer_records('hotpotatoes_responses', 'hotpot_responses', array('attempt'=>'attempt', 'question'=>'question'), 'response', $new); + // restore SQL message echo setting + $db->debug = $debug; + // remove the hotpotatoes tables, if the update went ok + if ($ok) { + // hotpot_db_remove_table('hotpotatoes'); + // hotpot_db_remove_table('hotpotatoes_attempts'); + // hotpot_db_remove_table('hotpotatoes_questions'); + // hotpot_db_remove_table('hotpotatoes_responses'); + // hotpot_db_remove_table('hotpotatoes_strings'); + } + // hide the hotpotatoes module (see admin/modules.php)) + if ($ok && ($module = get_record("modules", "name", "hotpotatoes"))) { + set_field("modules", "visible", "0", "id", $module->id); + print '

    All HotPotatoes activities have been imported to the HotPot module.
    '."\n"; + print 'The HotPotatoes module has been hidden and can safely be deleted from this Moodle site.
    '."\n"; + print '     Configuration -> Modules, then click "Delete" for "Hot Potatoes XML Quiz"

    '."\n"; + } + } + if ($ok) { + print '

    Thank you for using the HotPotatoes module.
    '; + print 'The HotPotatoes module has been replaced by
    version 2 of the HotPot module. Enjoy!

    '; + } + return $ok; +} +function hotpot_create_table($table) { + global $CFG; + $ok = true; + static $sql; + if (empty($sql)) { // first time only + $filepath = "$CFG->dirroot/mod/hotpot/db/$CFG->dbtype.sql"; + if (function_exists('file_get_contents')) { + $sql = file_get_contents($filepath); + } else { // PHP < 4.3 + $sql = file($filepath); + if (is_array($sql)) { + $sql = implode('', $sql); + } + } + if(empty($sql)) { // $sql==false + $sql = ''; + } + } + // check table does not already exist + if (!hotpot_db_table_exists($table)) { + // extract and execute all CREATE statements relating to this table + if (preg_match_all("/CREATE (TABLE|INDEX)(\s[^;]*)? prefix_{$table}(\s[^;]*)?;/s", $sql, $strings)) { + foreach ($strings[0] as $string) { + $ok = $ok && modify_database('', $string); + } + } else { + // no CREATE statements found for this $table + $ok = false; + } + } + return $ok; +} +function hotpot_transfer_records($oldtable, $table, $foreignkeys, $primarykey, &$new) { + global $db; + $ok = true; + // get the records, if any + if (hotpot_db_table_exists($oldtable) && ($records = get_records($oldtable))) { + // start progress report + $i = 0; + $count = count($records); + hotpot_update_print("Transferring $count records from "$oldtable" to "$table" ... "); + // transfer all $records + foreach ($records as $record) { + switch ($table) { + case 'hotpot' : + $record->summary = addslashes($record->summary); + break; + case 'hotpot_attempts' : + $record->details = addslashes($record->details); + break; + case 'hotpot_questions' : + $record->name = addslashes($record->name); + hotpot_update_string_id_list($table, $record, 'TEXT', $new); + break; + case 'hotpot_responses' : + hotpot_update_string_id_list($table, $record, 'correct', $new); + hotpot_update_string_id_list($table, $record, 'ignored', $new); + hotpot_update_string_id_list($table, $record, 'wrong', $new); + break; + case 'hotpot_strings' : + $record->string = addslashes($record->string); + break; + } + // update foreign keys, if any + foreach ($foreignkeys as $oldkey=>$key) { + // transfer (and update) key + $value = $record->$oldkey; + if (isset($new[$key][$value])) { + $record->$key = $new[$key][$value]; + } else { + // foreign key could not be updated + $ok = hotpot_update_print_warning($key, $value, $oldtable, $record->id) && $ok; + unset($record->id); + } + } + if ($ok && isset($record->id)) { + // store and remove old primary key + $id = $record->id; + unset($record->id); + // add the updated record and store the new id + $new[$primarykey][$id] = insert_record($table, $record, true); + // check id is numeric + if (!is_numeric($new[$primarykey][$id])) { + hotpot_update_print("
  • Record could not added to $table table ($oldtable id=$id)
  • \n"); + //$ok = false; + } + } + $i++; + hotpot_update_print_progress($i); + } + // finish progress report + hotpot_update_print_ok($ok); + } + return $ok; +} +function hotpot_update_course_modules($oldmodulename, $modulename, &$new) { + $ok = true; + $oldmoduleid = get_field('modules', 'id', 'name', $oldmodulename); + $moduleid = get_field('modules', 'id', 'name', $modulename); + if (is_numeric($oldmoduleid) && is_numeric($moduleid)) { + // get module records + if ($records = get_records('course_modules', 'module', $oldmoduleid)) { + // start progress report + $count = count($records); + hotpot_update_print("Updating $count course modules from "$oldmodulename" to "$modulename" ... "); + // update foreign keys in all $records + foreach ($records as $record) { + // update instance + $instance = $record->instance; + if (isset($new[$modulename][$instance])) { + $record->instance = $new[$modulename][$instance]; + } else if ($record->deleted) { + unset($record->id); + } else { + // could not find new id of course module + $ok = hotpot_update_print_warning("$modulename instance", $instance, 'course_modules', $record->id) && $ok; + unset($record->id); + } + // update module id + if ($ok && isset($record->id)) { + $record->module = $moduleid; + $ok = update_record('course_modules', $record); + } + } + // finish progress report + hotpot_update_print_ok($ok); + } + // update logs + $ok = $ok && hotpot_update_logs($oldmodulename, $modulename, $moduleid, $new); + } + return $ok; +} +function hotpot_update_logs($oldmodulename, $modulename, $moduleid, &$new) { + $table = 'log'; + $ok = true; + // get log records for the oldmodule + if ($records = get_records($table, 'module', $oldmodulename)) { + // start progress report + $i = 0; + $count = count($records); + hotpot_update_print("Updating $count log records ... "); + // update foreign keys in all $records + foreach ($records as $record) { + // update course module name + $record->module = $modulename; + // check if module id was given (usually it is) + if ($record->cmid) { + // update course module id, if necessary + if (isset($new[$modulename][$record->cmid])) { + $record->cmid = $new[$modulename][$record->cmid]; + } else { + // could not update course module id + $ok = hotpot_update_print_warning('cmid', $record->cmid, 'log', $record->id) && $ok; + unset($record->id); + } + // update url and info + switch ($record->action) { + case "add": + case "update": + case "view": + $record->url = "view.php?id=".$record->cmid; + $record->info = $moduleid; + break; + case "view all": + // do nothing + break; + case "report": + $record->url = "report.php?id=".$record->cmid; + $record->info = $moduleid; + break; + case "attempt": + case "submit": + case "review": + $id = substr(strrchr($record->url,"="),1); + if (isset($new->attempt[$id])) { + $id = $new->attempt[$id]; + } + $record->url = "review.php?id=".$record->cmid."&attempt=$id"; + $record->info = $moduleid; + break; + default: + // unknown log action + $ok = hotpot_update_print_warning('action', $record->action, 'log', $record->id) && $ok; + unset($record->id); + } // end switch + } + if (isset($record->id)) { + $ok = $ok && update_record($table, $record); + } + $i++; + hotpot_update_print_progress($i); + } // end foreach + // finish progress report + hotpot_update_print_ok($ok); + } + return $ok; +} +function hotpot_update_fields($table, $feedback=false) { + global $CFG, $db; + $ok = true; + // check the table exists + if (hotpot_db_table_exists($table)) { + switch ($table) { + case 'hotpot' : + // == ADD == + hotpot_db_update_field_type($table, '', 'location', 'INTEGER', 4, 'UNSIGNED', 'NOT NULL', 0); + hotpot_db_update_field_type($table, '', 'navigation', 'INTEGER', 4, 'UNSIGNED', 'NOT NULL', 1); + hotpot_db_update_field_type($table, '', 'outputformat', 'INTEGER', 4, 'UNSIGNED', 'NOT NULL', 1); + hotpot_db_update_field_type($table, '', 'shownextquiz', 'INTEGER', 4, 'UNSIGNED', 'NOT NULL', 0); + hotpot_db_update_field_type($table, '', 'forceplugins', 'INTEGER', 4, 'UNSIGNED', 'NOT NULL', 0); + hotpot_db_update_field_type($table, '', 'password', 'VARCHAR', 255, '', 'NOT NULL', ''); + hotpot_db_update_field_type($table, '', 'subnet', 'VARCHAR', 255, '', 'NOT NULL', ''); + // == ALTER == + hotpot_db_update_field_type($table, 'summary', 'summary', 'TEXT', '', '', 'NOT NULL', ''); + hotpot_db_update_field_type($table, 'reference', 'reference', 'VARCHAR', 255, '', 'NOT NULL', ''); + // == REMOVE == + hotpot_db_remove_field($table, 'intro'); + hotpot_db_remove_field($table, 'attemptonlast'); + hotpot_db_remove_field($table, 'sumgrades'); + hotpot_db_set_table_comment($table, 'details about Hot Potatoes quizzes'); + break; + case 'hotpot_events' : + // == ADD == + hotpot_db_update_field_type($table, '', 'hotpot', 'INTEGER', 10, 'UNSIGNED', 'NOT NULL'); + hotpot_db_update_field_type($table, '', 'attempt', 'INTEGER', 6, 'UNSIGNED', 'NOT NULL'); + hotpot_db_update_field_type($table, '', 'details', 'TEXT', '', '', '', ''); + hotpot_db_update_field_type($table, '', 'timestart', 'INTEGER', 10, 'UNSIGNED', 'NOT NULL', 0); + hotpot_db_update_field_type($table, '', 'timefinish', 'INTEGER', 10, 'UNSIGNED', 'NOT NULL', 0); + // == ALTER == + hotpot_db_update_field_type($table, 'score', 'score', 'INTEGER', 6, 'UNSIGNED', 'NULL'); + hotpot_db_update_field_type($table, 'wrong', 'penalties', 'INTEGER', 6, 'UNSIGNED', 'NULL'); + hotpot_db_update_field_type($table, 'starttime', 'starttime', 'INTEGER', 10, 'UNSIGNED', 'NULL'); + hotpot_db_update_field_type($table, 'endtime', 'endtime', 'INTEGER', 10, 'UNSIGNED', 'NULL'); + // save and switch off SQL message echo + $debug = $db->debug; + $db->debug = $feedback; + // get array mapping course module ids to hotpot ids + $hotpotmoduleid = get_field('modules', 'id', 'name', 'hotpot'); + $coursemodules = get_records('course_modules', 'module', $hotpotmoduleid, 'id', 'id, instance'); + // get all event records + if (hotpot_db_field_exists($table, 'hotpotid')) { + $records = get_records($table, '', '', 'userid,hotpotid,time'); + } else { + $records = false; // table has already been updated + } + if ($records) { + $count = count($records); + hotpot_update_print("Updating $count records in $table ... "); + $ids = array_keys($records); + foreach ($ids as $i=>$id) { + // reference to current record + $record = &$records[$id]; + // set timestart and timefinish (the times recorded by Moodle) + if (empty($record->timestart) && $record->time) { + $record->timestart = $record->time; + } + if (empty($record->timefinish) && $record->timestart) { + if ($record->starttime && $record->endtime) { + $duration = ($record->endtime - $record->starttime); + } else { + if (($i+1)>=$count) { + $nextrecord = NULL; + } else { + $nextrecord = &$records[$ids[$i+1]]; + } + if (isset($nextrecord) && $nextrecord->userid==$record->userid && $nextrecord->hotpotid==$record->hotpotid) { + $duration = $nextrecord->time - $record->time; + } else { + $duration = NULL; + } + } + if (isset($duration)) { + $record->timefinish = $record->timestart + $duration; + } + } + // unset score and penalties, if quiz was abandoned + if (empty($record->endtime) || (empty($record->penalties) && empty($record->score))) { + unset($record->score); + unset($record->penalties); + } + // get last (=previous) record + if ($i==0) { + $lastrecord = NULL; + } else { + $lastrecord = &$records[$ids[$i-1]]; + } + // increment or reset $attempt number + if (isset($lastrecord) && $lastrecord->userid==$record->userid && $lastrecord->hotpotid==$record->hotpotid) { + $attempt++; + } else { + $attempt = 1; + } + // set $record->$attempt, if necessary + if (empty($record->attempt) || $record->attempt<$attempt) { + $record->attempt = $attempt; + } else { + $attempt = $record->attempt; + } + // set hotpot id and update record + if (isset($record->hotpotid) && isset($record->id)) { + if (isset($coursemodules[$record->hotpotid])) { + $record->hotpot = $coursemodules[$record->hotpotid]->instance; + hotpot_db_update_record($table, $record, true); + } else { + // hotpotid is invalid (shouldn't happen) + $ok = hotpot_update_print_warning('hotpotid', $record->hotpotid, $table, $record->id) && $ok; + delete_records($table, 'id', $record->id); + } + } else { + // empty record (shouldn't happen) + } + hotpot_update_print_progress($i); + } + // finish progress report + hotpot_update_print_ok($ok); + } + // restore SQL message echo setting + $db->debug = $debug; + // == REMOVE == + hotpot_db_remove_field($table, 'hotpotid'); + hotpot_db_remove_field($table, 'course'); + hotpot_db_remove_field($table, 'time'); + hotpot_db_remove_field($table, 'event'); + hotpot_db_set_table_comment($table, 'details about Hot Potatoes quiz attempts'); + break; + case 'hotpotatoes' : + // == ALTER == + hotpot_db_update_field_type($table, 'intro', 'summary', 'TEXT', '', '', '', 'NULL'); + break; + } + } + return $ok; +} +function hotpot_update_string_id_list($table, &$record, $field, &$new) { + $ok = true; + if (isset($record->$field)) { + $oldids = explode(',', $record->$field); + $newids = array(); + foreach ($oldids as $id) { + if (isset($new['string'][$id])) { + $newids[] = $new['string'][$id]; + } else if (is_numeric($id)) { + // string id could not be updated + $ok = hotpot_update_print_warning("string id in $field", $id, $table, $record->id) && $ok; + } else { + // ignore non-numeric ids (e.g. blanks) + } + } + if ($ok) { + $record->$field = implode(',', $newids); + } + } + return $ok; +} +/////////////////////////// +// print functions +/////////////////////////// +function hotpot_update_print($msg=false, $n=300) { + // this function prints $msg and flush output buffer + if ($msg) { + if (is_string($msg)) { + print $msg; + } else { + print strftime("%X", time()); + } + } + // fill output buffer + if ($n) { + print str_repeat(" ", $n); + } + // some browser's require newline to flush + print "\n"; + // flush PHP's output buffer + flush(); +} +function hotpot_update_print_progress($i) { + if ($i%10==0) { + $msg = '.'; + hotpot_update_print($msg); + } +} +function hotpot_update_print_ok($ok) { + if ($ok) { + hotpot_update_print(''.get_string('success')."
    \n"); + } else { + hotpot_update_print(''.get_string('error')."
    \n"); + } +} +function hotpot_update_print_warning($field, $value, $table, $id) { + hotpot_update_print("
  • Warning: invalid $field field (value=$value) in $table (id=$id)
  • \n"); + return true; +} +/////////////////////////// +// database functions +/////////////////////////// +function hotpot_db_index_exists($table, $index, $feedback=false) { + global $CFG, $db; + $exists = false; + // save and switch off SQL message echo + $debug = $db->debug; + $db->debug = $feedback; + switch (strtolower($CFG->dbtype)) { + case 'mysql' : + $rs = $db->Execute("SHOW INDEX FROM `$table`"); + if ($rs && $rs->RecordCount()>0) { + $records = $rs->GetArray(); + foreach ($records as $record) { + if (isset($record['Key_name']) && $record['Key_name']==$index) { + $exists = true; + break; + } + } + } + break; + case 'postgres7' : + $rs = $db->Execute("SELECT relname FROM pg_class WHERE relname = '$index' AND relkind='i'"); + if ($rs && $rs->RecordCount()>0) { + $exists = true; + } + break; + } + // restore SQL message echo + $db->debug = $debug; + return $exists; +} +function hotpot_db_delete_index($table, $index, $feedback=false) { + global $CFG, $db; + $ok = true; + // check index exists + if (hotpot_db_index_exists($table, $index)) { + switch (strtolower($CFG->dbtype)) { + case 'mysql' : + $sql = "ALTER TABLE `$table` DROP INDEX `$index`"; + break; + case 'postgres7' : + $sql = "DROP INDEX $index"; + break; + default: // unknown database type + $sql = ''; + break; + } + if ($sql) { + // save and switch off SQL message echo + $debug = $db->debug; + $db->debug = $feedback; + $ok = $db->Execute($sql) ? true : false; + // restore SQL message echo + $db->debug = $debug; + } else { // unknown database type + $ok = false; + } + } + return $ok; +} +function hotpot_db_add_index($table, $field, $length='') { + global $CFG, $db; + // expand $table and $index names + $table = "{$CFG->prefix}$table"; + $index = "{$table}_{$field}_idx"; + // delete $index if it already exists + $ok = hotpot_db_delete_index($table, $index); + switch (strtolower($CFG->dbtype)) { + case 'mysql' : + $length = empty($length) ? '' : " ($length)"; + $ok = $ok && $db->Execute("ALTER TABLE `$table` ADD INDEX `$index` (`$field`$length)"); + break; + case 'postgres7' : + $ok = $ok && $db->Execute("CREATE INDEX $index ON $table ($field)"); + break; + default: // unknown database type + $ok = false; + break; + } + return $ok; +} +function hotpot_db_table_exists($table, $feedback=false) { + return hotpot_db_object_exists($table, '', $feedback); +} +function hotpot_db_field_exists($table, $field, $feedback=false) { + return + hotpot_db_object_exists($table, '', $feedback) && + hotpot_db_object_exists($table, $field, $feedback) + ; +} +function hotpot_db_object_exists($table, $field='', $feedback=false) { + global $CFG,$db; + // expand table name + $table = "{$CFG->prefix}$table"; + // set $sql + switch (strtolower($CFG->dbtype)) { + case 'mysql' : + if (empty($field)) { + $sql = "SHOW TABLES LIKE '$table'"; + } else { + $sql = "SHOW COLUMNS FROM `$table` LIKE '$field'"; + } + break; + case 'postgres7' : + if (empty($field)) { + $sql = "SELECT relname FROM pg_class WHERE relname = '$table' AND relkind='r'"; + } else { + $sql = " + SELECT attname FROM pg_attribute WHERE attname = '$field' + AND attrelid = (SELECT oid FROM pg_class WHERE relname = '$table') + "; + } + break; + } + // save and switch off SQL message echo + $debug = $db->debug; + $db->debug = $feedback; + // execute sql + $rs = $db->Execute($sql); + // restore SQL message echo setting + $db->debug = $debug; + // report error if required + if (empty($rs) && isset($CFG->debug) and $CFG->debug > 7) { + notify($db->ErrorMsg()."

    $sql"); + } + return ($rs && $rs->RecordCount()>0); +} +function hotpot_db_remove_table($table, $feedback=true) { + global $CFG; + if (hotpot_db_table_exists($table)) { + $ok = execute_sql("DROP TABLE {$CFG->prefix}$table", $feedback); + } else { + $ok = true; + } + return $ok; +} +function hotpot_db_rename_table($oldtable, $table, $feedback=true) { + global $CFG; + if (hotpot_db_table_exists($oldtable)) { + $ok = execute_sql("ALTER TABLE {$CFG->prefix}$oldtable RENAME TO {$CFG->prefix}$table", $feedback); + } else { + $ok = true; + } + return $ok; +} +function hotpot_db_append_table($oldtable, $table, $feedback=true) { + global $CFG, $db; + if (hotpot_db_table_exists($oldtable)) { + if (hotpot_db_table_exists($table)) { + // expand table names + $table = "{$CFG->prefix}$table"; + $oldtable = "{$CFG->prefix}$oldtable"; + // get field info + $fields = $db->MetaColumns($table); + $oldfields = $db->MetaColumns($oldtable); + $fieldnames = array(); + if (!empty($fields) || !empty($oldfields)) { + foreach ($fields as $field) { + if ($field->name!='id' && isset($oldfields[strtoupper($field->name)])) { + $fieldnames[] = $field->name; + } + } + } + $fieldnames = implode(',', $fieldnames); + if (empty($fieldnames)) { + $ok = false; + } else { + switch (strtolower($CFG->dbtype)) { + case 'mysql': + $ok = execute_sql("INSERT INTO `$table` ($fieldnames) SELECT $fieldnames FROM `$oldtable` WHERE 1"); + break; + case 'postgres7': + $ok = execute_sql("INSERT INTO $table ($fieldnames) SELECT $fieldnames FROM $oldtable"); + break; + default: + $ok = false; + break; + } + } + } else { // $table does not exist + $ok = hotpot_db_rename_table($oldtable, $table, $feedback); + } + } else { // $oldtable does not exist + $ok = hotpot_db_table_exists($table, $feedback); + } + return $ok; +} +function hotpot_db_set_table_comment($table, $comment, $feedback=true) { + global $CFG; + $ok = true; + switch (strtolower($CFG->dbtype)) { + case 'mysql' : + $ok = execute_sql("ALTER TABLE {$CFG->prefix}$table COMMENT='$comment'"); + break; + case 'postgres7' : + $ok = execute_sql("COMMENT ON TABLE {$CFG->prefix}$table IS '$comment'"); + break; + } + return $ok; +} +function hotpot_db_remove_field($table, $field, $feedback=true) { + global $CFG; + if (hotpot_db_field_exists($table, $field)) { + $ok = execute_sql("ALTER TABLE {$CFG->prefix}$table DROP COLUMN $field", $feedback); + } else { + $ok = true; + } + return $ok; +} +function hotpot_db_update_field_type($table, $oldfield, $field, $type, $size, $unsigned, $notnull, $default=NULL, $after=NULL) { + $ok = true; + global $CFG,$db; + // check validity of arguments, and adjust if necessary + if ($oldfield && !hotpot_db_field_exists($table, $oldfield)) { + $oldfield = ''; + } + if (empty($oldfield) && hotpot_db_field_exists($table, $field)) { + $oldfield = $field; + } + if (is_string($unsigned)) { + $unsigned = (strtoupper($unsigned)=='UNSIGNED'); + } + if (is_string($notnull)) { + $notnull = (strtoupper($notnull)=='NOT NULL'); + } + if (isset($default)) { + if (!is_numeric($default) && strtoupper($default)!='NULL' && !preg_match("|^'.*'$|", $default)) { + $default = "'$default'"; + } + } + // set full table name + $table = "{$CFG->prefix}$table"; + // update the field in the database + switch (strtolower($CFG->dbtype)) { + case 'mysql': + // optimize integer types + switch (strtoupper($type)) { + case 'TEXT': + $size = ''; + $unsigned = false; + break; + case 'INTEGER' : + if (!is_numeric($size)) { + $size = ''; + } else if ($size <= 4) { + $type = "TINYINT"; // 1 byte + } else if ($size <= 6) { + $type = "SMALLINT"; // 2 bytes + } else if ($size <= 8) { + $type = "MEDIUMINT"; // 3 bytes + } else if ($size <= 10) { + $type = "INTEGER"; // 4 bytes (=INT) + } else if ($size > 10) { + $type = "BIGINT"; // 8 bytes + } + break; + case 'VARCHAR': + $unsigned = false; + break; + } + // set action + if (empty($oldfield)) { + $action = "ADD"; + } else { + $action = "CHANGE `$oldfield`"; + } + // set fieldtype + $fieldtype = $type; + if ($size) { + $fieldtype .= "($size)"; + } + if ($unsigned) { + $fieldtype .= ' UNSIGNED'; + } + if ($notnull) { + $fieldtype .= ' NOT NULL'; + } + if (isset($default)) { + $fieldtype .= " DEFAULT $default"; + } + if (!empty($after)) { + $fieldtype .= " AFTER `$after`"; + } + $ok = $ok && execute_sql("ALTER TABLE `$table` $action `$field` $fieldtype"); + break; + case 'postgres7': + // get db version + $dbinfo = $db->ServerInfo(); + $dbversion = substr($dbinfo['version'],0,3); + // prevent conflicts with reserved words + $tmpfield = "\"temporary_{$field}_".time()."\""; + $oldfield = "\"$oldfield\""; + $field = "\"$field\""; + switch (strtoupper($type)) { + case "INTEGER": + if (!is_numeric($size)) { + $fieldtype = "INTEGER"; + } else if ($size <= 4) { + $fieldtype = "INT2"; // 2 bytes + } else if ($size <= 10) { + $fieldtype = "INT4"; // 4 bytes (=INTEGER) + } else if ($size > 10) { + $fieldtype = "INT8"; // 8 bytes + } + break; + case "VARCHAR": + $fieldtype = "VARCHAR($size)"; + break; + default: + $fieldtype = $type; + } + // start transaction + execute_sql("BEGIN"); + // create temporary field + execute_sql("ALTER TABLE $table ADD COLUMN $tmpfield $fieldtype"); + // set default + if (isset($default)) { + execute_sql("UPDATE $table SET $tmpfield = $default"); + execute_sql("ALTER TABLE $table ALTER COLUMN $tmpfield SET DEFAULT $default"); + } else { + execute_sql("ALTER TABLE $table ALTER COLUMN $tmpfield DROP DEFAULT"); + } + // set not null + if ($dbversion >= "7.3") { + $notnull = ($notnull ? "SET NOT NULL" : "DROP NOT NULL"); + execute_sql("ALTER TABLE $table ALTER COLUMN $tmpfield $notnull"); + } else { + execute_sql(" + UPDATE pg_attribute SET attnotnull=".($notnull ? 'TRUE' : 'FALSE')." + WHERE attname = $tmpfield + AND attrelid = (SELECT oid FROM pg_class WHERE relname = '$table') + "); + } + // transfer $oldfield values, if necessary + if ( $oldfield != '""' ) { + execute_sql("UPDATE $table SET $tmpfield = CAST ($oldfield AS $fieldtype)"); + execute_sql("ALTER TABLE $table DROP COLUMN $oldfield"); + } + // rename $tmpfield to $field + execute_sql("ALTER TABLE $table RENAME COLUMN $tmpfield TO $field"); + // do the transaction + execute_sql("COMMIT"); + // reclaim disk space (must be done outside transaction) + if ($oldfield != '""' && $dbversion >= "7.3") { + execute_sql("UPDATE $table SET $field = $field"); + execute_sql("VACUUM FULL $table"); + } + break; + } // end switch $CGF->dbtype + return $ok; +} +function hotpot_db_update_record($table, $record, $forcenull=false) { + global $CFG, $db; + $ok = true; + // set full table name + $table = "{$CFG->prefix}$table"; + // get field names + $fields = $db->MetaColumns($table); + if (empty($fields)) { + $ok = false; + } else { + // get values + $values = array(); + foreach ($fields as $field) { + $fieldname = $field->name; + if ($fieldname!='id' && ($forcenull || isset($record->$fieldname))) { + $value = isset($record->$fieldname) ? "'".$record->$fieldname."'" : 'NULL'; + $values[] = "$fieldname = $value"; + } + } + $values = implode(',', $values); + // update values (if there are any) + if ($values) { + $sql = "UPDATE $table SET $values WHERE id='$record->id'"; + $rs = $db->Execute($sql); + if (empty($rs)) { + $ok = false; + if (isset($CFG->debug) and $CFG->debug > 7) { + notify($db->ErrorMsg()."

    $sql"); + } + } + } + } + return $ok; +} +function hotpot_rm($target, $output=true) { + $ok = true; + if (!empty($target)) { + if (is_file($target)) { + if ($output) { + print "removing file: $target ... "; + } + $ok = @unlink($target); + } else if (is_dir($target)) { + $dir = dir($target); + while(false !== ($entry = $dir->read())) { + if ($entry!='.' && $entry!='..') { + $ok = $ok && hotpot_rm($target.DIRECTORY_SEPARATOR.$entry, $output); + } + } + $dir->close(); + if ($output) { + print "removing folder: $target ... "; + } + $ok = $ok && @rmdir($target); + } else { // not a file or directory (probably doesn't exist) + $output = false; + } + if ($output) { + if ($ok) { + print 'OK
    '; + } else { + print 'Failed
    '; + } + } + } + return $ok; +} +function hotpot_flush($n=0, $time=false) { + if ($time) { + $t = strftime("%X",time()); + } else { + $t = ""; + } + echo str_repeat(" ", $n) . $t . "\n"; + flush(); +} +?> diff --git a/mod/hotpot/hotpot-full.js b/mod/hotpot/hotpot-full.js index 51bbdf67727..c0d0b617d20 100644 --- a/mod/hotpot/hotpot-full.js +++ b/mod/hotpot/hotpot-full.js @@ -1,3288 +1,2880 @@ - + diff --git a/mod/hotpot/iframe.js b/mod/hotpot/iframe.js index 10f337e34f6..6185f98f6cd 100644 --- a/mod/hotpot/iframe.js +++ b/mod/hotpot/iframe.js @@ -1,52 +1,52 @@ - + diff --git a/mod/hotpot/report/click/report.php b/mod/hotpot/report/click/report.php index 5d6b5267942..c7d3944cbed 100644 --- a/mod/hotpot/report/click/report.php +++ b/mod/hotpot/report/click/report.php @@ -1,639 +1,539 @@ -create_clickreport_table($hotpot, $cm, $course, $users, $attempts, $questions, $options, $tables=array()); - - // print the table - $this->print_report($course, $hotpot, $tables, $options); - - - return true; - } - - function create_clickreport_table(&$hotpot, &$cm, &$course, &$users, &$attempts, &$questions, &$options, &$tables) { - - global $CFG; - - $is_html = ($options['reportformat']=='htm'); - - // time and date format strings // date format strings - $strftimetime = '%H:%M:%S'; - $strftimedate = get_string('strftimedate'); - - // get the current time and max execution time - $start_report_time = microtime(); - $max_execution_time = ini_get('max_execution_time'); - - $correct = get_string('reportcorrectsymbol', 'hotpot'); - $wrong = get_string('reportwrongsymbol', 'hotpot'); - $nottried = get_string('reportnottriedsymbol', 'hotpot'); - - // shortcuts for font tags - $blank = $is_html ? ' ' : ""; - - // store question count - $questioncount = count($questions); - - // array to map columns onto question ids ($col => $id) - $questionids = array_keys($questions); - - // store exercise type - $exercisetype = $this->get_exercisetype($questions, $questionids, $blank); - - // initialize details ('events' must go last) - $details = array('checks', 'status', 'answers', 'changes', 'hints', 'clues', 'events'); - - // initialize $table - unset($table); - $table->border = 1; - $table->width = '100%'; - - // initialize legend, if necessary - if (!empty($options['reportshowlegend'])) { - $table->legend = array(); - } - - // start $table headings - $this->set_head($options, $table, 'exercise'); - $this->set_head($options, $table, 'user'); - $this->set_head($options, $table, 'attempt'); - $this->set_head($options, $table, 'click'); - - // store clicktype column number - $clicktype_col = count($table->head)-1; - - // finish $table headings - $this->set_head($options, $table, 'details', $exercisetype, $details, $questioncount); - $this->set_head($options, $table, 'totals', $exercisetype); - - // set align and wrap - $this->set_align_and_wrap($table); - - // is link to review allowed? - $allow_review = ($is_html && (isteacher($course->id) || $hotpot->review)); - - // initialize array of data values - $this->data = array(); - - // set exercise data values - $this->set_data_exercise($cm, $course, $hotpot, $questions, $questionids, $questioncount, $blank); - - // add details of users' responses - foreach ($users as $user) { - $this->set_data_user($options, $course, $user); - - unset($clickreportid); - foreach ($user->attempts as $attempt) { - - // initialize totals for - $click = array( - 'qnumber' => array(), - 'correct' => array(), - 'wrong' => array(), - 'answers' => array(), - 'hints' => array(), - 'clues' => array(), - 'changes' => array(), - 'checks' => array(), - 'events' => array(), - 'score' => array(), - 'weighting' => array() - ); - $clicktypes = array(); - - // is the start of a new attempt? - // (clicks in the same attempt have the same clickreportid) - if (!isset($clickreportid) || $clickreportid != $attempt->clickreportid) { - - $clickcount = 1; - $clickreportid = $attempt->clickreportid; - - // initialize totals for all clicks in this attempt - $clicks = $click; // $click has just been initialized - - $this->set_data_attempt($attempt, $strftimedate, $strftimetime, $blank); - } - $cells = array(); - $this->set_data($cells, 'exercise'); - $this->set_data($cells, 'user'); - $this->set_data($cells, 'attempt'); - - // get responses to questions in this attempt - foreach ($attempt->responses as $response) { - - // set $q(uestion number) - $q = array_search($response->question, $questionids); - $click['qnumber'][$q] = true; - - // was this question answered correctly? - if ($answer = hotpot_strings($response->correct)) { - - // mark the question as correctly answered - if (empty($clicks['correct'][$q])) { - $click['correct'][$q] = true; - $clicks['correct'][$q] = true; - } - // unset 'wrong' flags, if necessary - if (isset($click['wrong'][$q])) { - unset($click['wrong'][$q]); - } - if (isset($clicks['wrong'][$q])) { - unset($clicks['wrong'][$q]); - } - - // otherwise, was the question answered wrongly? - } else if ($answer = hotpot_strings($response->wrong)) { - - // mark the question as wrongly answered - $click['wrong'][$q] = true; - $clicks['wrong'][$q] = true; - - } else { // not correct or wrong (curious?!) - unset($answer); - } - - if (!empty($click['correct'][$q]) || !empty($click['wrong'][$q])) { - $click['score'][$q] = $response->score; - $clicks['score'][$q] = $response->score; - - $weighting = isset($response->weighting) ? $response->weighting : 100; - $click['weighting'][$q] = $weighting; - $clicks['weighting'][$q] =$weighting; - } - - foreach($details as $detail) { - switch ($detail) { - case 'answers': - if (isset($answer) && is_string($answer) && !empty($answer)) { - $click[$detail][$q] = $answer; - } - break; - case 'hints': - case 'clues': - case 'checks': - if (isset($response->$detail) && is_numeric($response->$detail) && $response->$detail>0) { - if (!isset($click[$detail][$q]) || $click[$detail][$q] < $response->$detail) { - $click[$detail][$q] = $response->$detail; - } - } - break; - } - } // end foreach $detail - - } // end foreach $response - - $click['types'] = array(); - $this->data['details'] = array(); - - foreach($details as $detail) { - - for ($q=0; $q<$questioncount; $q++) { - switch ($detail) { - case 'status': - if (isset($clicks['correct'][$q])) { - $this->data['details'][] = $correct; - } else if (isset($clicks['wrong'][$q])) { - $this->data['details'][] = $wrong; - } else if (isset($click['qnumber'][$q])) { - $this->data['details'][] = $nottried; - } else { // this question did not appear in this attempt - $this->data['details'][] = $blank; - } - break; - case 'answers': - case 'hints': - case 'clues': - case 'checks': - if (!isset($clicks[$detail][$q])) { - if (!isset($click[$detail][$q])) { - $this->data['details'][] = $blank; - } else { - $clicks[$detail][$q] = $click[$detail][$q]; - if ($detail=='answers') { - $this->set_legend($table, $q, $click[$detail][$q], $questions[$questionids[$q]]); - } - $this->data['details'][] = $click[$detail][$q]; - $this->update_event_count($click, $detail, $q); - } - } else { - if (!isset($click[$detail][$q])) { - $this->data['details'][] = $blank; - } else { - $difference = ''; - if ($detail=='answers') { - if ($click[$detail][$q] != $clicks[$detail][$q]) { - $pattern = '/^'.preg_quote($clicks[$detail][$q], '/').',/'; - $difference = preg_replace($pattern, '', $click[$detail][$q], 1); - } - } else { // hints, clues, checks - if ($click[$detail][$q] > $clicks[$detail][$q]) { - $difference = $click[$detail][$q] - $clicks[$detail][$q]; - } - } - if ($difference) { - $clicks[$detail][$q] = $click[$detail][$q]; - $click[$detail][$q] = $difference; - if ($detail=='answers') { - $this->set_legend($table, $q, $difference, $questions[$questionids[$q]]); - } - $this->data['details'][] = $difference; - $this->update_event_count($click, $detail, $q); - } else { - unset($click[$detail][$q]); - $this->data['details'][] = $blank; - } - } - } - break; - case 'changes': - case 'events': - if (empty($click[$detail][$q])) { - $this->data['details'][] = $blank; - } else { - $this->data['details'][] = $click[$detail][$q]; - } - break; - default: - // do nothing - break; - } // end switch - } // for $q - } // foreach $detail - - // set data cell values for - $this->set_data_click( - $allow_review ? ''.$clickcount.'' : $clickcount, - trim(userdate($attempt->timefinish, $strftimetime)), - $exercisetype, - $click - ); - $this->set_data($cells, 'click'); - $this->set_data($cells, 'details'); - - $this->set_data_totals($click, $clicks, $questioncount, $blank, $attempt); - $this->set_data($cells, 'totals'); - - $table->data[] = $cells; - $clickcount++; - - } // end foreach $attempt - - // insert 'tabledivider' between users - $table->data[] = 'hr'; - - } // end foreach $user - - // remove final 'hr' from data rows - array_pop($table->data); - - if ($is_html && $CFG->hotpot_showtimes) { - $count = count($users); - $duration = sprintf("%0.3f", microtime_diff($start_report_time, microtime())); - print "$count users processed in $duration seconds (".sprintf("%0.3f", $duration/$count).' secs/user)
    '."\n"; - } - - $tables[] = &$table; - $this->create_legend_table($tables, $table); - - } // end function - - function get_exercisetype(&$questions, &$questionids, &$blank) { - if (empty($questions)) { - $type = $blank; - } else { - switch ($questions[$questionids[0]]->type) { - case HOTPOT_JCB: - $type = "JCB"; - break; - case HOTPOT_JCLOZE : - $type = "JCloze"; - break; - case HOTPOT_JCROSS : - $type = "JCross"; - break; - case HOTPOT_JMATCH : - $type = "JMatch"; - break; - case HOTPOT_JMIX : - $type = "JMix"; - break; - case HOTPOT_JQUIZ : - $type = "JQuiz"; - break; - case HOTPOT_TEXTOYS_RHUBARB : - $type = "Rhubarb"; - break; - case HOTPOT_TEXTOYS_SEQUITUR : - $type = "Sequitur"; - break; - default: - $type = $blank; - } - } - return $type; - } - function set_head(&$options, &$table, $zone, $exercisetype='', $details=array(), $questioncount=0) { - - if (empty($table->head)) { - $table->head = array(); - } - switch ($zone) { - - case 'exercise': - array_push($table->head, - get_string('reportcoursename', 'hotpot'), - get_string('reportsectionnumber', 'hotpot'), - get_string('reportexercisenumber', 'hotpot'), - get_string('reportexercisename', 'hotpot'), - get_string('reportexercisetype', 'hotpot'), - get_string('reportnumberofquestions', 'hotpot') - ); - break; - case 'user': - array_push($table->head, - get_string('reportstudentid', 'hotpot'), - get_string('reportlogindate', 'hotpot'), - get_string('reportlogintime', 'hotpot'), - get_string('reportlogofftime', 'hotpot') - ); - break; - case 'attempt': - array_push($table->head, - get_string('reportattemptnumber', 'hotpot'), - get_string('reportattemptstart', 'hotpot'), - get_string('reportattemptfinish', 'hotpot') - ); - break; - case 'click': - array_push($table->head, - get_string('reportclicknumber', 'hotpot'), - get_string('reportclicktime', 'hotpot'), - get_string('reportclicktype', 'hotpot') - ); - break; - - case 'details': - foreach($details as $detail) { - - if ($exercisetype=='JQuiz' && $detail=='clues') { - $detail = 'showanswer'; - } - $detail = get_string("report$detail", 'hotpot'); - - for ($i=0; $i<$questioncount; $i++) { - $str = get_string('questionshort', 'hotpot', $i+1); - if ($i==0 || $options['reportformat']!='htm') { - $str = "$detail $str"; - } - $table->head[] = $str; - } - } - break; - - case 'totals': - - $reportpercentscore =get_string('reportpercentscore', 'hotpot'); - if (!function_exists('clean_getstring_data')) { // Moodle 1.4 (and less) - $reportpercentscore = str_replace('%', '%%', $reportpercentscore); - } - - array_push($table->head, - get_string('reportthisclick', 'hotpot', get_string('reportquestionstried', 'hotpot')), - get_string('reportsofar', 'hotpot', get_string('reportquestionstried', 'hotpot')), - - get_string('reportthisclick', 'hotpot', get_string('reportright', 'hotpot')), - get_string('reportthisclick', 'hotpot', get_string('reportwrong', 'hotpot')), - get_string('reportthisclick', 'hotpot', get_string('reportnottried', 'hotpot')), - - get_string('reportsofar', 'hotpot', get_string('reportright', 'hotpot')), - get_string('reportsofar', 'hotpot', get_string('reportwrong', 'hotpot')), - get_string('reportsofar', 'hotpot', get_string('reportnottried', 'hotpot')), - - get_string('reportthisclick', 'hotpot', get_string('reportanswers', 'hotpot')), - get_string('reportthisclick', 'hotpot', get_string('reporthints', 'hotpot')), - get_string('reportthisclick', 'hotpot', get_string($exercisetype=='JQuiz' ? 'reportshowanswer' : 'reportclues', 'hotpot')), - get_string('reportthisclick', 'hotpot', get_string('reportevents', 'hotpot')), - - get_string('reportsofar', 'hotpot', get_string('reporthints', 'hotpot')), - get_string('reportsofar', 'hotpot', get_string($exercisetype=='JQuiz' ? 'reportshowanswer' : 'reportclues', 'hotpot')), - - get_string('reportthisclick', 'hotpot', get_string('reportrawscore', 'hotpot')), - get_string('reportthisclick', 'hotpot', get_string('reportmaxscore', 'hotpot')), - get_string('reportthisclick', 'hotpot', $reportpercentscore), - - get_string('reportsofar', 'hotpot', get_string('reportrawscore', 'hotpot')), - get_string('reportsofar', 'hotpot', get_string('reportmaxscore', 'hotpot')), - get_string('reportsofar', 'hotpot', $reportpercentscore), - - get_string('reporthotpotscore', 'hotpot') - ); - break; - } // end switch - } - function set_align_and_wrap(&$table) { - $count = count($table->head); - for ($i=0; $i<$count; $i++) { - - if ($i==0 || $i==1 || $i==2 || $i==4 || $i==5 || $i>=7) { - // numeric (and short text) columns - $table->align[] = 'center'; - $table->wrap[] = ''; - } else { - // text columns - $table->align[] = 'left'; - $table->wrap[] = 'nowrap'; - } - } - } - - function set_data_exercise(&$cm, &$course, &$hotpot, &$questions, &$questionids, &$questioncount, &$blank) { - // get exercise details (course name, section number, activity number, quiztype and question count) - $record = get_record("course_sections", "id", $cm->section); - $this->data['exercise'] = array( - 'course' => $course->shortname, - 'section' => empty($record) ? $blank : $record->section+1, - 'number' => empty($record) ? $blank : array_search($cm->id, explode(',', $record->sequence))+1, - 'name' => $hotpot->name, - 'type' => $this->get_exercisetype($questions, $questionids, $blank), - 'questioncount' => $questioncount - ); - } - function set_data_user(&$options, &$course, &$user) { - global $CFG; - - // shortcut to first attempt record (which also hold user info) - $attempt = &$user->attempts[0]; - - $idnumber = $attempt->idnumber; - if (empty($idnumber)) { - $idnumber = fullname($attempt); - } - if ($options['reportformat']=='htm') { - $idnumber = ''.$idnumber.''; - } - $this->data['user'] = array( - 'idnumber' => $idnumber, - ); - } - - function set_data_attempt(&$attempt, &$strftimedate, &$strftimetime, &$blank) { - global $CFG; - - $records = get_records_sql_menu(" - SELECT userid, MAX(time) AS logintime - FROM {$CFG->prefix}log - WHERE userid=$attempt->userid AND action='login' AND time<$attempt->timestart - GROUP BY userid - "); - - if (empty($records)) { - $logindate = $blank; - $logintime = $blank; - } else { - $logintime = $records[$attempt->userid]; - $logindate = trim(userdate($logintime, $strftimedate)); - $logintime = trim(userdate($logintime, $strftimetime)); - } - - $records = get_records_sql_menu(" - SELECT userid, MIN(time) AS logouttime - FROM {$CFG->prefix}log - WHERE userid=$attempt->userid AND action='logout' AND time>$attempt->cr_timefinish - GROUP BY userid - "); - - if (empty($records)) { - $logouttime = $blank; - } else { - $logouttime = $records[$attempt->userid]; - $logouttime = trim(userdate($logouttime, $strftimetime)); - } - - - $this->data['attempt'] = array( - 'logindate' => $logindate, - 'logintime' => $logintime, - 'logouttime' => $logouttime, - - 'number' => $attempt->attempt, - 'start' => trim(userdate($attempt->timestart, $strftimetime)), - 'finish' => trim(userdate($attempt->cr_timefinish, $strftimetime)), - ); - } - - function set_data_click($number, $time, $exercisetype, $click) { - $types = array(); - foreach (array_keys($click['types']) as $type) { - if ($exercisetype=='JQuiz' && $type=='clues') { - $type = 'showanswer'; - } else { - // remove final 's' - $type = substr($type, 0, strlen($type)-1); - } - // $types[] = get_string($type, 'hotpot'); - $types[] = $type; - } - - $this->data['click'] = array( - 'number' => $number, - 'time' => $time, - 'type' => empty($types) ? '??' : implode(',', $types) - ); - } - - function set_data_totals(&$click, &$clicks, &$questioncount, &$blank, &$attempt) { - $count= array( - 'click' => array( - 'correct' => count($click['correct']), - 'wrong' => count($click['wrong']), - 'answers' => count($click['answers']), - 'hints' => array_sum($click['hints']), - 'clues' => array_sum($click['clues']), - 'events' => array_sum($click['events']), - 'score' => array_sum($click['score']), - 'maxscore' => array_sum($click['weighting']), - ), - 'clicks' => array( - 'correct' => count($clicks['correct']), - 'wrong' => count($clicks['wrong']), - 'answers' => count($clicks['answers']), - 'hints' => array_sum($clicks['hints']), - 'clues' => array_sum($clicks['clues']), - 'score' => array_sum($clicks['score']), - 'maxscore' => array_sum($clicks['weighting']), - ) - ); - - foreach ($count as $period=>$values) { - $count[$period]['nottried'] = $questioncount - ($values['correct'] + $values['wrong']); - $count[$period]['percent'] = empty($values['maxscore']) ? $blank : round(100 * $values['score'] / $values['maxscore'], 0); - - // blank out zero click values - if ($period=='click') { - foreach ($values as $detail=>$value) { - if ($detail=='answers' || $detail=='hints' || $detail=='clues' || $detail=='events') { - if (empty($value)) { - $count[$period][$detail] = $blank; - } - } - } - } - } - - $this->data['totals'] = array( - - $count['click']['answers'], // "q's tried" - $count['clicks']['answers'], // "q's tried so far" - $count['click']['correct'], // "right" - $count['click']['wrong'], // "wrong" - $count['click']['nottried'], // "not tried" - $count['clicks']['correct'], // "right so far" - $count['clicks']['wrong'], // "wrong so far" - $count['clicks']['nottried'], // "not tried so far" - - $count['click']['answers'], // "answers", - $count['click']['hints'], // "hints", - $count['click']['clues'], // "clues", - $count['click']['events'], // "answers", - - $count['clicks']['hints'], // "hints so far", - $count['clicks']['clues'], // "clues so far", - - $count['click']['score'], // 'raw score', - $count['click']['maxscore'], // 'max score', - $count['click']['percent'], // '% score' - - $count['clicks']['score'], // 'raw score, - $count['clicks']['maxscore'], // 'max score, - $count['clicks']['percent'], // '% score - - $attempt->score // 'hotpot score' - ); - } - - function update_event_count(&$click, $detail, $q) { - if ($detail=='checks' || $detail=='hints' || $detail=='clues') { - $click['types'][$detail] = true; - } - if ($detail=='answers' || $detail=='hints' || $detail=='clues') { - $click['events'][$q] = isset($click['events'][$q]) ? $click['events'][$q]+1 : 1; - } - if ($detail=='answers') { - $click['changes'][$q] = isset($click['changes'][$q]) ? $click['changes'][$q]+1 : 1; - } - } - - function set_data(&$cells, $zone) { - foreach ($this->data[$zone] as $name=>$value) { - $cells[] = $value; - } - } -} // end class -?> +create_clickreport_table($hotpot, $cm, $course, $users, $attempts, $questions, $options, $tables=array()); + // print the table + $this->print_report($course, $hotpot, $tables, $options); + return true; + } + function create_clickreport_table(&$hotpot, &$cm, &$course, &$users, &$attempts, &$questions, &$options, &$tables) { + global $CFG; + $is_html = ($options['reportformat']=='htm'); + // time and date format strings // date format strings + $strftimetime = '%H:%M:%S'; + $strftimedate = get_string('strftimedate'); + // get the current time and max execution time + $start_report_time = microtime(); + $max_execution_time = ini_get('max_execution_time'); + $correct = get_string('reportcorrectsymbol', 'hotpot'); + $wrong = get_string('reportwrongsymbol', 'hotpot'); + $nottried = get_string('reportnottriedsymbol', 'hotpot'); + // shortcuts for font tags + $blank = $is_html ? ' ' : ""; + // store question count + $questioncount = count($questions); + // array to map columns onto question ids ($col => $id) + $questionids = array_keys($questions); + // store exercise type + $exercisetype = $this->get_exercisetype($questions, $questionids, $blank); + // initialize details ('events' must go last) + $details = array('checks', 'status', 'answers', 'changes', 'hints', 'clues', 'events'); + // initialize $table + unset($table); + $table->border = 1; + $table->width = '100%'; + // initialize legend, if necessary + if (!empty($options['reportshowlegend'])) { + $table->legend = array(); + } + // start $table headings + $this->set_head($options, $table, 'exercise'); + $this->set_head($options, $table, 'user'); + $this->set_head($options, $table, 'attempt'); + $this->set_head($options, $table, 'click'); + // store clicktype column number + $clicktype_col = count($table->head)-1; + // finish $table headings + $this->set_head($options, $table, 'details', $exercisetype, $details, $questioncount); + $this->set_head($options, $table, 'totals', $exercisetype); + // set align and wrap + $this->set_align_and_wrap($table); + // is link to review allowed? + $allow_review = ($is_html && (isteacher($course->id) || $hotpot->review)); + // initialize array of data values + $this->data = array(); + // set exercise data values + $this->set_data_exercise($cm, $course, $hotpot, $questions, $questionids, $questioncount, $blank); + // add details of users' responses + foreach ($users as $user) { + $this->set_data_user($options, $course, $user); + unset($clickreportid); + foreach ($user->attempts as $attempt) { + // initialize totals for + $click = array( + 'qnumber' => array(), + 'correct' => array(), + 'wrong' => array(), + 'answers' => array(), + 'hints' => array(), + 'clues' => array(), + 'changes' => array(), + 'checks' => array(), + 'events' => array(), + 'score' => array(), + 'weighting' => array() + ); + $clicktypes = array(); + // is the start of a new attempt? + // (clicks in the same attempt have the same clickreportid) + if (!isset($clickreportid) || $clickreportid != $attempt->clickreportid) { + $clickcount = 1; + $clickreportid = $attempt->clickreportid; + // initialize totals for all clicks in this attempt + $clicks = $click; // $click has just been initialized + $this->set_data_attempt($attempt, $strftimedate, $strftimetime, $blank); + } + $cells = array(); + $this->set_data($cells, 'exercise'); + $this->set_data($cells, 'user'); + $this->set_data($cells, 'attempt'); + // get responses to questions in this attempt + foreach ($attempt->responses as $response) { + // set $q(uestion number) + $q = array_search($response->question, $questionids); + $click['qnumber'][$q] = true; + // was this question answered correctly? + if ($answer = hotpot_strings($response->correct)) { + // mark the question as correctly answered + if (empty($clicks['correct'][$q])) { + $click['correct'][$q] = true; + $clicks['correct'][$q] = true; + } + // unset 'wrong' flags, if necessary + if (isset($click['wrong'][$q])) { + unset($click['wrong'][$q]); + } + if (isset($clicks['wrong'][$q])) { + unset($clicks['wrong'][$q]); + } + // otherwise, was the question answered wrongly? + } else if ($answer = hotpot_strings($response->wrong)) { + // mark the question as wrongly answered + $click['wrong'][$q] = true; + $clicks['wrong'][$q] = true; + } else { // not correct or wrong (curious?!) + unset($answer); + } + if (!empty($click['correct'][$q]) || !empty($click['wrong'][$q])) { + $click['score'][$q] = $response->score; + $clicks['score'][$q] = $response->score; + $weighting = isset($response->weighting) ? $response->weighting : 100; + $click['weighting'][$q] = $weighting; + $clicks['weighting'][$q] =$weighting; + } + foreach($details as $detail) { + switch ($detail) { + case 'answers': + if (isset($answer) && is_string($answer) && !empty($answer)) { + $click[$detail][$q] = $answer; + } + break; + case 'hints': + case 'clues': + case 'checks': + if (isset($response->$detail) && is_numeric($response->$detail) && $response->$detail>0) { + if (!isset($click[$detail][$q]) || $click[$detail][$q] < $response->$detail) { + $click[$detail][$q] = $response->$detail; + } + } + break; + } + } // end foreach $detail + } // end foreach $response + $click['types'] = array(); + $this->data['details'] = array(); + foreach($details as $detail) { + for ($q=0; $q<$questioncount; $q++) { + switch ($detail) { + case 'status': + if (isset($clicks['correct'][$q])) { + $this->data['details'][] = $correct; + } else if (isset($clicks['wrong'][$q])) { + $this->data['details'][] = $wrong; + } else if (isset($click['qnumber'][$q])) { + $this->data['details'][] = $nottried; + } else { // this question did not appear in this attempt + $this->data['details'][] = $blank; + } + break; + case 'answers': + case 'hints': + case 'clues': + case 'checks': + if (!isset($clicks[$detail][$q])) { + if (!isset($click[$detail][$q])) { + $this->data['details'][] = $blank; + } else { + $clicks[$detail][$q] = $click[$detail][$q]; + if ($detail=='answers') { + $this->set_legend($table, $q, $click[$detail][$q], $questions[$questionids[$q]]); + } + $this->data['details'][] = $click[$detail][$q]; + $this->update_event_count($click, $detail, $q); + } + } else { + if (!isset($click[$detail][$q])) { + $this->data['details'][] = $blank; + } else { + $difference = ''; + if ($detail=='answers') { + if ($click[$detail][$q] != $clicks[$detail][$q]) { + $pattern = '/^'.preg_quote($clicks[$detail][$q], '/').',/'; + $difference = preg_replace($pattern, '', $click[$detail][$q], 1); + } + } else { // hints, clues, checks + if ($click[$detail][$q] > $clicks[$detail][$q]) { + $difference = $click[$detail][$q] - $clicks[$detail][$q]; + } + } + if ($difference) { + $clicks[$detail][$q] = $click[$detail][$q]; + $click[$detail][$q] = $difference; + if ($detail=='answers') { + $this->set_legend($table, $q, $difference, $questions[$questionids[$q]]); + } + $this->data['details'][] = $difference; + $this->update_event_count($click, $detail, $q); + } else { + unset($click[$detail][$q]); + $this->data['details'][] = $blank; + } + } + } + break; + case 'changes': + case 'events': + if (empty($click[$detail][$q])) { + $this->data['details'][] = $blank; + } else { + $this->data['details'][] = $click[$detail][$q]; + } + break; + default: + // do nothing + break; + } // end switch + } // for $q + } // foreach $detail + // set data cell values for + $this->set_data_click( + $allow_review ? ''.$clickcount.'' : $clickcount, + trim(userdate($attempt->timefinish, $strftimetime)), + $exercisetype, + $click + ); + $this->set_data($cells, 'click'); + $this->set_data($cells, 'details'); + $this->set_data_totals($click, $clicks, $questioncount, $blank, $attempt); + $this->set_data($cells, 'totals'); + $table->data[] = $cells; + $clickcount++; + } // end foreach $attempt + // insert 'tabledivider' between users + $table->data[] = 'hr'; + } // end foreach $user + // remove final 'hr' from data rows + array_pop($table->data); + if ($is_html && $CFG->hotpot_showtimes) { + $count = count($users); + $duration = sprintf("%0.3f", microtime_diff($start_report_time, microtime())); + print "$count users processed in $duration seconds (".sprintf("%0.3f", $duration/$count).' secs/user)
    '."\n"; + } + $tables[] = &$table; + $this->create_legend_table($tables, $table); + } // end function + function get_exercisetype(&$questions, &$questionids, &$blank) { + if (empty($questions)) { + $type = $blank; + } else { + switch ($questions[$questionids[0]]->type) { + case HOTPOT_JCB: + $type = "JCB"; + break; + case HOTPOT_JCLOZE : + $type = "JCloze"; + break; + case HOTPOT_JCROSS : + $type = "JCross"; + break; + case HOTPOT_JMATCH : + $type = "JMatch"; + break; + case HOTPOT_JMIX : + $type = "JMix"; + break; + case HOTPOT_JQUIZ : + $type = "JQuiz"; + break; + case HOTPOT_TEXTOYS_RHUBARB : + $type = "Rhubarb"; + break; + case HOTPOT_TEXTOYS_SEQUITUR : + $type = "Sequitur"; + break; + default: + $type = $blank; + } + } + return $type; + } + function set_head(&$options, &$table, $zone, $exercisetype='', $details=array(), $questioncount=0) { + if (empty($table->head)) { + $table->head = array(); + } + switch ($zone) { + case 'exercise': + array_push($table->head, + get_string('reportcoursename', 'hotpot'), + get_string('reportsectionnumber', 'hotpot'), + get_string('reportexercisenumber', 'hotpot'), + get_string('reportexercisename', 'hotpot'), + get_string('reportexercisetype', 'hotpot'), + get_string('reportnumberofquestions', 'hotpot') + ); + break; + case 'user': + array_push($table->head, + get_string('reportstudentid', 'hotpot'), + get_string('reportlogindate', 'hotpot'), + get_string('reportlogintime', 'hotpot'), + get_string('reportlogofftime', 'hotpot') + ); + break; + case 'attempt': + array_push($table->head, + get_string('reportattemptnumber', 'hotpot'), + get_string('reportattemptstart', 'hotpot'), + get_string('reportattemptfinish', 'hotpot') + ); + break; + case 'click': + array_push($table->head, + get_string('reportclicknumber', 'hotpot'), + get_string('reportclicktime', 'hotpot'), + get_string('reportclicktype', 'hotpot') + ); + break; + case 'details': + foreach($details as $detail) { + if ($exercisetype=='JQuiz' && $detail=='clues') { + $detail = 'showanswer'; + } + $detail = get_string("report$detail", 'hotpot'); + for ($i=0; $i<$questioncount; $i++) { + $str = get_string('questionshort', 'hotpot', $i+1); + if ($i==0 || $options['reportformat']!='htm') { + $str = "$detail $str"; + } + $table->head[] = $str; + } + } + break; + case 'totals': + $reportpercentscore =get_string('reportpercentscore', 'hotpot'); + if (!function_exists('clean_getstring_data')) { // Moodle 1.4 (and less) + $reportpercentscore = str_replace('%', '%%', $reportpercentscore); + } + array_push($table->head, + get_string('reportthisclick', 'hotpot', get_string('reportquestionstried', 'hotpot')), + get_string('reportsofar', 'hotpot', get_string('reportquestionstried', 'hotpot')), + get_string('reportthisclick', 'hotpot', get_string('reportright', 'hotpot')), + get_string('reportthisclick', 'hotpot', get_string('reportwrong', 'hotpot')), + get_string('reportthisclick', 'hotpot', get_string('reportnottried', 'hotpot')), + get_string('reportsofar', 'hotpot', get_string('reportright', 'hotpot')), + get_string('reportsofar', 'hotpot', get_string('reportwrong', 'hotpot')), + get_string('reportsofar', 'hotpot', get_string('reportnottried', 'hotpot')), + get_string('reportthisclick', 'hotpot', get_string('reportanswers', 'hotpot')), + get_string('reportthisclick', 'hotpot', get_string('reporthints', 'hotpot')), + get_string('reportthisclick', 'hotpot', get_string($exercisetype=='JQuiz' ? 'reportshowanswer' : 'reportclues', 'hotpot')), + get_string('reportthisclick', 'hotpot', get_string('reportevents', 'hotpot')), + get_string('reportsofar', 'hotpot', get_string('reporthints', 'hotpot')), + get_string('reportsofar', 'hotpot', get_string($exercisetype=='JQuiz' ? 'reportshowanswer' : 'reportclues', 'hotpot')), + get_string('reportthisclick', 'hotpot', get_string('reportrawscore', 'hotpot')), + get_string('reportthisclick', 'hotpot', get_string('reportmaxscore', 'hotpot')), + get_string('reportthisclick', 'hotpot', $reportpercentscore), + get_string('reportsofar', 'hotpot', get_string('reportrawscore', 'hotpot')), + get_string('reportsofar', 'hotpot', get_string('reportmaxscore', 'hotpot')), + get_string('reportsofar', 'hotpot', $reportpercentscore), + get_string('reporthotpotscore', 'hotpot') + ); + break; + } // end switch + } + function set_align_and_wrap(&$table) { + $count = count($table->head); + for ($i=0; $i<$count; $i++) { + if ($i==0 || $i==1 || $i==2 || $i==4 || $i==5 || $i>=7) { + // numeric (and short text) columns + $table->align[] = 'center'; + $table->wrap[] = ''; + } else { + // text columns + $table->align[] = 'left'; + $table->wrap[] = 'nowrap'; + } + } + } + function set_data_exercise(&$cm, &$course, &$hotpot, &$questions, &$questionids, &$questioncount, &$blank) { + // get exercise details (course name, section number, activity number, quiztype and question count) + $record = get_record("course_sections", "id", $cm->section); + $this->data['exercise'] = array( + 'course' => $course->shortname, + 'section' => empty($record) ? $blank : $record->section+1, + 'number' => empty($record) ? $blank : array_search($cm->id, explode(',', $record->sequence))+1, + 'name' => $hotpot->name, + 'type' => $this->get_exercisetype($questions, $questionids, $blank), + 'questioncount' => $questioncount + ); + } + function set_data_user(&$options, &$course, &$user) { + global $CFG; + // shortcut to first attempt record (which also hold user info) + $attempt = &$user->attempts[0]; + $idnumber = $attempt->idnumber; + if (empty($idnumber)) { + $idnumber = fullname($attempt); + } + if ($options['reportformat']=='htm') { + $idnumber = ''.$idnumber.''; + } + $this->data['user'] = array( + 'idnumber' => $idnumber, + ); + } + function set_data_attempt(&$attempt, &$strftimedate, &$strftimetime, &$blank) { + global $CFG; + $records = get_records_sql_menu(" + SELECT userid, MAX(time) AS logintime + FROM {$CFG->prefix}log + WHERE userid=$attempt->userid AND action='login' AND time<$attempt->timestart + GROUP BY userid + "); + if (empty($records)) { + $logindate = $blank; + $logintime = $blank; + } else { + $logintime = $records[$attempt->userid]; + $logindate = trim(userdate($logintime, $strftimedate)); + $logintime = trim(userdate($logintime, $strftimetime)); + } + $records = get_records_sql_menu(" + SELECT userid, MIN(time) AS logouttime + FROM {$CFG->prefix}log + WHERE userid=$attempt->userid AND action='logout' AND time>$attempt->cr_timefinish + GROUP BY userid + "); + if (empty($records)) { + $logouttime = $blank; + } else { + $logouttime = $records[$attempt->userid]; + $logouttime = trim(userdate($logouttime, $strftimetime)); + } + $this->data['attempt'] = array( + 'logindate' => $logindate, + 'logintime' => $logintime, + 'logouttime' => $logouttime, + 'number' => $attempt->attempt, + 'start' => trim(userdate($attempt->timestart, $strftimetime)), + 'finish' => trim(userdate($attempt->cr_timefinish, $strftimetime)), + ); + } + function set_data_click($number, $time, $exercisetype, $click) { + $types = array(); + foreach (array_keys($click['types']) as $type) { + if ($exercisetype=='JQuiz' && $type=='clues') { + $type = 'showanswer'; + } else { + // remove final 's' + $type = substr($type, 0, strlen($type)-1); + } + // $types[] = get_string($type, 'hotpot'); + $types[] = $type; + } + $this->data['click'] = array( + 'number' => $number, + 'time' => $time, + 'type' => empty($types) ? '??' : implode(',', $types) + ); + } + function set_data_totals(&$click, &$clicks, &$questioncount, &$blank, &$attempt) { + $count= array( + 'click' => array( + 'correct' => count($click['correct']), + 'wrong' => count($click['wrong']), + 'answers' => count($click['answers']), + 'hints' => array_sum($click['hints']), + 'clues' => array_sum($click['clues']), + 'events' => array_sum($click['events']), + 'score' => array_sum($click['score']), + 'maxscore' => array_sum($click['weighting']), + ), + 'clicks' => array( + 'correct' => count($clicks['correct']), + 'wrong' => count($clicks['wrong']), + 'answers' => count($clicks['answers']), + 'hints' => array_sum($clicks['hints']), + 'clues' => array_sum($clicks['clues']), + 'score' => array_sum($clicks['score']), + 'maxscore' => array_sum($clicks['weighting']), + ) + ); + foreach ($count as $period=>$values) { + $count[$period]['nottried'] = $questioncount - ($values['correct'] + $values['wrong']); + $count[$period]['percent'] = empty($values['maxscore']) ? $blank : round(100 * $values['score'] / $values['maxscore'], 0); + // blank out zero click values + if ($period=='click') { + foreach ($values as $detail=>$value) { + if ($detail=='answers' || $detail=='hints' || $detail=='clues' || $detail=='events') { + if (empty($value)) { + $count[$period][$detail] = $blank; + } + } + } + } + } + $this->data['totals'] = array( + $count['click']['answers'], // "q's tried" + $count['clicks']['answers'], // "q's tried so far" + $count['click']['correct'], // "right" + $count['click']['wrong'], // "wrong" + $count['click']['nottried'], // "not tried" + $count['clicks']['correct'], // "right so far" + $count['clicks']['wrong'], // "wrong so far" + $count['clicks']['nottried'], // "not tried so far" + $count['click']['answers'], // "answers", + $count['click']['hints'], // "hints", + $count['click']['clues'], // "clues", + $count['click']['events'], // "answers", + $count['clicks']['hints'], // "hints so far", + $count['clicks']['clues'], // "clues so far", + $count['click']['score'], // 'raw score', + $count['click']['maxscore'], // 'max score', + $count['click']['percent'], // '% score' + $count['clicks']['score'], // 'raw score, + $count['clicks']['maxscore'], // 'max score, + $count['clicks']['percent'], // '% score + $attempt->score // 'hotpot score' + ); + } + function update_event_count(&$click, $detail, $q) { + if ($detail=='checks' || $detail=='hints' || $detail=='clues') { + $click['types'][$detail] = true; + } + if ($detail=='answers' || $detail=='hints' || $detail=='clues') { + $click['events'][$q] = isset($click['events'][$q]) ? $click['events'][$q]+1 : 1; + } + if ($detail=='answers') { + $click['changes'][$q] = isset($click['changes'][$q]) ? $click['changes'][$q]+1 : 1; + } + } + function set_data(&$cells, $zone) { + foreach ($this->data[$zone] as $name=>$value) { + $cells[] = $value; + } + } +} // end class +?> diff --git a/mod/hotpot/report/fullstat/report.php b/mod/hotpot/report/fullstat/report.php index 47b40a18057..7eafbae7c26 100644 --- a/mod/hotpot/report/fullstat/report.php +++ b/mod/hotpot/report/fullstat/report.php @@ -1,553 +1,448 @@ -create_responses_table($hotpot, $course, $users, $attempts, $questions, $options, $tables); - $this->create_analysis_table($users, $attempts, $questions, $options, $tables); - - // print report - $this->print_report($course, $hotpot, $tables, $options); - - return true; - } - - function create_responses_table(&$hotpot, &$course, &$users, &$attempts, &$questions, &$options, &$tables) { - - global $CFG; - - $is_html = ($options['reportformat']=='htm'); - - // shortcuts for font tags - $br = $is_html ? "
    \n" : "\n"; - $blank = $is_html ? ' ' : ""; - $font_end = $is_html ? '' : ''; - $font_red = $is_html ? '' : ''; - $font_blue = $is_html ? '' : ''; - $font_brown = $is_html ? '' : ''; - $font_green = $is_html ? '' : ''; - $font_small = $is_html ? '' : ''; - $nobr_start = $is_html ? '' : ''; - $nobr_end = $is_html ? '' : ''; - - // is review allowed? (do this once here, to save time later) - $allow_review = ($is_html && (isteacher($course->id) || $hotpot->review)); - - // assume penalties column is NOT required - $show_penalties = false; - - // initialize $table - unset($table); - $table->border = 1; - $table->width = '100%'; - - // initialize legend, if necessary - if (!empty($options['reportshowlegend'])) { - $table->legend = array(); - } - - // headings for name, attempt number, score/grade and penalties - $table->head = array( - get_string("name"), - hotpot_grade_heading($hotpot, $options), - get_string('attempt', 'quiz'), - ); - $table->align = array('left', 'center', 'center'); - $table->size = array(150, 80, 10); - $table->wrap = array(0, 0, 0); - $table->fontsize = array(0, 0, 0); - - // question headings - $this->add_question_headings($questions, $table, 'left', 0, false, 2); - - // penalties (not always needed) and raw score - array_push($table->head, - get_string('penalties', 'hotpot'), - get_string('score', 'quiz') - ); - array_push($table->align, 'center', 'center'); - array_push($table->size, 50, 50); - array_push($table->wrap, 0, 0); - array_push($table->fontsize, 0, 0); - - // message strings - $strnoresponse = get_string('noresponse', 'quiz'); - - // array to map columns onto question ids ($col => $id) - $questionids = array_keys($questions); - - // add details of users' responses - foreach ($users as $user) { - - // shortcut to user info held in first attempt record - $u = &$user->attempts[0]; - - if (function_exists("fullname")) { - $name = fullname($u); - } else { - $name = "$u->firstname $u->lastname"; - } - if ($is_html) { - $name = ''.$name.''; - } - $grade = isset($user->grade) ? $user->grade : $blank; - - foreach ($user->attempts as $attempt) { - - $attemptnumber = $attempt->attempt; - if ($allow_review) { - $attemptnumber = ' '.$attemptnumber.''; - } - $cells = array ($name, $grade, $attemptnumber); - - // $name and $grade are only printed on first line per user - $name = $blank; - $grade = $blank; - - $start_col = count($cells); - foreach ($questionids as $col => $id) { - $cells[$start_col + $col] = "$font_brown($strnoresponse)$font_end"; - } - - if (isset($attempt->penalties)) { - $show_penalties = true; - $penalties = $attempt->penalties; - } else { - $penalties = $blank; - } - array_push($cells, $penalties, hotpot_format_score($attempt)); - - // get responses to questions in this attempt - foreach ($attempt->responses as $response) { - - // check this question id is OK (should be) - $col = array_search($response->question, $questionids); - if (is_numeric($col)) { - - // correct - if ($value = hotpot_strings($response->correct)) { - $this->set_legend($table, $col, $value, $questions[$response->question]); - } else { - $value = "($strnoresponse)"; - } - $cell = $font_red.$value.$font_end; - - // wrong - if ($value = hotpot_strings($response->wrong)) { - if (isset($table->legend)) { - $values = array(); - foreach (explode(',', $value) as $v) { - $this->set_legend($table, $col, $v, $questions[$response->question]); - $values[] = $v; - } - $value = implode(',', $values); - } - $cell .= $br.$font_blue.$value.$font_end; - } - - // ignored - if ($value = hotpot_strings($response->ignored)) { - if (isset($table->legend)) { - $values = array(); - foreach (explode(',', $value) as $v) { - $this->set_legend($table, $col, $v, $questions[$response->question]); - $values[] = $v; - } - $value = implode(',', $values); - } - $cell .= $br.$font_brown.$value.$font_end; - } - - // numeric - if (is_numeric($response->score)) { - if (empty($table->caption)) { - $table->caption = get_string('indivresp', 'quiz'); - if ($is_html) { - $table->caption .= helpbutton('responsestable', $table->caption, 'hotpot', true, false, '', true); - } - } - $hints = empty($response->hints) ? 0 : $response->hints; - $clues = empty($response->clues) ? 0 : $response->clues; - $checks = empty($response->checks) ? 0 : $response->checks; - $numeric = $response->score.'% '.$blank.' ('.$hints.','.$clues.','.$checks.')'; - $cell .= $br.$nobr_start.$font_green.$numeric.$font_end.$nobr_end; - } - - $cells[$start_col + $col] = $cell; - } - } - $table->data[] = $cells; - } - - // insert 'tabledivider' between users - $table->data[] = 'hr'; - - } // end foreach $users - - // remove final 'hr' from data rows - array_pop($table->data); - - if (!$show_penalties) { - $col = 3 + count($questionids); - $this->remove_column($table, $col); - } - - $tables[] = &$table; - } - - function create_analysis_table(&$users, &$attempts, &$questions, &$options, &$tables) { - - $is_html = ($options['reportformat']=='htm'); - - // the fields we are interested in, in the order we want them - $fields = array('correct', 'wrong', 'ignored', 'hints', 'clues', 'checks', 'weighting'); - $string_fields = array('correct', 'wrong', 'ignored'); - - $q = array(); // statistics about the $q(uestions) - $f = array(); // statistics about the $f(ields) - - //////////////////////////////////////////// - // compile the statistics about the questions - //////////////////////////////////////////// - - foreach ($questions as $id=>$question) { - - // extract scores for attempts at this question - $scores = array(); - foreach ($question->attempts as $attempt) { - $scores[] = $attempt->score; - } - - // sort scores values (in ascending order) - asort($scores); - - // get the borderline high and low scores - $count = count($scores); - switch ($count) { - case 0: - $lo_score = 0; - $hi_score = 0; - break; - case 1: - $lo_score = 0; - $hi_score = $scores[0]; - break; - default: - $lo_score = $scores[round($count*1/3)]; - $hi_score = $scores[round($count*2/3)]; - break; - } - - // get statistics for each attempt which includes this question - foreach ($question->attempts as $attempt) { - - $is_hi_score = ($attempt->score >= $hi_score); - $is_lo_score = ($attempt->score < $lo_score); - - // reference to the response to the current question - $response = &$attempt->responses[$id]; - - // update statistics for fields in this response - foreach($fields as $field) { - - if (!isset($q[$id])) { - $q[$id] = array(); - } - - if (!isset($f[$field])) { - $f[$field] = array('count' => 0); - } - - if (!isset($q[$id][$field])) { - $q[$id][$field] = array('count' => 0); - } - - $values = explode(',', $response->$field); - $values = array_unique($values); - foreach($values as $value) { - - // $value should be an integer (string_id or count) - if (is_numeric($value)) { - - $f[$field]['count']++; - - if (!isset($q[$id][$field][$value])) { - $q[$id][$field][$value] = 0; - } - - $q[$id][$field]['count']++; - $q[$id][$field][$value]++; - } - } - } // end foreach $field - - // initialize counters for this question, if necessary - if (!isset($q[$id]['count'])) { - $q[$id]['count'] = array('hi'=>0, 'lo'=>0, 'correct'=>0, 'total'=>0, 'sum'=>0); - } - - // increment counters - $q[$id]['count']['sum'] += $response->score; - $q[$id]['count']['total']++; - if ($response->score==100) { - $q[$id]['count']['correct']++; - if ($is_hi_score) { - $q[$id]['count']['hi']++; - } else if ($is_lo_score) { - $q[$id]['count']['lo']++; - } - } - - } // end foreach attempt - } // end foreach question - - // check we have some details - if (count($q)) { - $showhideid = 'showhide'; - - // shortcuts for html tags - $bold_start = $is_html ? '' : ""; - $bold_end = $is_html ? '' : ""; - $div_start = $is_html ? '
    ' : ""; - $div_end = $is_html ? '
    ' : ""; - - $font_red = $is_html ? '' : ''; - $font_blue = $is_html ? '' : ''; - $font_green = $is_html ? '' : ''; - $font_brown = $is_html ? '' : ''; - $font_end = $is_html ? ''."\n" : ''; - - $br = $is_html ? '
    ' : "\n"; - $space = $is_html ? ' ' : ""; - $no_value = $is_html ? '--' : ""; - $help_button = $is_html ? helpbutton("discrimination", "", "quiz", true, false, "", true) : ""; - - // table properties - unset($table); - $table->border = 1; - $table->width = '100%'; - $table->caption = get_string('itemanal', 'quiz'); - if ($is_html) { - $table->caption .= helpbutton('analysistable', $table->caption, 'hotpot', true, false, '', true); - } - - // initialize legend, if necessary - if (!empty($options['reportshowlegend'])) { - if (empty($tables) || empty($tables[0]->legend)) { - $table->legend = array(); - } else { - $table->legend = $tables[0]->legend; - unset($tables[0]->legend); - } - } - - // headings for name, attempt number and score/grade - $table->head = array($space); - $table->align = array('right'); - $table->size = array(80); - - // question headings - $this->add_question_headings($questions, $table, 'left', 0); - - // initialize statistics - $table->stat = array(); - $table->statheadercols = array(0); - - // add headings for the $foot of the $table - $table->foot = array(); - $table->foot[0] = array(get_string('average', 'hotpot')); - $table->foot[1] = array(get_string('percentcorrect', 'quiz')); - $table->foot[2] = array(get_string('discrimination', 'quiz').$help_button); - - // maximum discrimination index (also default the default value) - $max_d_index = 10; - - //////////////////////////////////////////// - // format the statistics into the $table - //////////////////////////////////////////// - - // add $stat(istics) and $foot of $table - $questionids = array_keys($q); - foreach ($questionids as $col => $id) { - - $row = 0; - - // print the question text if there is no legend - if (empty($table->legend)) { - - // add button to show/hide question text - if (!isset($table->stat[0])) { - $button = $is_html ? hotpot_showhide_button($showhideid) : ""; - $table->stat[0] = array(get_string('question', 'quiz').$button); - } - - // add the question name/text - $name = hotpot_get_question_name($questions[$id]); - $table->stat[$row++][$col+1] = $div_start.$bold_start.$name.$bold_end.$div_end.$space; - } - - // add details about each field - foreach ($fields as $field) { - - // check this row is required - if ($f[$field]['count']) { - - $values = array(); - $string_type = array_search($field, $string_fields); - - // get the value of each response to this field - // and the count of that value - foreach ($q[$id][$field] as $value => $count) { - - if (is_numeric($value) && $count) { - if (is_numeric($string_type)) { - $value = hotpot_string($value); - $this->set_legend($table, $col, $value, $questions[$id]); - switch ($string_type) { - case 0: // correct - $font_start = $font_red; - break; - case 1: // wrong - $font_start = $font_blue; - break; - case 2: // ignored - $font_start = $font_brown; - break; - } - } else { // numeric field - $font_start = $font_green; - } - $values[] = $font_start.round(100*$count/$q[$id]['count']['total']).'%'.$font_end.' '.$value; - } - - } // end foreach $value => $count - - // initialize stat(istics) row for this field, if required - if (!isset($table->stat[$row])) { - $table->stat[$row] = array(get_string($field, 'hotpot')); - } - - // sort the values by frequency (using user-defined function) - usort($values, "hotpot_sort_stat_values"); - - // add stat(istics) values for this field - $table->stat[$row++][$col+1] = count($values) ? implode($br, $values) : $space; - } - } // end foreach field - - // default percent correct and discrimination index for this question - $average = $no_value; - $percent = $no_value; - $d_index = $no_value; - - if (isset($q[$id]['count'])) { - - // average and percent correct - if ($q[$id]['count']['total']) { - $average = round($q[$id]['count']['sum'] / $q[$id]['count']['total']).'%'; - $percent = round(100*$q[$id]['count']['correct'] / $q[$id]['count']['total']).'%'; - $percent .= ' ('.$q[$id]['count']['correct'].'/'.$q[$id]['count']['total'].')'; - } - - // discrimination index - if ($q[$id]['count']['lo']) { - $d_index = min($max_d_index, round($q[$id]['count']['hi'] / $q[$id]['count']['lo'], 1)); - } else { - $d_index = $q[$id]['count']['hi'] ? $max_d_index : 0; - } - $d_index .= ' ('.$q[$id]['count']['hi'].'/'.$q[$id]['count']['lo'].')'; - - } - $table->foot[0][$col+1] = $average; - $table->foot[1][$col+1] = $percent; - $table->foot[2][$col+1] = $d_index; - - } // end foreach $question ($col) - - // add javascript to show/hide question text - if (isset($table->stat[0]) && $is_html && empty($table->legend)) { - $i = count($table->stat[0]); - $table->stat[0][$i-1] .= hotpot_showhide_set($showhideid); - } - - $tables[] = &$table; - $this->create_legend_table($tables, $table); - - } // end if (empty($q) - } // end function -} // end class - -function hotpot_sort_stat_values($a, $b) { - // sorts in descending order - // assumes first chars in $a and $b are a percentage - $a_val = intval(strip_tags($a)); - $b_val = intval(strip_tags($b)); - return ($a_val<$b_val) ? 1 : ($a_val==$b_val ? 0 : -1); -} -function hotpot_showhide_button($id) { - $show = get_string('show'); - $hide = get_string('hide'); - $pref = '1'; - $text = ($pref=='1' ? $hide : $show); -return << - - -SHOWHIDE_BUTTON -; -} - -function hotpot_showhide_set($id) { -return << - - -SHOWHIDE_SET -; -} -?> +create_responses_table($hotpot, $course, $users, $attempts, $questions, $options, $tables); + $this->create_analysis_table($users, $attempts, $questions, $options, $tables); + // print report + $this->print_report($course, $hotpot, $tables, $options); + return true; + } + function create_responses_table(&$hotpot, &$course, &$users, &$attempts, &$questions, &$options, &$tables) { + global $CFG; + $is_html = ($options['reportformat']=='htm'); + // shortcuts for font tags + $br = $is_html ? "
    \n" : "\n"; + $blank = $is_html ? ' ' : ""; + $font_end = $is_html ? '
    ' : ''; + $font_red = $is_html ? '' : ''; + $font_blue = $is_html ? '' : ''; + $font_brown = $is_html ? '' : ''; + $font_green = $is_html ? '' : ''; + $font_small = $is_html ? '' : ''; + $nobr_start = $is_html ? '' : ''; + $nobr_end = $is_html ? '' : ''; + // is review allowed? (do this once here, to save time later) + $allow_review = ($is_html && (isteacher($course->id) || $hotpot->review)); + // assume penalties column is NOT required + $show_penalties = false; + // initialize $table + unset($table); + $table->border = 1; + $table->width = '100%'; + // initialize legend, if necessary + if (!empty($options['reportshowlegend'])) { + $table->legend = array(); + } + // headings for name, attempt number, score/grade and penalties + $table->head = array( + get_string("name"), + hotpot_grade_heading($hotpot, $options), + get_string('attempt', 'quiz'), + ); + $table->align = array('left', 'center', 'center'); + $table->size = array(150, 80, 10); + $table->wrap = array(0, 0, 0); + $table->fontsize = array(0, 0, 0); + // question headings + $this->add_question_headings($questions, $table, 'left', 0, false, 2); + // penalties (not always needed) and raw score + array_push($table->head, + get_string('penalties', 'hotpot'), + get_string('score', 'quiz') + ); + array_push($table->align, 'center', 'center'); + array_push($table->size, 50, 50); + array_push($table->wrap, 0, 0); + array_push($table->fontsize, 0, 0); + // message strings + $strnoresponse = get_string('noresponse', 'quiz'); + // array to map columns onto question ids ($col => $id) + $questionids = array_keys($questions); + // add details of users' responses + foreach ($users as $user) { + // shortcut to user info held in first attempt record + $u = &$user->attempts[0]; + if (function_exists("fullname")) { + $name = fullname($u); + } else { + $name = "$u->firstname $u->lastname"; + } + if ($is_html) { + $name = ''.$name.''; + } + $grade = isset($user->grade) ? $user->grade : $blank; + foreach ($user->attempts as $attempt) { + $attemptnumber = $attempt->attempt; + if ($allow_review) { + $attemptnumber = ' '.$attemptnumber.''; + } + $cells = array ($name, $grade, $attemptnumber); + // $name and $grade are only printed on first line per user + $name = $blank; + $grade = $blank; + $start_col = count($cells); + foreach ($questionids as $col => $id) { + $cells[$start_col + $col] = "$font_brown($strnoresponse)$font_end"; + } + if (isset($attempt->penalties)) { + $show_penalties = true; + $penalties = $attempt->penalties; + } else { + $penalties = $blank; + } + array_push($cells, $penalties, hotpot_format_score($attempt)); + // get responses to questions in this attempt + foreach ($attempt->responses as $response) { + // check this question id is OK (should be) + $col = array_search($response->question, $questionids); + if (is_numeric($col)) { + // correct + if ($value = hotpot_strings($response->correct)) { + $this->set_legend($table, $col, $value, $questions[$response->question]); + } else { + $value = "($strnoresponse)"; + } + $cell = $font_red.$value.$font_end; + // wrong + if ($value = hotpot_strings($response->wrong)) { + if (isset($table->legend)) { + $values = array(); + foreach (explode(',', $value) as $v) { + $this->set_legend($table, $col, $v, $questions[$response->question]); + $values[] = $v; + } + $value = implode(',', $values); + } + $cell .= $br.$font_blue.$value.$font_end; + } + // ignored + if ($value = hotpot_strings($response->ignored)) { + if (isset($table->legend)) { + $values = array(); + foreach (explode(',', $value) as $v) { + $this->set_legend($table, $col, $v, $questions[$response->question]); + $values[] = $v; + } + $value = implode(',', $values); + } + $cell .= $br.$font_brown.$value.$font_end; + } + // numeric + if (is_numeric($response->score)) { + if (empty($table->caption)) { + $table->caption = get_string('indivresp', 'quiz'); + if ($is_html) { + $table->caption .= helpbutton('responsestable', $table->caption, 'hotpot', true, false, '', true); + } + } + $hints = empty($response->hints) ? 0 : $response->hints; + $clues = empty($response->clues) ? 0 : $response->clues; + $checks = empty($response->checks) ? 0 : $response->checks; + $numeric = $response->score.'% '.$blank.' ('.$hints.','.$clues.','.$checks.')'; + $cell .= $br.$nobr_start.$font_green.$numeric.$font_end.$nobr_end; + } + $cells[$start_col + $col] = $cell; + } + } + $table->data[] = $cells; + } + // insert 'tabledivider' between users + $table->data[] = 'hr'; + } // end foreach $users + // remove final 'hr' from data rows + array_pop($table->data); + if (!$show_penalties) { + $col = 3 + count($questionids); + $this->remove_column($table, $col); + } + $tables[] = &$table; + } + function create_analysis_table(&$users, &$attempts, &$questions, &$options, &$tables) { + $is_html = ($options['reportformat']=='htm'); + // the fields we are interested in, in the order we want them + $fields = array('correct', 'wrong', 'ignored', 'hints', 'clues', 'checks', 'weighting'); + $string_fields = array('correct', 'wrong', 'ignored'); + $q = array(); // statistics about the $q(uestions) + $f = array(); // statistics about the $f(ields) + //////////////////////////////////////////// + // compile the statistics about the questions + //////////////////////////////////////////// + foreach ($questions as $id=>$question) { + // extract scores for attempts at this question + $scores = array(); + foreach ($question->attempts as $attempt) { + $scores[] = $attempt->score; + } + // sort scores values (in ascending order) + asort($scores); + // get the borderline high and low scores + $count = count($scores); + switch ($count) { + case 0: + $lo_score = 0; + $hi_score = 0; + break; + case 1: + $lo_score = 0; + $hi_score = $scores[0]; + break; + default: + $lo_score = $scores[round($count*1/3)]; + $hi_score = $scores[round($count*2/3)]; + break; + } + // get statistics for each attempt which includes this question + foreach ($question->attempts as $attempt) { + $is_hi_score = ($attempt->score >= $hi_score); + $is_lo_score = ($attempt->score < $lo_score); + // reference to the response to the current question + $response = &$attempt->responses[$id]; + // update statistics for fields in this response + foreach($fields as $field) { + if (!isset($q[$id])) { + $q[$id] = array(); + } + if (!isset($f[$field])) { + $f[$field] = array('count' => 0); + } + if (!isset($q[$id][$field])) { + $q[$id][$field] = array('count' => 0); + } + $values = explode(',', $response->$field); + $values = array_unique($values); + foreach($values as $value) { + // $value should be an integer (string_id or count) + if (is_numeric($value)) { + $f[$field]['count']++; + if (!isset($q[$id][$field][$value])) { + $q[$id][$field][$value] = 0; + } + $q[$id][$field]['count']++; + $q[$id][$field][$value]++; + } + } + } // end foreach $field + // initialize counters for this question, if necessary + if (!isset($q[$id]['count'])) { + $q[$id]['count'] = array('hi'=>0, 'lo'=>0, 'correct'=>0, 'total'=>0, 'sum'=>0); + } + // increment counters + $q[$id]['count']['sum'] += $response->score; + $q[$id]['count']['total']++; + if ($response->score==100) { + $q[$id]['count']['correct']++; + if ($is_hi_score) { + $q[$id]['count']['hi']++; + } else if ($is_lo_score) { + $q[$id]['count']['lo']++; + } + } + } // end foreach attempt + } // end foreach question + // check we have some details + if (count($q)) { + $showhideid = 'showhide'; + // shortcuts for html tags + $bold_start = $is_html ? '' : ""; + $bold_end = $is_html ? '' : ""; + $div_start = $is_html ? '
    ' : ""; + $div_end = $is_html ? '
    ' : ""; + $font_red = $is_html ? '' : ''; + $font_blue = $is_html ? '' : ''; + $font_green = $is_html ? '' : ''; + $font_brown = $is_html ? '' : ''; + $font_end = $is_html ? ''."\n" : ''; + $br = $is_html ? '
    ' : "\n"; + $space = $is_html ? ' ' : ""; + $no_value = $is_html ? '--' : ""; + $help_button = $is_html ? helpbutton("discrimination", "", "quiz", true, false, "", true) : ""; + // table properties + unset($table); + $table->border = 1; + $table->width = '100%'; + $table->caption = get_string('itemanal', 'quiz'); + if ($is_html) { + $table->caption .= helpbutton('analysistable', $table->caption, 'hotpot', true, false, '', true); + } + // initialize legend, if necessary + if (!empty($options['reportshowlegend'])) { + if (empty($tables) || empty($tables[0]->legend)) { + $table->legend = array(); + } else { + $table->legend = $tables[0]->legend; + unset($tables[0]->legend); + } + } + // headings for name, attempt number and score/grade + $table->head = array($space); + $table->align = array('right'); + $table->size = array(80); + // question headings + $this->add_question_headings($questions, $table, 'left', 0); + // initialize statistics + $table->stat = array(); + $table->statheadercols = array(0); + // add headings for the $foot of the $table + $table->foot = array(); + $table->foot[0] = array(get_string('average', 'hotpot')); + $table->foot[1] = array(get_string('percentcorrect', 'quiz')); + $table->foot[2] = array(get_string('discrimination', 'quiz').$help_button); + // maximum discrimination index (also default the default value) + $max_d_index = 10; + //////////////////////////////////////////// + // format the statistics into the $table + //////////////////////////////////////////// + // add $stat(istics) and $foot of $table + $questionids = array_keys($q); + foreach ($questionids as $col => $id) { + $row = 0; + // print the question text if there is no legend + if (empty($table->legend)) { + // add button to show/hide question text + if (!isset($table->stat[0])) { + $button = $is_html ? hotpot_showhide_button($showhideid) : ""; + $table->stat[0] = array(get_string('question', 'quiz').$button); + } + // add the question name/text + $name = hotpot_get_question_name($questions[$id]); + $table->stat[$row++][$col+1] = $div_start.$bold_start.$name.$bold_end.$div_end.$space; + } + // add details about each field + foreach ($fields as $field) { + // check this row is required + if ($f[$field]['count']) { + $values = array(); + $string_type = array_search($field, $string_fields); + // get the value of each response to this field + // and the count of that value + foreach ($q[$id][$field] as $value => $count) { + if (is_numeric($value) && $count) { + if (is_numeric($string_type)) { + $value = hotpot_string($value); + $this->set_legend($table, $col, $value, $questions[$id]); + switch ($string_type) { + case 0: // correct + $font_start = $font_red; + break; + case 1: // wrong + $font_start = $font_blue; + break; + case 2: // ignored + $font_start = $font_brown; + break; + } + } else { // numeric field + $font_start = $font_green; + } + $values[] = $font_start.round(100*$count/$q[$id]['count']['total']).'%'.$font_end.' '.$value; + } + } // end foreach $value => $count + // initialize stat(istics) row for this field, if required + if (!isset($table->stat[$row])) { + $table->stat[$row] = array(get_string($field, 'hotpot')); + } + // sort the values by frequency (using user-defined function) + usort($values, "hotpot_sort_stat_values"); + // add stat(istics) values for this field + $table->stat[$row++][$col+1] = count($values) ? implode($br, $values) : $space; + } + } // end foreach field + // default percent correct and discrimination index for this question + $average = $no_value; + $percent = $no_value; + $d_index = $no_value; + if (isset($q[$id]['count'])) { + // average and percent correct + if ($q[$id]['count']['total']) { + $average = round($q[$id]['count']['sum'] / $q[$id]['count']['total']).'%'; + $percent = round(100*$q[$id]['count']['correct'] / $q[$id]['count']['total']).'%'; + $percent .= ' ('.$q[$id]['count']['correct'].'/'.$q[$id]['count']['total'].')'; + } + // discrimination index + if ($q[$id]['count']['lo']) { + $d_index = min($max_d_index, round($q[$id]['count']['hi'] / $q[$id]['count']['lo'], 1)); + } else { + $d_index = $q[$id]['count']['hi'] ? $max_d_index : 0; + } + $d_index .= ' ('.$q[$id]['count']['hi'].'/'.$q[$id]['count']['lo'].')'; + } + $table->foot[0][$col+1] = $average; + $table->foot[1][$col+1] = $percent; + $table->foot[2][$col+1] = $d_index; + } // end foreach $question ($col) + // add javascript to show/hide question text + if (isset($table->stat[0]) && $is_html && empty($table->legend)) { + $i = count($table->stat[0]); + $table->stat[0][$i-1] .= hotpot_showhide_set($showhideid); + } + $tables[] = &$table; + $this->create_legend_table($tables, $table); + } // end if (empty($q) + } // end function +} // end class +function hotpot_sort_stat_values($a, $b) { + // sorts in descending order + // assumes first chars in $a and $b are a percentage + $a_val = intval(strip_tags($a)); + $b_val = intval(strip_tags($b)); + return ($a_val<$b_val) ? 1 : ($a_val==$b_val ? 0 : -1); +} +function hotpot_showhide_button($id) { + $show = get_string('show'); + $hide = get_string('hide'); + $pref = '1'; + $text = ($pref=='1' ? $hide : $show); +return << + + +SHOWHIDE_BUTTON +; +} +function hotpot_showhide_set($id) { +return << + + +SHOWHIDE_SET +; +} +?> diff --git a/mod/hotpot/report/overview/report.php b/mod/hotpot/report/overview/report.php index c4155db86c2..f98b0a35b03 100644 --- a/mod/hotpot/report/overview/report.php +++ b/mod/hotpot/report/overview/report.php @@ -1,210 +1,167 @@ -create_overview_table($hotpot, $cm, $course, $users, $attempts, $questions, $options, $tables=array()); - - $this->print_report($course, $hotpot, $tables, $options); - - return true; - } - function create_overview_table(&$hotpot, &$cm, &$course, &$users, &$attempts, &$questions, &$options, &$tables) { - - global $CFG; - - $strtimeformat = get_string('strftimedatetime'); - - $is_html = ($options['reportformat']=='htm'); - - $spacer = $is_html ? ' ' : ' '; - $br = $is_html ? "
    \n" : "\n"; - - // initialize $table - unset($table); - $table->border = 1; - $table->width = 10; - - $table->head = array(); - $table->align = array(); - $table->size = array(); - $table->wrap = array(); - - // picture column, if required - if ($is_html) { - $table->head[] = $spacer; - $table->align[] = 'center'; - $table->size[] = 10; - $table->wrap[] = "nowrap"; - } - - array_push($table->head, - get_string("name"), - hotpot_grade_heading($hotpot, $options), - get_string("attempt", "quiz"), - get_string("time", "quiz"), - get_string("reportstatus", "hotpot"), - get_string("timetaken", "quiz"), - get_string("score", "quiz") - ); - array_push($table->align, "left", "center", "center", "left", "center", "center", "center"); - array_push($table->wrap, "nowrap", "nowrap", "nowrap", "nowrap", "nowrap", "nowrap", "nowrap"); - array_push($table->size, "*", "*", "*", "*", "*", "*", "*"); - - $abandoned = 0; - - foreach ($users as $user) { - - // shortcut to user info held in first attempt record - $u = &$user->attempts[0]; - - $picture = ''; - $name = fullname($u); - if ($is_html) { - $picture = print_user_picture($u->userid, $course->id, $u->picture, false, true); - $name = ''.$name.''; - } - $grade = isset($user->grade) ? $user->grade : $spacer; - - $attemptcount = count($user->attempts); - if ($attemptcount>1) { - $text = $name; - $name = NULL; - $name->text = $text; - $name->rowspan = $attemptcount; - - $text = $grade; - $grade = NULL; - $grade->text = $text; - $grade->rowspan = $attemptcount; - } - - $data = array(); - if ($is_html) { - if ($attemptcount>1) { - $text = $picture; - $picture = NULL; - $picture->text = $text; - $picture->rowspan = $attemptcount; - } - $data[] = $picture; - } - array_push($data, $name, $grade); - - foreach ($user->attempts as $attempt) { - - // increment count of abandoned attempts - // if attempt is marked as finished but has no score - if ($attempt->status==HOTPOT_STATUS_ABANDONED) { - $abandoned++; - } - - $attemptnumber = $attempt->attempt; - $starttime = trim(userdate($attempt->timestart, $strtimeformat)); - - if ($is_html && isset($attempt->score) && (isteacher($course->id) || $hotpot->review)) { - $attemptnumber = ''.$attemptnumber.''; - $starttime = ''.$starttime.''; - } - - if ($is_html && isteacher($course->id)) { - $checkbox = ''.$spacer; - } else { - $checkbox = ''; - } - - $timetaken = empty($attempt->timefinish) ? $spacer : format_time($attempt->timefinish - $attempt->timestart); - - $score = hotpot_format_score($attempt); - if ($is_html && is_numeric($score) && $score==$user->grade) { // best grade - $score = ''.$score.''; - } - - array_push($data, - $attemptnumber, - $checkbox.$starttime, - hotpot_format_status($attempt), - $timetaken, - $score - ); - - $table->data[] = $data; - - $data = array(); - } // end foreach $attempt - - $table->data[] = 'hr'; - } // end foreach $user - - // remove final 'hr' from data rows - array_pop($table->data); - - // add the "delete" form to the table - if ($options['reportformat']=='htm' && isteacher($course->id)) { - $strdeletecheck = get_string('deleteattemptcheck','quiz'); - - $table->start = $this->deleteform_javascript(); - $table->start .= '
    '."\n"; - $table->start .= ''."\n"; - $table->start .= ''."\n"; - - $table->finish = '
    '."\n"; - $table->finish .= ' '."\n"; - if ($abandoned) { - $table->finish .= ''."\n"; - } - $table->finish .= ''."\n"; - $table->finish .= '
    '."\n"; - $table->finish .= '
    '."\n"; - } - - $tables[] = &$table; - } - function deleteform_javascript() { - $strselectattempt = addslashes(get_string('selectattempt','hotpot')); - return << - - -END_OF_JAVASCRIPT -; - } // end function - -} // end class - -?> +create_overview_table($hotpot, $cm, $course, $users, $attempts, $questions, $options, $tables=array()); + $this->print_report($course, $hotpot, $tables, $options); + return true; + } + function create_overview_table(&$hotpot, &$cm, &$course, &$users, &$attempts, &$questions, &$options, &$tables) { + global $CFG; + $strtimeformat = get_string('strftimedatetime'); + $is_html = ($options['reportformat']=='htm'); + $spacer = $is_html ? ' ' : ' '; + $br = $is_html ? "
    \n" : "\n"; + // initialize $table + unset($table); + $table->border = 1; + $table->width = 10; + $table->head = array(); + $table->align = array(); + $table->size = array(); + $table->wrap = array(); + // picture column, if required + if ($is_html) { + $table->head[] = $spacer; + $table->align[] = 'center'; + $table->size[] = 10; + $table->wrap[] = "nowrap"; + } + array_push($table->head, + get_string("name"), + hotpot_grade_heading($hotpot, $options), + get_string("attempt", "quiz"), + get_string("time", "quiz"), + get_string("reportstatus", "hotpot"), + get_string("timetaken", "quiz"), + get_string("score", "quiz") + ); + array_push($table->align, "left", "center", "center", "left", "center", "center", "center"); + array_push($table->wrap, "nowrap", "nowrap", "nowrap", "nowrap", "nowrap", "nowrap", "nowrap"); + array_push($table->size, "*", "*", "*", "*", "*", "*", "*"); + $abandoned = 0; + foreach ($users as $user) { + // shortcut to user info held in first attempt record + $u = &$user->attempts[0]; + $picture = ''; + $name = fullname($u); + if ($is_html) { + $picture = print_user_picture($u->userid, $course->id, $u->picture, false, true); + $name = ''.$name.''; + } + $grade = isset($user->grade) ? $user->grade : $spacer; + $attemptcount = count($user->attempts); + if ($attemptcount>1) { + $text = $name; + $name = NULL; + $name->text = $text; + $name->rowspan = $attemptcount; + $text = $grade; + $grade = NULL; + $grade->text = $text; + $grade->rowspan = $attemptcount; + } + $data = array(); + if ($is_html) { + if ($attemptcount>1) { + $text = $picture; + $picture = NULL; + $picture->text = $text; + $picture->rowspan = $attemptcount; + } + $data[] = $picture; + } + array_push($data, $name, $grade); + foreach ($user->attempts as $attempt) { + // increment count of abandoned attempts + // if attempt is marked as finished but has no score + if ($attempt->status==HOTPOT_STATUS_ABANDONED) { + $abandoned++; + } + $attemptnumber = $attempt->attempt; + $starttime = trim(userdate($attempt->timestart, $strtimeformat)); + if ($is_html && isset($attempt->score) && (isteacher($course->id) || $hotpot->review)) { + $attemptnumber = ''.$attemptnumber.''; + $starttime = ''.$starttime.''; + } + if ($is_html && isteacher($course->id)) { + $checkbox = ''.$spacer; + } else { + $checkbox = ''; + } + $timetaken = empty($attempt->timefinish) ? $spacer : format_time($attempt->timefinish - $attempt->timestart); + $score = hotpot_format_score($attempt); + if ($is_html && is_numeric($score) && $score==$user->grade) { // best grade + $score = ''.$score.''; + } + array_push($data, + $attemptnumber, + $checkbox.$starttime, + hotpot_format_status($attempt), + $timetaken, + $score + ); + $table->data[] = $data; + $data = array(); + } // end foreach $attempt + $table->data[] = 'hr'; + } // end foreach $user + // remove final 'hr' from data rows + array_pop($table->data); + // add the "delete" form to the table + if ($options['reportformat']=='htm' && isteacher($course->id)) { + $strdeletecheck = get_string('deleteattemptcheck','quiz'); + $table->start = $this->deleteform_javascript(); + $table->start .= '
    '."\n"; + $table->start .= ''."\n"; + $table->start .= ''."\n"; + $table->finish = '
    '."\n"; + $table->finish .= ' '."\n"; + if ($abandoned) { + $table->finish .= ''."\n"; + } + $table->finish .= ''."\n"; + $table->finish .= '
    '."\n"; + $table->finish .= '
    '."\n"; + } + $tables[] = &$table; + } + function deleteform_javascript() { + $strselectattempt = addslashes(get_string('selectattempt','hotpot')); + return << + + +END_OF_JAVASCRIPT +; + } // end function +} // end class +?> diff --git a/mod/hotpot/report/simplestat/report.php b/mod/hotpot/report/simplestat/report.php index 769ece49e7f..b5f1b80e369 100644 --- a/mod/hotpot/report/simplestat/report.php +++ b/mod/hotpot/report/simplestat/report.php @@ -1,250 +1,203 @@ -create_scores_table($hotpot, $course, $users, $attempts, $questions, $options, $tables); - - $this->print_report($course, $hotpot, $tables, $options); - - return true; - } - - function create_scores_table(&$hotpot, &$course, &$users, &$attempts, &$questions, &$options, &$tables) { - - global $CFG; - - $download = ($options['reportformat']=='htm') ? false : true; - $is_html = ($options['reportformat']=='htm'); - $blank = ($download ? '' : ' '); - $no_value = ($download ? '' : '-'); - - $allow_review = true; // ($options['reportformat']=='htm' && (isteacher($course->id) || $hotpot->review)); - - // start the table - unset($table); - $table->border = 1; - - $table->head = array(); - $table->align = array(); - $table->size = array(); - - // picture column, if required - if ($is_html) { - $table->head[] = ' '; - $table->align[] = 'center'; - $table->size[] = 10; - } - - // name, grade and attempt number - array_push($table->head, - get_string("name"), - hotpot_grade_heading($hotpot, $options), - get_string("attempt", "quiz") - ); - array_push($table->align, "left", "center", "center"); - array_push($table->size, '', '', ''); - - // question headings - $this->add_question_headings($questions, $table); - - // penalties and raw score - array_push($table->head, - get_string('penalties', 'hotpot'), - get_string('score', 'quiz') - ); - array_push($table->align, "center", "center"); - array_push($table->size, '', ''); - - $table->data = array(); - - $q = array( - 'grade' => array('count'=>0, 'total'=>0), - 'penalties' => array('count'=>0, 'total'=>0), - 'score' => array('count'=>0, 'total'=>0), - ); - - foreach ($users as $user) { - - // shortcut to user info held in first attempt record - $u = &$user->attempts[0]; - - $picture = ''; - $name = fullname($u); - if ($is_html) { - $picture = print_user_picture($u->userid, $course->id, $u->picture, false, true); - $name = ''.$name.''; - } - - if (isset($user->grade)) { - $grade = $user->grade; - $q['grade']['count'] ++; - if (is_numeric($grade)) { - $q['grade']['total'] += $grade; - } - } else { - $grade = $no_value; - } - - $attemptcount = count($user->attempts); - if ($attemptcount>1) { - $text = $name; - $name = NULL; - $name->text = $text; - $name->rowspan = $attemptcount; - - $text = $grade; - $grade = NULL; - $grade->text = $text; - $grade->rowspan = $attemptcount; - } - - $data = array(); - if ($is_html) { - if ($attemptcount>1) { - $text = $picture; - $picture = NULL; - $picture->text = $text; - $picture->rowspan = $attemptcount; - } - $data[] = $picture; - } - array_push($data, $name, $grade); - - foreach ($user->attempts as $attempt) { - - // set flag if this is best grade - $is_best_grade = ($is_html && $attempt->score==$user->grade); - - // get attempt number - $attemptnumber= $attempt->attempt; - if ($is_html && $allow_review) { - $attemptnumber = ''.$attemptnumber.''; - } - if ($is_best_grade) { - $score = ''.$attemptnumber.''; - } - $data[] = $attemptnumber; - - // get responses to questions in this attempt by this user - foreach ($questions as $id=>$question) { - if (!isset($q[$id])) { - $q[$id] = array('count'=>0, 'total'=>0); - } - - if (isset($attempt->responses[$id])) { - $score = $attempt->responses[$id]->score; - if (is_numeric($score)) { - $q[$id]['count'] ++; - $q[$id]['total'] += $score; - - if ($is_best_grade) { - $score = ''.$score.''; - } - } else if (empty($score)) { - $score = $no_value; - } - } else { - $score = $no_value; - } - - $data[] = $score; - } // foreach $questions - - if (isset($attempt->penalties)) { - $penalties = $attempt->penalties; - if (is_numeric($penalties)) { - $q['penalties']['count'] ++; - $q['penalties']['total'] += $penalties; - } - if ($is_best_grade) { - $penalties = ''.$penalties.''; - } - } else { - $penalties = $no_value; - } - $data[] = $penalties; - - if (isset($attempt->score)) { - $score = $attempt->score; - if (is_numeric($score)) { - $q['score']['total'] += $score; - $q['score']['count'] ++; - } - if ($is_best_grade) { - $score = ''.$score.''; - } - } else { - $score = $no_value; - } - - $data[] = $score; - - // append data for this attempt - $table->data[] = $data; - - // reset data array for next attempt, if any - $data = array(); - - } // end foreach $attempt - - $table->data[] = 'hr'; - } // end foreach $user - - // remove final 'hr' from data rows - array_pop($table->data); - - // add averages to foot of table - $averages = array(); - if ($is_html) { - $averages[] = $blank; - } - array_push($averages, get_string('average', 'hotpot')); - - $col = count($averages); - - if (empty($q['grade']['count'])) { - // remove score $col from $table - $this->remove_column($table, $col); - } else { - $precision = ($hotpot->grademethod==HOTPOT_GRADEMETHOD_AVERAGE || $hotpot->grade<100) ? 1 : 0; - $averages[] = round($q['grade']['total'] / $q['grade']['count'], $precision); - $col++; - } - - // skip the attempt number column - $averages[$col++] = $blank; - - foreach ($questions as $id=>$question) { - if (empty($q[$id]['count'])) { - // remove this question $col from $table - $this->remove_column($table, $col); - } else { - $averages[$col++] = round($q[$id]['total'] / $q[$id]['count']); - } - } - if (empty($q['penalties']['count'])) { - // remove penalties $col from $table - $this->remove_column($table, $col); - } else { - $averages[$col++] = round($q['penalties']['total'] / $q['penalties']['count']); - } - if (empty($q['score']['count'])) { - // remove score $col from $table - $this->remove_column($table, $col); - } else { - $averages[$col++] = round($q['score']['total'] / $q['score']['count']); - } - $table->foot = array($averages); - - $tables[] = &$table; - } - -} // end class -?> +create_scores_table($hotpot, $course, $users, $attempts, $questions, $options, $tables); + $this->print_report($course, $hotpot, $tables, $options); + return true; + } + function create_scores_table(&$hotpot, &$course, &$users, &$attempts, &$questions, &$options, &$tables) { + global $CFG; + $download = ($options['reportformat']=='htm') ? false : true; + $is_html = ($options['reportformat']=='htm'); + $blank = ($download ? '' : ' '); + $no_value = ($download ? '' : '-'); + $allow_review = true; // ($options['reportformat']=='htm' && (isteacher($course->id) || $hotpot->review)); + // start the table + unset($table); + $table->border = 1; + $table->head = array(); + $table->align = array(); + $table->size = array(); + // picture column, if required + if ($is_html) { + $table->head[] = ' '; + $table->align[] = 'center'; + $table->size[] = 10; + } + // name, grade and attempt number + array_push($table->head, + get_string("name"), + hotpot_grade_heading($hotpot, $options), + get_string("attempt", "quiz") + ); + array_push($table->align, "left", "center", "center"); + array_push($table->size, '', '', ''); + // question headings + $this->add_question_headings($questions, $table); + // penalties and raw score + array_push($table->head, + get_string('penalties', 'hotpot'), + get_string('score', 'quiz') + ); + array_push($table->align, "center", "center"); + array_push($table->size, '', ''); + $table->data = array(); + $q = array( + 'grade' => array('count'=>0, 'total'=>0), + 'penalties' => array('count'=>0, 'total'=>0), + 'score' => array('count'=>0, 'total'=>0), + ); + foreach ($users as $user) { + // shortcut to user info held in first attempt record + $u = &$user->attempts[0]; + $picture = ''; + $name = fullname($u); + if ($is_html) { + $picture = print_user_picture($u->userid, $course->id, $u->picture, false, true); + $name = ''.$name.''; + } + if (isset($user->grade)) { + $grade = $user->grade; + $q['grade']['count'] ++; + if (is_numeric($grade)) { + $q['grade']['total'] += $grade; + } + } else { + $grade = $no_value; + } + $attemptcount = count($user->attempts); + if ($attemptcount>1) { + $text = $name; + $name = NULL; + $name->text = $text; + $name->rowspan = $attemptcount; + $text = $grade; + $grade = NULL; + $grade->text = $text; + $grade->rowspan = $attemptcount; + } + $data = array(); + if ($is_html) { + if ($attemptcount>1) { + $text = $picture; + $picture = NULL; + $picture->text = $text; + $picture->rowspan = $attemptcount; + } + $data[] = $picture; + } + array_push($data, $name, $grade); + foreach ($user->attempts as $attempt) { + // set flag if this is best grade + $is_best_grade = ($is_html && $attempt->score==$user->grade); + // get attempt number + $attemptnumber= $attempt->attempt; + if ($is_html && $allow_review) { + $attemptnumber = ''.$attemptnumber.''; + } + if ($is_best_grade) { + $score = ''.$attemptnumber.''; + } + $data[] = $attemptnumber; + // get responses to questions in this attempt by this user + foreach ($questions as $id=>$question) { + if (!isset($q[$id])) { + $q[$id] = array('count'=>0, 'total'=>0); + } + if (isset($attempt->responses[$id])) { + $score = $attempt->responses[$id]->score; + if (is_numeric($score)) { + $q[$id]['count'] ++; + $q[$id]['total'] += $score; + if ($is_best_grade) { + $score = ''.$score.''; + } + } else if (empty($score)) { + $score = $no_value; + } + } else { + $score = $no_value; + } + $data[] = $score; + } // foreach $questions + if (isset($attempt->penalties)) { + $penalties = $attempt->penalties; + if (is_numeric($penalties)) { + $q['penalties']['count'] ++; + $q['penalties']['total'] += $penalties; + } + if ($is_best_grade) { + $penalties = ''.$penalties.''; + } + } else { + $penalties = $no_value; + } + $data[] = $penalties; + if (isset($attempt->score)) { + $score = $attempt->score; + if (is_numeric($score)) { + $q['score']['total'] += $score; + $q['score']['count'] ++; + } + if ($is_best_grade) { + $score = ''.$score.''; + } + } else { + $score = $no_value; + } + $data[] = $score; + // append data for this attempt + $table->data[] = $data; + // reset data array for next attempt, if any + $data = array(); + } // end foreach $attempt + $table->data[] = 'hr'; + } // end foreach $user + // remove final 'hr' from data rows + array_pop($table->data); + // add averages to foot of table + $averages = array(); + if ($is_html) { + $averages[] = $blank; + } + array_push($averages, get_string('average', 'hotpot')); + $col = count($averages); + if (empty($q['grade']['count'])) { + // remove score $col from $table + $this->remove_column($table, $col); + } else { + $precision = ($hotpot->grademethod==HOTPOT_GRADEMETHOD_AVERAGE || $hotpot->grade<100) ? 1 : 0; + $averages[] = round($q['grade']['total'] / $q['grade']['count'], $precision); + $col++; + } + // skip the attempt number column + $averages[$col++] = $blank; + foreach ($questions as $id=>$question) { + if (empty($q[$id]['count'])) { + // remove this question $col from $table + $this->remove_column($table, $col); + } else { + $averages[$col++] = round($q[$id]['total'] / $q[$id]['count']); + } + } + if (empty($q['penalties']['count'])) { + // remove penalties $col from $table + $this->remove_column($table, $col); + } else { + $averages[$col++] = round($q['penalties']['total'] / $q['penalties']['count']); + } + if (empty($q['score']['count'])) { + // remove score $col from $table + $this->remove_column($table, $col); + } else { + $averages[$col++] = round($q['score']['total'] / $q['score']['count']); + } + $table->foot = array($averages); + $tables[] = &$table; + } +} // end class +?> diff --git a/mod/hotpot/restorelib.php b/mod/hotpot/restorelib.php index 800fa549658..03b0160c785 100644 --- a/mod/hotpot/restorelib.php +++ b/mod/hotpot/restorelib.php @@ -1,463 +1,399 @@ -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 - // - //----------------------------------------------------------- - -require_once ("$CFG->dirroot/mod/hotpot/lib.php"); - -//This function restores a single hotpot activity -function hotpot_restore_mods($mod, $restore) { - - // this function is called by "restore_create_modules" (in "backup/restorelib.php") - // which is called by "backup/restore_execute.html" (included by "backup/restore.php") - - // $mod is an object - // id : id field in 'modtype' table - // modtype : 'hotpot' - - // $restore is an object - // backup_unique_code : xxxxxxxxxx - // file : '/full/path/to/backupfile.zip' - // mods : an array of $modinfo's (see below) - // restoreto : 0=existing course (replace), 1=existing course (append), 2=new course - // users : 0=all, 1=course, 2=none - // logs : 0=no, 1=yes - // user_files : 0=no, 1=yes - // course_files : 0=no, 1=yes - // course_id : id of course into which data is to be restored - // deleting : true if 'restoreto'==0, otherwise false - // original_wwwroot : 'http://your.server.com/moodle' - - // $modinfo is an array - // 'modname' : array( 'restore'=> 0=no 1=yes, 'userinfo' => 0=no 1=yes) - - $status = true; - - // get course module data this hotpot activity - $data = backup_getid($restore->backup_unique_code, 'hotpot', $mod->id); - if ($data) { - - // $data is an object - // backup_code => xxxxxxxxxx, - // table_name => 'hotpot', - // old_id => xxx, - // new_id => NULL, - // info => xml tree array of info backed up for this hotpot activity - - $xml = &$data->info['MOD']['#']; - $table = 'hotpot'; - $foreign_keys = array('course' => $restore->course_id); - - $more_restore = ''; - - // print a message after each hotpot is backed up - $more_restore .= 'print "
  • ".get_string("modulename", "hotpot")." "".$record->name.""
  • ";'; - $more_restore .= 'backup_flush(300);'; - - if ($restore->mods['hotpot']->userinfo) { - if (isset($xml["STRING_DATA"]) && isset($xml["QUESTION_DATA"])) { - // HotPot v2.1+ - $more_restore .= '$status = hotpot_restore_strings($restore, $status, $xml, $record);'; - $more_restore .= '$status = hotpot_restore_questions($restore, $status, $xml, $record);'; - $more_restore .= '$status = hotpot_restore_attempts($restore, $status, $xml, $record);'; - } else { - // HotPot v2.0.x (regenerate questions, responses and strings from attempt details) - $more_restore .= '$status = hotpot_restore_attempts($restore, $status, $xml, $record, true);'; - } - } - - $status = hotpot_restore_records( - $restore, $status, $xml, $table, $foreign_keys, $more_restore - ); - } - return $status; -} -function hotpot_restore_strings(&$restore, $status, &$xml, &$record) { - // $xml is an XML tree for a hotpot record - // $record is the newly added hotpot record - - return hotpot_restore_records( - $restore, $status, $xml, 'hotpot_strings', array(), '', 'STRING_DATA', 'STRING', 'string' - ); -} -function hotpot_restore_questions(&$restore, $status, &$xml, &$record) { - // $xml is an XML tree for a hotpot record - // $record is the newly added hotpot record - - $foreignkeys = array( - 'hotpot'=>$record->id, - 'text'=>'hotpot_strings' - ); - - return hotpot_restore_records( - $restore, $status, $xml, 'hotpot_questions', $foreignkeys, '', 'QUESTION_DATA', 'QUESTION' - ); -} -function hotpot_restore_attempts(&$restore, $status, &$xml, &$record, $hotpot_v20=false) { - // $xml is an XML tree for a hotpot record - // $record is the newly added hotpot record - - $foreignkeys = array( - 'userid'=>'user', - 'hotpot'=>$record->id, - ); - - $more_restore = ''; - $more_restore .= 'hotpot_restore_details($restore, $status, $xml, $record);'; - if ($hotpot_v20) { - // HotPot v2.0.x (regenerate questions and responses from details) - $more_restore .= '$record->details=stripslashes($record->details);'; - $more_restore .= 'hotpot_add_attempt_details($record);'; // see "hotpot/lib.php" - } else { - // HotPot v2.1+ - $more_restore .= '$status = hotpot_restore_responses($restore, $status, $xml, $record);'; - - // save clickreportid (to be updated it later) - $more_restore .= 'if (!empty($record->clickreportid)) {'; - $more_restore .= '$GLOBALS["hotpot_backup_clickreportids"][$record->id]=$record->clickreportid;'; - $more_restore .= '}'; - - // initialize global array to store clickreportids - $GLOBALS["hotpot_backup_clickreportids"] = array(); - } - - - $status = hotpot_restore_records( - $restore, $status, $xml, 'hotpot_attempts', $foreignkeys, $more_restore, 'ATTEMPT_DATA', 'ATTEMPT' - ); - - if ($hotpot_v20) { - if ($status) { - global $CFG; - // based on code in "mod/hotpot/db/update_to_v2.php" - execute_sql("UPDATE {$CFG->prefix}hotpot_attempts SET status=1 WHERE hotpot=$record->id AND timefinish=0 AND score IS NULL", false); - execute_sql("UPDATE {$CFG->prefix}hotpot_attempts SET status=3 WHERE hotpot=$record->id AND timefinish>0 AND score IS NULL", false); - execute_sql("UPDATE {$CFG->prefix}hotpot_attempts SET status=4 WHERE hotpot=$record->id AND timefinish>0 AND score IS NOT NULL", false); - execute_sql("UPDATE {$CFG->prefix}hotpot_attempts SET clickreportid=id WHERE hotpot=$record->id AND clickreportid IS NULL", false); - } - } else { - $status = hotpot_restore_clickreportids($restore, $status); - unset($GLOBALS["hotpot_backup_clickreportids"]); // tidy up - } - - return $status; -} -function hotpot_restore_clickreportids(&$restore, $status) { - // update clickreport ids, if any - global $CFG; - foreach ($GLOBALS["hotpot_backup_clickreportids"] as $id=>$clickreportid) { - if ($status) { - $attempt_record = backup_getid($restore->backup_unique_code, 'hotpot_attempts', $clickreportid); - if ($attempt_record) { - $new_clickreportid = $attempt_record->new_id; - $status = execute_sql("UPDATE {$CFG->prefix}hotpot_attempts SET clickreportid=$new_clickreportid WHERE id=$id", false); - } else { - // New clickreport id could not be found - print "
    • New clickreportid could not be found: attempt id=$id, clickreportid=$clickreportid
    "; - $status = false; - } - } - } - return $status; -} -function hotpot_restore_responses(&$restore, $status, &$xml, &$record) { - // $xml is an XML tree for an attempt record - // $record is the newly added attempt record - - $foreignkeys = array( - 'attempt'=>$record->id, - 'question'=>'hotpot_questions', - 'correct'=>'hotpot_strings', - 'wrong'=>'hotpot_strings', - 'ignored'=>'hotpot_strings' - ); - - return hotpot_restore_records( - $restore, $status, $xml, 'hotpot_responses', $foreignkeys, '', 'RESPONSE_DATA', 'RESPONSE' - ); -} -function hotpot_restore_details(&$restore, $status, &$xml, &$record) { - // $xml is an XML tree for an attempt record - // $record is the newly added attempt record - - if (empty($record->details)) { - $status = true; - } else { - unset($details); - $details->attempt = $record->id; - $details->details = $record->details; - - if (insert_record('hotpot_details', $details)) { - $status = true; - } else { - print "
    • Details record could not be updated: attempt=$record->attempt
    "; - $status = false; - } - } - return $status; -} -function hotpot_restore_records(&$restore, $status, &$xml, $table, $foreign_keys, $more_restore='', $records_TAG='', $record_TAG='', $secondary_key='') { -// general purpose function to restore a group of records - - // $restore : (see "hotpot_restore_mods" above) - - // $xml : an XML tree (or sub-tree) - - // $records_TAG : (optional) the name of an XML tag which starts a block of records - // If no $records_TAG is specified, $xml is assumed to be a block of records - - // $record_TAG : (optional) the name of an XML tag which starts a single record - // If no $record_TAG is specified, the block of records is assumed to be a single record - - // other parameters are explained in "hotpot_restore_record" below - - $i = 0; - do { - unset($xml_records); - if ($records_TAG) { - if (isset($xml[$records_TAG][$i]['#'])) { - $xml_records = &$xml[$records_TAG][$i]['#']; - } - } else { - if ($i==0) { - $xml_records = &$xml; - } - } - if (empty($xml_records)) { - // do nothing - } else { - $ii = 0; - do { - unset($xml_record); - if ($record_TAG) { - if (isset($xml_records[$record_TAG][$ii]['#'])) { - $xml_record = &$xml_records[$record_TAG][$ii]['#']; - } - } else { - if ($ii==0) { - $xml_record = &$xml_records; - } - } - if (empty($xml_record)) { - // do nothing - } else { - $status = hotpot_restore_record( - $restore, $status, $xml_record, $table, $foreign_keys, $more_restore, $secondary_key - ); - } - $ii++; - } while ($status && isset($xml_record)); - } - $i++; - } while ($status && isset($xml_records)); - - return $status; -} -function hotpot_restore_record(&$restore, $status, &$xml, $table, $foreign_keys, $more_restore, $secondary_key) { -// general purpose function to restore a single record - - // $restore : (see "hotpot_restore_mods" above) - - // $status : current status of backup (true or false) - // $xml : XML tree of current record - // $table : name of Moodle database table to restore to - - // $foreign_keys : array of foreign keys, if any, specifed as $key=>$value - // $key : the name of a field in the current $record - // $value : if $value is numeric, then $record->$key is set to $value. - // Otherwise $value is assumed to be a table name and $record->$key - // is treated as a comma separated list of ids in that table - - // $more_restore : optional PHP code to be eval(uated) for each record - - // $secondary_key : - // the name of the secondary key field, if any, in the current $record. - // If this field is specified, then the current record will only be added - // if the $record->$secondarykey value does not already exist in $table - - unset($record); - - $TAGS = array_keys($xml); - foreach ($TAGS as $TAG) { - - $value = $xml[$TAG][0]['#']; - if (is_string($value)) { - - $tag = strtolower($TAG); - $record->$tag = backup_todb($value); - } - } - - foreach ($foreign_keys as $key=>$value) { - if (is_numeric($value)) { - $record->$key = $value; - } else { - if (empty($record->$key)) { - $record->$key = NULL; - } else { - $key_table = $value; - $new_ids = array(); - $old_ids = explode(',', $record->$key); - foreach ($old_ids as $old_id) { - $key_record = backup_getid($restore->backup_unique_code, $key_table, $old_id); - if ($key_record) { - $new_ids[] = $key_record->new_id; - } else { - // foreign key could not be updated - print "
    • Foreign key could not be updated: table=$table, $key=".$record->$key."
    "; - $status = false; - } - } - $record->$key = implode(',', $new_ids); - } - } - } - - // check everything is OK so far - if ($status && isset($record)) { - - // store old record id, if necessary - if (isset($record->id)) { - $record->old_id = $record->id; - unset($record->id); - } - - // if there is a secondary key field ... - if ($secondary_key) { - // check to see if a record with the same value already exists - $key_record = get_record($table, $secondary_key, $record->$secondary_key); - if ($key_record) { - // set new record id from already existing record - $record->id = $key_record->id; - } - } - - if (empty($record->id)) { - // add the $record (and get new id) - $record->id = insert_record ($table, $record); - } - - // check $record was added (or found) - if (is_numeric($record->id)) { - - // if there was an old id, save a mapping to the new id - if (isset($record->old_id)) { - backup_putid($restore->backup_unique_code, $table, $record->old_id, $record->id); - } - } else { - // failed to add (or find) $record - print "
    • Record could not be added: table=$table
    "; - $status = false; - } - - // restore related records, if required - if ($more_restore) { - eval($more_restore); - } - } - return $status; -} - -//This function returns a log record with all the necessay transformations -//done. It's used by restore_log_module() to restore modules log. -function hotpot_restore_logs($restore, $log) { - - // assume the worst - $status = false; - - switch ($log->action) { - - case "add": - case "update": - case "view": - if ($log->cmid) { - //Get the new_id of the module (to recode the info field) - $mod = backup_getid($restore->backup_unique_code, $log->module, $log->info); - if ($mod) { - $log->url = "view.php?id=".$log->cmid; - $log->info = $mod->new_id; - $status = true; - } - } - break; - - case "view all": - $log->url = "index.php?id=".$log->course; - $status = true; - break; - - case "report": - if ($log->cmid) { - //Get the new_id of the module (to recode the info field) - $mod = backup_getid($restore->backup_unique_code,$log->module,$log->info); - if ($mod) { - $log->url = "report.php?id=".$log->cmid; - $log->info = $mod->new_id; - $status = true; - } - } - break; - - case "attempt": - case "submit": - case "review": - if ($log->cmid) { - //Get the new_id of the module (to recode the info field) - $mod = backup_getid($restore->backup_unique_code,$log->module,$log->info); - if ($mod) { - //Extract the attempt id from the url field - $attemptid = substr(strrchr($log->url,"="),1); - //Get the new_id of the attempt (to recode the url field) - $attempt = backup_getid($restore->backup_unique_code,"hotpot_attempts",$attemptid); - if ($attempt) { - $log->url = "review.php?id=".$log->cmid."&attempt=".$attempt->new_id; - $log->info = $mod->new_id; - $status = true; - } - } - } - break; - - default: - // Oops, unknown $log->action - print "

    action (".$log->module."-".$log->action.") unknown. Not restored

    "; - break; - - } // end switch - - return $status ? $log : false; -} -?> +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 + // + //----------------------------------------------------------- +require_once ("$CFG->dirroot/mod/hotpot/lib.php"); +//This function restores a single hotpot activity +function hotpot_restore_mods($mod, $restore) { + // this function is called by "restore_create_modules" (in "backup/restorelib.php") + // which is called by "backup/restore_execute.html" (included by "backup/restore.php") + // $mod is an object + // id : id field in 'modtype' table + // modtype : 'hotpot' + // $restore is an object + // backup_unique_code : xxxxxxxxxx + // file : '/full/path/to/backupfile.zip' + // mods : an array of $modinfo's (see below) + // restoreto : 0=existing course (replace), 1=existing course (append), 2=new course + // users : 0=all, 1=course, 2=none + // logs : 0=no, 1=yes + // user_files : 0=no, 1=yes + // course_files : 0=no, 1=yes + // course_id : id of course into which data is to be restored + // deleting : true if 'restoreto'==0, otherwise false + // original_wwwroot : 'http://your.server.com/moodle' + // $modinfo is an array + // 'modname' : array( 'restore'=> 0=no 1=yes, 'userinfo' => 0=no 1=yes) + $status = true; + // get course module data this hotpot activity + $data = backup_getid($restore->backup_unique_code, 'hotpot', $mod->id); + if ($data) { + // $data is an object + // backup_code => xxxxxxxxxx, + // table_name => 'hotpot', + // old_id => xxx, + // new_id => NULL, + // info => xml tree array of info backed up for this hotpot activity + $xml = &$data->info['MOD']['#']; + $table = 'hotpot'; + $foreign_keys = array('course' => $restore->course_id); + $more_restore = ''; + // print a message after each hotpot is backed up + $more_restore .= 'print "
  • ".get_string("modulename", "hotpot")." "".$record->name.""
  • ";'; + $more_restore .= 'backup_flush(300);'; + if ($restore->mods['hotpot']->userinfo) { + if (isset($xml["STRING_DATA"]) && isset($xml["QUESTION_DATA"])) { + // HotPot v2.1+ + $more_restore .= '$status = hotpot_restore_strings($restore, $status, $xml, $record);'; + $more_restore .= '$status = hotpot_restore_questions($restore, $status, $xml, $record);'; + $more_restore .= '$status = hotpot_restore_attempts($restore, $status, $xml, $record);'; + } else { + // HotPot v2.0.x (regenerate questions, responses and strings from attempt details) + $more_restore .= '$status = hotpot_restore_attempts($restore, $status, $xml, $record, true);'; + } + } + $status = hotpot_restore_records( + $restore, $status, $xml, $table, $foreign_keys, $more_restore + ); + } + return $status; +} +function hotpot_restore_strings(&$restore, $status, &$xml, &$record) { + // $xml is an XML tree for a hotpot record + // $record is the newly added hotpot record + return hotpot_restore_records( + $restore, $status, $xml, 'hotpot_strings', array(), '', 'STRING_DATA', 'STRING', 'string' + ); +} +function hotpot_restore_questions(&$restore, $status, &$xml, &$record) { + // $xml is an XML tree for a hotpot record + // $record is the newly added hotpot record + $foreignkeys = array( + 'hotpot'=>$record->id, + 'text'=>'hotpot_strings' + ); + return hotpot_restore_records( + $restore, $status, $xml, 'hotpot_questions', $foreignkeys, '', 'QUESTION_DATA', 'QUESTION' + ); +} +function hotpot_restore_attempts(&$restore, $status, &$xml, &$record, $hotpot_v20=false) { + // $xml is an XML tree for a hotpot record + // $record is the newly added hotpot record + $foreignkeys = array( + 'userid'=>'user', + 'hotpot'=>$record->id, + ); + $more_restore = ''; + $more_restore .= 'hotpot_restore_details($restore, $status, $xml, $record);'; + if ($hotpot_v20) { + // HotPot v2.0.x (regenerate questions and responses from details) + $more_restore .= '$record->details=stripslashes($record->details);'; + $more_restore .= 'hotpot_add_attempt_details($record);'; // see "hotpot/lib.php" + } else { + // HotPot v2.1+ + $more_restore .= '$status = hotpot_restore_responses($restore, $status, $xml, $record);'; + // save clickreportid (to be updated it later) + $more_restore .= 'if (!empty($record->clickreportid)) {'; + $more_restore .= '$GLOBALS["hotpot_backup_clickreportids"][$record->id]=$record->clickreportid;'; + $more_restore .= '}'; + // initialize global array to store clickreportids + $GLOBALS["hotpot_backup_clickreportids"] = array(); + } + $status = hotpot_restore_records( + $restore, $status, $xml, 'hotpot_attempts', $foreignkeys, $more_restore, 'ATTEMPT_DATA', 'ATTEMPT' + ); + if ($hotpot_v20) { + if ($status) { + global $CFG; + // based on code in "mod/hotpot/db/update_to_v2.php" + execute_sql("UPDATE {$CFG->prefix}hotpot_attempts SET status=1 WHERE hotpot=$record->id AND timefinish=0 AND score IS NULL", false); + execute_sql("UPDATE {$CFG->prefix}hotpot_attempts SET status=3 WHERE hotpot=$record->id AND timefinish>0 AND score IS NULL", false); + execute_sql("UPDATE {$CFG->prefix}hotpot_attempts SET status=4 WHERE hotpot=$record->id AND timefinish>0 AND score IS NOT NULL", false); + execute_sql("UPDATE {$CFG->prefix}hotpot_attempts SET clickreportid=id WHERE hotpot=$record->id AND clickreportid IS NULL", false); + } + } else { + $status = hotpot_restore_clickreportids($restore, $status); + unset($GLOBALS["hotpot_backup_clickreportids"]); // tidy up + } + return $status; +} +function hotpot_restore_clickreportids(&$restore, $status) { + // update clickreport ids, if any + global $CFG; + foreach ($GLOBALS["hotpot_backup_clickreportids"] as $id=>$clickreportid) { + if ($status) { + $attempt_record = backup_getid($restore->backup_unique_code, 'hotpot_attempts', $clickreportid); + if ($attempt_record) { + $new_clickreportid = $attempt_record->new_id; + $status = execute_sql("UPDATE {$CFG->prefix}hotpot_attempts SET clickreportid=$new_clickreportid WHERE id=$id", false); + } else { + // New clickreport id could not be found + print "
    • New clickreportid could not be found: attempt id=$id, clickreportid=$clickreportid
    "; + $status = false; + } + } + } + return $status; +} +function hotpot_restore_responses(&$restore, $status, &$xml, &$record) { + // $xml is an XML tree for an attempt record + // $record is the newly added attempt record + $foreignkeys = array( + 'attempt'=>$record->id, + 'question'=>'hotpot_questions', + 'correct'=>'hotpot_strings', + 'wrong'=>'hotpot_strings', + 'ignored'=>'hotpot_strings' + ); + return hotpot_restore_records( + $restore, $status, $xml, 'hotpot_responses', $foreignkeys, '', 'RESPONSE_DATA', 'RESPONSE' + ); +} +function hotpot_restore_details(&$restore, $status, &$xml, &$record) { + // $xml is an XML tree for an attempt record + // $record is the newly added attempt record + if (empty($record->details)) { + $status = true; + } else { + unset($details); + $details->attempt = $record->id; + $details->details = $record->details; + if (insert_record('hotpot_details', $details)) { + $status = true; + } else { + print "
    • Details record could not be updated: attempt=$record->attempt
    "; + $status = false; + } + } + return $status; +} +function hotpot_restore_records(&$restore, $status, &$xml, $table, $foreign_keys, $more_restore='', $records_TAG='', $record_TAG='', $secondary_key='') { +// general purpose function to restore a group of records + // $restore : (see "hotpot_restore_mods" above) + // $xml : an XML tree (or sub-tree) + // $records_TAG : (optional) the name of an XML tag which starts a block of records + // If no $records_TAG is specified, $xml is assumed to be a block of records + // $record_TAG : (optional) the name of an XML tag which starts a single record + // If no $record_TAG is specified, the block of records is assumed to be a single record + // other parameters are explained in "hotpot_restore_record" below + $i = 0; + do { + unset($xml_records); + if ($records_TAG) { + if (isset($xml[$records_TAG][$i]['#'])) { + $xml_records = &$xml[$records_TAG][$i]['#']; + } + } else { + if ($i==0) { + $xml_records = &$xml; + } + } + if (empty($xml_records)) { + // do nothing + } else { + $ii = 0; + do { + unset($xml_record); + if ($record_TAG) { + if (isset($xml_records[$record_TAG][$ii]['#'])) { + $xml_record = &$xml_records[$record_TAG][$ii]['#']; + } + } else { + if ($ii==0) { + $xml_record = &$xml_records; + } + } + if (empty($xml_record)) { + // do nothing + } else { + $status = hotpot_restore_record( + $restore, $status, $xml_record, $table, $foreign_keys, $more_restore, $secondary_key + ); + } + $ii++; + } while ($status && isset($xml_record)); + } + $i++; + } while ($status && isset($xml_records)); + return $status; +} +function hotpot_restore_record(&$restore, $status, &$xml, $table, $foreign_keys, $more_restore, $secondary_key) { +// general purpose function to restore a single record + // $restore : (see "hotpot_restore_mods" above) + // $status : current status of backup (true or false) + // $xml : XML tree of current record + // $table : name of Moodle database table to restore to + // $foreign_keys : array of foreign keys, if any, specifed as $key=>$value + // $key : the name of a field in the current $record + // $value : if $value is numeric, then $record->$key is set to $value. + // Otherwise $value is assumed to be a table name and $record->$key + // is treated as a comma separated list of ids in that table + // $more_restore : optional PHP code to be eval(uated) for each record + // $secondary_key : + // the name of the secondary key field, if any, in the current $record. + // If this field is specified, then the current record will only be added + // if the $record->$secondarykey value does not already exist in $table + unset($record); + $TAGS = array_keys($xml); + foreach ($TAGS as $TAG) { + $value = $xml[$TAG][0]['#']; + if (is_string($value)) { + $tag = strtolower($TAG); + $record->$tag = backup_todb($value); + } + } + foreach ($foreign_keys as $key=>$value) { + if (is_numeric($value)) { + $record->$key = $value; + } else { + if (empty($record->$key)) { + $record->$key = NULL; + } else { + $key_table = $value; + $new_ids = array(); + $old_ids = explode(',', $record->$key); + foreach ($old_ids as $old_id) { + $key_record = backup_getid($restore->backup_unique_code, $key_table, $old_id); + if ($key_record) { + $new_ids[] = $key_record->new_id; + } else { + // foreign key could not be updated + print "
    • Foreign key could not be updated: table=$table, $key=".$record->$key."
    "; + $status = false; + } + } + $record->$key = implode(',', $new_ids); + } + } + } + // check everything is OK so far + if ($status && isset($record)) { + // store old record id, if necessary + if (isset($record->id)) { + $record->old_id = $record->id; + unset($record->id); + } + // if there is a secondary key field ... + if ($secondary_key) { + // check to see if a record with the same value already exists + $key_record = get_record($table, $secondary_key, $record->$secondary_key); + if ($key_record) { + // set new record id from already existing record + $record->id = $key_record->id; + } + } + if (empty($record->id)) { + // add the $record (and get new id) + $record->id = insert_record ($table, $record); + } + // check $record was added (or found) + if (is_numeric($record->id)) { + // if there was an old id, save a mapping to the new id + if (isset($record->old_id)) { + backup_putid($restore->backup_unique_code, $table, $record->old_id, $record->id); + } + } else { + // failed to add (or find) $record + print "
    • Record could not be added: table=$table
    "; + $status = false; + } + // restore related records, if required + if ($more_restore) { + eval($more_restore); + } + } + return $status; +} +//This function returns a log record with all the necessay transformations +//done. It's used by restore_log_module() to restore modules log. +function hotpot_restore_logs($restore, $log) { + // assume the worst + $status = false; + switch ($log->action) { + case "add": + case "update": + case "view": + if ($log->cmid) { + //Get the new_id of the module (to recode the info field) + $mod = backup_getid($restore->backup_unique_code, $log->module, $log->info); + if ($mod) { + $log->url = "view.php?id=".$log->cmid; + $log->info = $mod->new_id; + $status = true; + } + } + break; + case "view all": + $log->url = "index.php?id=".$log->course; + $status = true; + break; + case "report": + if ($log->cmid) { + //Get the new_id of the module (to recode the info field) + $mod = backup_getid($restore->backup_unique_code,$log->module,$log->info); + if ($mod) { + $log->url = "report.php?id=".$log->cmid; + $log->info = $mod->new_id; + $status = true; + } + } + break; + case "attempt": + case "submit": + case "review": + if ($log->cmid) { + //Get the new_id of the module (to recode the info field) + $mod = backup_getid($restore->backup_unique_code,$log->module,$log->info); + if ($mod) { + //Extract the attempt id from the url field + $attemptid = substr(strrchr($log->url,"="),1); + //Get the new_id of the attempt (to recode the url field) + $attempt = backup_getid($restore->backup_unique_code,"hotpot_attempts",$attemptid); + if ($attempt) { + $log->url = "review.php?id=".$log->cmid."&attempt=".$attempt->new_id; + $log->info = $mod->new_id; + $status = true; + } + } + } + break; + default: + // Oops, unknown $log->action + print "

    action (".$log->module."-".$log->action.") unknown. Not restored

    "; + break; + } // end switch + return $status ? $log : false; +} +?> diff --git a/mod/hotpot/review.php b/mod/hotpot/review.php index dae24a129d8..b4fb7120162 100644 --- a/mod/hotpot/review.php +++ b/mod/hotpot/review.php @@ -1,290 +1,240 @@ -course)) { - error("Course is misconfigured"); - } - if (! $hotpot = get_record("hotpot", "id", $cm->instance)) { - error("Course module is incorrect"); - } - - } else { - if (! $hotpot = get_record("hotpot", "id", $hp)) { - error("Course module is incorrect"); - } - if (! $course = get_record("course", "id", $hotpot->course)) { - error("Course is misconfigured"); - } - if (! $cm = get_coursemodule_from_instance("hotpot", $hotpot->id, $course->id)) { - error("Course Module ID was incorrect"); - } - } - - if (! $attempt = get_record("hotpot_attempts", "id", $attempt)) { - error("Attempt ID was incorrect"); - } - - require_login($course->id); - - if (!isteacher($course->id)) { - if (!$hotpot->review) { - error(get_string("noreview", "quiz")); - } - //if (time() < $hotpot->timeclose) { - // error(get_string("noreviewuntil", "quiz", userdate($hotpot->timeclose))); - //} - if ($attempt->userid != $USER->id) { - error("This is not your attempt!"); - } - } - - add_to_log($course->id, "hotpot", "review", "review.php?id=$cm->id&attempt=$attempt->id", "$hotpot->id", "$cm->id"); - - -// Print the page header - - $strmodulenameplural = get_string("modulenameplural", "hotpot"); - $strmodulename = get_string("modulename", "hotpot"); - - // print header - $title = "$course->shortname: $hotpot->name"; - $heading = "$course->fullname"; - $navigation = "id\">$strmodulenameplural -> ".get_string("review", "quiz"); - if ($course->category) { - $navigation = "id\">$course->shortname -> $navigation"; - } - $button = update_module_button($cm->id, $course->id, $strmodulename); - - print_header($title, $heading, $navigation, "", "", true, $button, navmenu($course, $cm)); - - print ''; // for overlib - - print_heading($hotpot->name); - - hotpot_print_attempt_summary($hotpot, $attempt); - hotpot_print_review_buttons($course, $hotpot, $attempt); - - $action = isteacher($course->id) ? optional_param('action') : ''; - if ($action) { - - $xml = get_field('hotpot_details', 'details', 'attempt', $attempt->id); - - print '
    '; - switch ($action) { - case 'showxmltree': - print '
    ';
    -				$xml_tree = new hotpot_xml_tree($xml, "['hpjsresult']['#']");
    -				print_r ($xml_tree->xml_value('fields'));
    -				print '
    '; - break; - case 'showxmlsource': - print htmlspecialchars($xml); - break; - default: - print "Action '$action' not recognized"; - } - print '
    '; - - } else { - hotpot_print_attempt_details($hotpot, $attempt); - } - hotpot_print_review_buttons($course, $hotpot, $attempt); - - print_footer($course); - -/////////////////////////// -// functions -/////////////////////////// - -function hotpot_print_attempt_summary(&$hotpot, &$attempt) { - // start table - print_simple_box_start("center", "80%", "#ffffff", 0); - print ''."\n"; - - // add attempt properties - $fields = array('attempt', 'score', 'penalties', 'status', 'timetaken', 'timerecorded'); - foreach ($fields as $field) { - switch ($field) { - case 'score': - $value = hotpot_format_score($attempt); - break; - case 'status': - $value = hotpot_format_status($attempt); - break; - case 'timerecorded': - $value = empty($attempt->timefinish) ? '-' : userdate($attempt->timefinish); - break; - case 'timetaken': - $value = empty($attempt->timefinish) ? '-' : format_time($attempt->timefinish - $attempt->timestart); - break; - default: - $value = isset($attempt->$field) ? $attempt->$field : NULL; - } - if (isset($value)) { - switch ($field) { - case 'status': - case 'timerecorded': - $name = get_string('report'.$field, 'hotpot'); - break; - case 'penalties': - $name = get_string('penalties', 'hotpot'); - break; - default: - $name = get_string($field, 'quiz'); - } - print ''; - } - } - - // finish table - print '
    '.$name.':'.$value.'
    '; - print_simple_box_end(); -} -function hotpot_print_review_buttons(&$course, &$hotpot, &$attempt) { - print "\n".''; - print "\n\n".'\n".'\n".'\n\n"; - print '\n"; - print "
    '; - print_single_button("report.php?hp=$hotpot->id", NULL, get_string('continue'), 'post'); - if (isteacher($course->id) && record_exists('hotpot_details', 'attempt', $attempt->id)) { - print "'; - print_single_button("review.php?hp=$hotpot->id&attempt=$attempt->id&action=showxmlsource", NULL, get_string('showxmlsource', 'hotpot'), 'post'); - print "'; - print_single_button("review.php?hp=$hotpot->id&attempt=$attempt->id&action=showxmltree", NULL, get_string('showxmltree', 'hotpot'), 'post'); - $colspan = 3; - } else { - $colspan = 1; - } - print "
    '; - print_spacer(4, 1, false); // height=4, width=1, no
    - print "
    \n"; -} -function hotpot_print_attempt_details(&$hotpot, &$attempt) { - - // define fields to print - $textfields = array('correct', 'ignored', 'wrong'); - $numfields = array('score', 'weighting', 'hints', 'clues', 'checks'); - - $fields = array_merge($textfields, $numfields); - - $q = array(); // questions - $f = array(); // fields - foreach ($fields as $field) { - $name = get_string($field, 'hotpot'); - $f[$field] = array('count'=>0, 'name'=>$name); - } - - // get questions and responses for this attempt - $questions = get_records_select('hotpot_questions', "hotpot='$hotpot->id'", 'id'); - $responses = get_records_select('hotpot_responses', "attempt='$attempt->id'", 'id'); - - if ($questions && $responses) { - foreach ($responses as $response) { - $id = $response->question; - foreach ($fields as $field) { - if (!isset($f[$field])) { - $name = get_string($field, 'hotpot'); - $f[$field] = array('count'=>0, 'name'=>$name); - } - if (isset($response->$field)) { - $f[$field]['count']++; - - if (!isset($q[$id])) { - $name = hotpot_get_question_name($questions[$id]); - $q[$id] = array('name'=>$name); - } - - $q[$id][$field] = $response->$field; - } - } - } - } - - // count the number of columns required in the table - $colspan = 0; - foreach ($numfields as $field) { - if ($f[$field]['count']) { - $colspan += 2; - } - } - $colspan = max(2, $colspan); - - // start table of questions and responses - print_simple_box_start("center", "80%", "#ffffff", 0); - print ''."\n"; - - if (empty($q)) { - print '\n"; - - } else { - - // flag to ensure separators are only printed before the 2nd and subsequent questions - $printseparator = false; - - foreach ($q as $i=>$question) { - - // flag to ensure questions are only printed when there is at least one response - $printedquestion = false; - - // add rows of text fields - foreach ($textfields as $field) { - if (isset($question[$field])) { - $text = hotpot_strings($question[$field]); - if (trim($text)) { - - // print question if necessary - if (!$printedquestion) { - if ($printseparator) { - print ''."\n"; - } - $printseparator = true; - - print ''."\n"; - $printedquestion = true; - } - - // print response - print ''."\n"; - } - } - } - - // add row of numeric fields - print ''; - foreach ($numfields as $field) { - if ($f[$field]['count']) { - - // print question if necessary - if (!$printedquestion) { - print '\n"; - $printedquestion = true; - } - - // print numeric response - $value = isset($question[$field]) ? $question[$field] : '-'; - print ''; - } - } - print "\n"; - - } // foreach $q - } - - // finish table - print "
    '.get_string("noresponses", "hotpot")."
    '.$question['name'].'
    '.$f[$field]['name'].':'.$text.'
    '.$question['name']."
    '.$f[$field]['name'].':'.$value.'
    \n"; - print_simple_box_end(); -} -?> +course)) { + error("Course is misconfigured"); + } + if (! $hotpot = get_record("hotpot", "id", $cm->instance)) { + error("Course module is incorrect"); + } + } else { + if (! $hotpot = get_record("hotpot", "id", $hp)) { + error("Course module is incorrect"); + } + if (! $course = get_record("course", "id", $hotpot->course)) { + error("Course is misconfigured"); + } + if (! $cm = get_coursemodule_from_instance("hotpot", $hotpot->id, $course->id)) { + error("Course Module ID was incorrect"); + } + } + if (! $attempt = get_record("hotpot_attempts", "id", $attempt)) { + error("Attempt ID was incorrect"); + } + require_login($course->id); + if (!isteacher($course->id)) { + if (!$hotpot->review) { + error(get_string("noreview", "quiz")); + } + //if (time() < $hotpot->timeclose) { + // error(get_string("noreviewuntil", "quiz", userdate($hotpot->timeclose))); + //} + if ($attempt->userid != $USER->id) { + error("This is not your attempt!"); + } + } + add_to_log($course->id, "hotpot", "review", "review.php?id=$cm->id&attempt=$attempt->id", "$hotpot->id", "$cm->id"); +// Print the page header + $strmodulenameplural = get_string("modulenameplural", "hotpot"); + $strmodulename = get_string("modulename", "hotpot"); + // print header + $title = "$course->shortname: $hotpot->name"; + $heading = "$course->fullname"; + $navigation = "id\">$strmodulenameplural -> ".get_string("review", "quiz"); + if ($course->category) { + $navigation = "id\">$course->shortname -> $navigation"; + } + $button = update_module_button($cm->id, $course->id, $strmodulename); + print_header($title, $heading, $navigation, "", "", true, $button, navmenu($course, $cm)); + print ''; // for overlib + print_heading($hotpot->name); + hotpot_print_attempt_summary($hotpot, $attempt); + hotpot_print_review_buttons($course, $hotpot, $attempt); + $action = isteacher($course->id) ? optional_param('action') : ''; + if ($action) { + $xml = get_field('hotpot_details', 'details', 'attempt', $attempt->id); + print '
    '; + switch ($action) { + case 'showxmltree': + print '
    ';
    +				$xml_tree = new hotpot_xml_tree($xml, "['hpjsresult']['#']");
    +				print_r ($xml_tree->xml_value('fields'));
    +				print '
    '; + break; + case 'showxmlsource': + print htmlspecialchars($xml); + break; + default: + print "Action '$action' not recognized"; + } + print '
    '; + } else { + hotpot_print_attempt_details($hotpot, $attempt); + } + hotpot_print_review_buttons($course, $hotpot, $attempt); + print_footer($course); +/////////////////////////// +// functions +/////////////////////////// +function hotpot_print_attempt_summary(&$hotpot, &$attempt) { + // start table + print_simple_box_start("center", "80%", "#ffffff", 0); + print ''."\n"; + // add attempt properties + $fields = array('attempt', 'score', 'penalties', 'status', 'timetaken', 'timerecorded'); + foreach ($fields as $field) { + switch ($field) { + case 'score': + $value = hotpot_format_score($attempt); + break; + case 'status': + $value = hotpot_format_status($attempt); + break; + case 'timerecorded': + $value = empty($attempt->timefinish) ? '-' : userdate($attempt->timefinish); + break; + case 'timetaken': + $value = empty($attempt->timefinish) ? '-' : format_time($attempt->timefinish - $attempt->timestart); + break; + default: + $value = isset($attempt->$field) ? $attempt->$field : NULL; + } + if (isset($value)) { + switch ($field) { + case 'status': + case 'timerecorded': + $name = get_string('report'.$field, 'hotpot'); + break; + case 'penalties': + $name = get_string('penalties', 'hotpot'); + break; + default: + $name = get_string($field, 'quiz'); + } + print ''; + } + } + // finish table + print '
    '.$name.':'.$value.'
    '; + print_simple_box_end(); +} +function hotpot_print_review_buttons(&$course, &$hotpot, &$attempt) { + print "\n".''; + print "\n\n".'\n".'\n".'\n\n"; + print '\n"; + print "
    '; + print_single_button("report.php?hp=$hotpot->id", NULL, get_string('continue'), 'post'); + if (isteacher($course->id) && record_exists('hotpot_details', 'attempt', $attempt->id)) { + print "'; + print_single_button("review.php?hp=$hotpot->id&attempt=$attempt->id&action=showxmlsource", NULL, get_string('showxmlsource', 'hotpot'), 'post'); + print "'; + print_single_button("review.php?hp=$hotpot->id&attempt=$attempt->id&action=showxmltree", NULL, get_string('showxmltree', 'hotpot'), 'post'); + $colspan = 3; + } else { + $colspan = 1; + } + print "
    '; + print_spacer(4, 1, false); // height=4, width=1, no
    + print "
    \n"; +} +function hotpot_print_attempt_details(&$hotpot, &$attempt) { + // define fields to print + $textfields = array('correct', 'ignored', 'wrong'); + $numfields = array('score', 'weighting', 'hints', 'clues', 'checks'); + $fields = array_merge($textfields, $numfields); + $q = array(); // questions + $f = array(); // fields + foreach ($fields as $field) { + $name = get_string($field, 'hotpot'); + $f[$field] = array('count'=>0, 'name'=>$name); + } + // get questions and responses for this attempt + $questions = get_records_select('hotpot_questions', "hotpot='$hotpot->id'", 'id'); + $responses = get_records_select('hotpot_responses', "attempt='$attempt->id'", 'id'); + if ($questions && $responses) { + foreach ($responses as $response) { + $id = $response->question; + foreach ($fields as $field) { + if (!isset($f[$field])) { + $name = get_string($field, 'hotpot'); + $f[$field] = array('count'=>0, 'name'=>$name); + } + if (isset($response->$field)) { + $f[$field]['count']++; + if (!isset($q[$id])) { + $name = hotpot_get_question_name($questions[$id]); + $q[$id] = array('name'=>$name); + } + $q[$id][$field] = $response->$field; + } + } + } + } + // count the number of columns required in the table + $colspan = 0; + foreach ($numfields as $field) { + if ($f[$field]['count']) { + $colspan += 2; + } + } + $colspan = max(2, $colspan); + // start table of questions and responses + print_simple_box_start("center", "80%", "#ffffff", 0); + print ''."\n"; + if (empty($q)) { + print '\n"; + } else { + // flag to ensure separators are only printed before the 2nd and subsequent questions + $printseparator = false; + foreach ($q as $i=>$question) { + // flag to ensure questions are only printed when there is at least one response + $printedquestion = false; + // add rows of text fields + foreach ($textfields as $field) { + if (isset($question[$field])) { + $text = hotpot_strings($question[$field]); + if (trim($text)) { + // print question if necessary + if (!$printedquestion) { + if ($printseparator) { + print ''."\n"; + } + $printseparator = true; + print ''."\n"; + $printedquestion = true; + } + // print response + print ''."\n"; + } + } + } + // add row of numeric fields + print ''; + foreach ($numfields as $field) { + if ($f[$field]['count']) { + // print question if necessary + if (!$printedquestion) { + print '\n"; + $printedquestion = true; + } + // print numeric response + $value = isset($question[$field]) ? $question[$field] : '-'; + print ''; + } + } + print "\n"; + } // foreach $q + } + // finish table + print "
    '.get_string("noresponses", "hotpot")."
    '.$question['name'].'
    '.$f[$field]['name'].':'.$text.'
    '.$question['name']."
    '.$f[$field]['name'].':'.$value.'
    \n"; + print_simple_box_end(); +} +?> diff --git a/mod/hotpot/show.php b/mod/hotpot/show.php index 882244a75bd..d5e4867746a 100644 --- a/mod/hotpot/show.php +++ b/mod/hotpot/show.php @@ -1,78 +1,68 @@ -action = required_param('action'); - $params->course = required_param('course'); - $params->reference = required_param('reference'); - - require_login($params->course); - - if (!isteacher($params->course)) { - error("You are not allowed to view this page!"); - } - - if (isadmin()) { - $params->location = optional_param('location', HOTPOT_LOCATION_COURSEFILES); - } else { - $params->location = HOTPOT_LOCATION_COURSEFILES; - } - - $title = get_string($params->action, 'hotpot').': '.$params->reference; - print_header($title, $title); - - hotpot_print_show_links($params->course, $params->location, $params->reference); -?> - -'; - switch ($params->action) { - case 'showxmlsource': - print htmlspecialchars($hp->source); - break; - case 'showxmltree': - print_r($hp->xml); - break; - case 'showhtmlsource': - print htmlspecialchars($hp->html); - break; - case 'showhtmlquiz': - print $hp->html; - break; - } - print ''; - } else { - print_simple_box("Could not open Hot Potatoes XML file", "center", "", "#FFBBBB"); - } - - print_simple_box_end(); - print '
    '; - close_window_button(); -?> +action = required_param('action'); + $params->course = required_param('course'); + $params->reference = required_param('reference'); + require_login($params->course); + if (!isteacher($params->course)) { + error("You are not allowed to view this page!"); + } + if (isadmin()) { + $params->location = optional_param('location', HOTPOT_LOCATION_COURSEFILES); + } else { + $params->location = HOTPOT_LOCATION_COURSEFILES; + } + $title = get_string($params->action, 'hotpot').': '.$params->reference; + print_header($title, $title); + hotpot_print_show_links($params->course, $params->location, $params->reference); +?> + +'; + switch ($params->action) { + case 'showxmlsource': + print htmlspecialchars($hp->source); + break; + case 'showxmltree': + print_r($hp->xml); + break; + case 'showhtmlsource': + print htmlspecialchars($hp->html); + break; + case 'showhtmlquiz': + print $hp->html; + break; + } + print ''; + } else { + print_simple_box("Could not open Hot Potatoes XML file", "center", "", "#FFBBBB"); + } + print_simple_box_end(); + print '
    '; + close_window_button(); +?> diff --git a/mod/hotpot/version.php b/mod/hotpot/version.php index e97e7ab8a71..390cf9d6ca7 100644 --- a/mod/hotpot/version.php +++ b/mod/hotpot/version.php @@ -1,19 +1,15 @@ -version = 2005090705; // release date of this version (see note below) -$module->release = 'v2.1.5'; // human-friendly version name (used in mod/hotpot/lib.php) -$module->cron = 0; // period for cron to check this module (secs) - -// interpretation of YYYYMMDDXY version numbers -// YYYY : year -// MM : month -// DD : day -// X : point release version 1,2,3 etc -// Y : increment between point releases - -?> +version = 2005090705; // release date of this version (see note below) +$module->release = 'v2.1.5'; // human-friendly version name (used in mod/hotpot/lib.php) +$module->cron = 0; // period for cron to check this module (secs) +// interpretation of YYYYMMDDXY version numbers +// YYYY : year +// MM : month +// DD : day +// X : point release version 1,2,3 etc +// Y : increment between point releases +?> diff --git a/mod/hotpot/view.php b/mod/hotpot/view.php index 94386f8856d..303102d03be 100644 --- a/mod/hotpot/view.php +++ b/mod/hotpot/view.php @@ -1,536 +1,455 @@ -course)) { - error("Course is misconfigured"); - } - if (! $hotpot = get_record("hotpot", "id", $cm->instance)) { - error("Course module is incorrect"); - } - - } else { - if (! $hotpot = get_record("hotpot", "id", $hp)) { - error("Course module is incorrect"); - } - if (! $course = get_record("course", "id", $hotpot->course)) { - error("Course is misconfigured"); - } - if (! $cm = get_coursemodule_from_instance("hotpot", $hotpot->id, $course->id)) { - error("Course Module ID was incorrect"); - } - } - - require_login($course->id); - } - - // set nextpage (for error messages) - $nextpage = "$CFG->wwwroot/course/view.php?id=$course->id"; - - // header strings - $title = strip_tags($course->shortname.': '.$hotpot->name); - $heading = "$course->fullname"; - - $target = empty($CFG->framename) ? '' : ' target="'.$CFG->framename.'"'; - $navigation = ''.get_string("modulenameplural", "hotpot")." -> $hotpot->name"; - if ($course->category) { - $navigation = ''.$course->shortname.' -> '.$navigation; - } - - $button = update_module_button($cm->id, $course->id, get_string("modulename", "hotpot").'" style="font-size:0.75em;'); - $loggedinas = ''.user_login_string($course, $USER).''; - - $time = time(); - $hppassword = optional_param('hppassword'); - - if (HOTPOT_FIRST_ATTEMPT && !isteacher($course->id)) { - // check this quiz is available to this student - - // error message, if quiz is unavailable - $error = ''; - - // check quiz is visible - if (!hotpot_is_visible($cm)) { - $error = get_string("activityiscurrentlyhidden"); - - // check network address - } else if ($hotpot->subnet && !address_in_subnet($_SERVER['REMOTE_ADDR'], $hotpot->subnet)) { - $error = get_string("subneterror", "quiz"); - - // check number of attempts - } else if ($hotpot->attempts && $hotpot->attempts <= count_records('hotpot_attempts', 'hotpot', $hotpot->id, 'userid', $USER->id)) { - $error = get_string("nomoreattempts", "quiz"); - - // get password - } else if ($hotpot->password && empty($hppassword)) { - - print_header($title, $heading, $navigation, "", "", true, $button, $loggedinas, false); - print_heading($hotpot->name); - - $boxalign = 'center'; - $boxwidth = 500; - - if (trim(strip_tags($hotpot->summary))) { - print_simple_box_start($boxalign, $boxwidth); - print '
    '.format_text($hotpot->summary)."
    \n"; - print_simple_box_end(); - print "
    \n"; - } - - print '
    '."\n"; - print_simple_box_start($boxalign, $boxwidth); - - print '
    '; - print get_string('requirepasswordmessage', 'quiz').'

    '; - print ''.get_string('password').': '; - print ' '; - print ' '; - print "
    \n"; - - print_simple_box_end(); - print "
    \n"; - - print_footer(); - exit; - - // check password - } else if ($hotpot->password && strcmp($hotpot->password, $hppassword)) { - $error = get_string("passworderror", "quiz"); - $nextpage = "view.php?id=$cm->id"; - - // check quiz is open - } else if ($hotpot->timeopen && $hotpot->timeopen > $time) { - $error = get_string("quiznotavailable", "quiz", userdate($hotpot->timeopen))."
    \n"; - - // check quiz is not closed - } else if ($hotpot->timeclose && $hotpot->timeclose < $time) { - $error = get_string("quizclosed", "quiz", userdate($hotpot->timeclose))."
    \n"; - } - - if ($error) { - print_header($title, $heading, $navigation, "", "", true, $button, $loggedinas, false); - notice($error, $nextpage); - // - // script stops here, if quiz is unavailable to student - // - } - } - - $available_msg = ''; - if (!empty($hotpot->timeclose) && $hotpot->timeclose > $time) { - // quiz is available until 'timeclose' - $available_msg = get_string("quizavailable", "quiz", userdate($hotpot->timeclose))."
    \n"; - } - - - // open and parse the source file - if(!$hp = new hotpot_xml_quiz($hotpot)) { - error("Quiz is unavailable at the moment"); - } - - $get_js = optional_param('js'); - $get_css = optional_param('css'); - $framename = optional_param('framename'); - - // look for (HP5 v5) - $frameset = ''; - $frameset_tags = ''; - if (preg_match_all('|]*)>(.*?)|is', $hp->html, $matches)) { - $last = count($matches[0])-1; - $frameset = $matches[2][$last]; - $frameset_tags = $matches[1][$last]; - } - - // if HTML is being requested ... - if (empty($get_js) && empty($get_css)) { - - if (empty($frameset)) { - // HP v6 - if ($hotpot->navigation==HOTPOT_NAVIGATION_FRAME || $hotpot->navigation==HOTPOT_NAVIGATION_IFRAME) { - $get_html = ($framename=='main') ? true : false; - } else { - $get_html = true; - } - } else { - // HP5 v5 - $get_html = empty($framename) ? true : false; - } - - if ($get_html) { - - if (HOTPOT_FIRST_ATTEMPT) { - add_to_log($course->id, "hotpot", "view", "view.php?id=$cm->id", "$hotpot->id", "$cm->id"); - - $attemptid = hotpot_add_attempt($hotpot->id); - if (! is_numeric($attemptid)) { - error('Could not insert attempt record: '.$db->ErrorMsg); - } - } - - $hp->adjust_media_urls(); - - if (empty($frameset)) { - // HP6 v6 - switch ($hotpot->navigation) { - case HOTPOT_NAVIGATION_BUTTONS: - // do nothing (i.e. leave buttons as they are) - break; - case HOTPOT_NAVIGATION_GIVEUP: - $hp->insert_giveup_form($attemptid, '', ''); - break; - default: - $hp->remove_nav_buttons(); - } - if (isset($hp->real_outputformat) && $hp->real_outputformat==HOTPOT_OUTPUTFORMAT_MOBILE) { - $hp->insert_submission_form($attemptid, '', '', true); - } else { - $hp->insert_submission_form($attemptid, '', ''); - } - - } else { - // HP5 v5 - switch ($hotpot->navigation) { - case HOTPOT_NAVIGATION_BUTTONS: - // convert URLs in nav buttons - break; - case HOTPOT_NAVIGATION_GIVEUP: - // $hp->insert_giveup_form($attemptid, '', ''); - break; - default: - // remove navigation buttons - $hp->html = preg_replace('#NavBar\+=(.*);#', '', $hp->html); - } - $hp->insert_submission_form($attemptid, "var NavBar='", "';"); - } - } - } - - //FEEDBACK = new Array(); - //FEEDBACK[0] = ''; // url of feedback page/script - //FEEDBACK[1] = ''; // array of array('teachername', 'value'); - //FEEDBACK[2] = ''; // 'student name' [formmail only] - //FEEDBACK[3] = ''; // 'student email' [formmail only] - //FEEDBACK[4] = ''; // window width - //FEEDBACK[5] = ''; // window height - //FEEDBACK[6] = ''; // 'Send a message to teacher' [prompt/button text] - //FEEDBACK[7] = ''; // 'Title' - //FEEDBACK[8] = ''; // 'Teacher' - //FEEDBACK[9] = ''; // 'Message' - //FEEDBACK[10] = ''; // 'Close this window' - - $feedback = array(); - switch ($hotpot->studentfeedback) { - - case HOTPOT_FEEDBACK_NONE: - // do nothing - break; - - case HOTPOT_FEEDBACK_WEBPAGE: - if (empty($hotpot->studentfeedbackurl)) { - $hotpot->studentfeedback = HOTPOT_FEEDBACK_NONE; - } else { - $feedback[0] = "'$hotpot->studentfeedbackurl'"; - } - break; - - case HOTPOT_FEEDBACK_FORMMAIL: - $teachers = hotpot_feedback_teachers($course, $hotpot); - if (empty($teachers) || empty($hotpot->studentfeedbackurl)) { - $hotpot->studentfeedback = HOTPOT_FEEDBACK_NONE; - } else { - $feedback[0] = "'$hotpot->studentfeedbackurl'"; - $feedback[1] = $teachers; - $feedback[2] = "'".fullname($USER)."'"; - $feedback[3] = "'".$USER->email."'"; - $feedback[4] = 500; // width - $feedback[5] = 300; // height - } - break; - - case HOTPOT_FEEDBACK_MOODLEFORUM: - $module = get_record('modules', 'name', 'forum'); - $forums = get_records('forum', 'course', "$course->id"); - if (empty($module) || empty($module->visible) || empty($forums)) { - $hotpot->studentfeedback = HOTPOT_FEEDBACK_NONE; - } else { - $feedback[0] = "'$CFG->wwwroot/mod/forum/index.php?id=$course->id'"; - } - break; - - case HOTPOT_FEEDBACK_MOODLEMESSAGING: - $teachers = hotpot_feedback_teachers($course, $hotpot); - if (empty($CFG->messaging) || empty($teachers)) { - $hotpot->studentfeedback = HOTPOT_FEEDBACK_NONE; - } else { - $feedback[0] = "'$CFG->wwwroot/message/discussion.php?id='"; - $feedback[1] = $teachers; - $feedback[4] = 400; // width - $feedback[5] = 500; // height - } - break; - - default: - // do nothing - } - - if ($hotpot->studentfeedback != HOTPOT_FEEDBACK_NONE) { - $feedback[6] = "'Send a message to teacher'"; - $feedback[7] = "'Title'"; - $feedback[8] = "'Teacher'"; - $feedback[9] = "'Message'"; - $feedback[10] = "'Close this window'"; - $js = ''; - foreach ($feedback as $i=>$str) { - $js .= 'FEEDBACK['.$i."] = $str;\n"; - } - $js = '\n"; - $hp->html = preg_replace('||i', "$js", $hp->html, 1); - } - - // insert hot-potatoes.js - $hp->insert_script(HOTPOT_JS); - - // extract first tag - $head = ''; - $pattern = '|]*)>(.*?)|is'; - if (preg_match($pattern, $hp->html, $matches)) { - $head = $matches[2]; - - // remove - $head = preg_replace('|<title[^>]*>(.*?)|is', '', $head); - } - - // extract |is'; - if (preg_match_all($pattern, $head, $matches)) { - $count = count($matches[0]); - for ($i=0; $i<$count; $i++) { - $styles .= $matches[0][$i]."\n"; - $head = str_replace($matches[0][$i], '', $head); - } - } - - // extract |is'; - if (preg_match_all($pattern, $head, $matches)) { - $count = count($matches[0]); - for ($i=0; $i<$count; $i++) { - $scripts .= $matches[0][$i]."\n"; - $head = str_replace($matches[0][$i], '', $head); - } - } - - // extract tags - $body = ''; - $body_tags = ''; - $footer = ''; - - // HP6 and some HP5 (v6 and v4) - if (preg_match('|]*'.'onLoad=(["\'])(.*?)(\\2)'.'[^>]*)'.'>(.*)|is', $hp->html, $matches)) { - - $body = $matches[5]; // contents of first ... block - $body_tags = $matches[1]; - - // workaround to ensure javascript onload routine for quiz is always executed - // $body_tags will only be inserted into the tag - // if it is included in the theme/$CFG->theme/header.html, - // so some old or modified themes may not insert $body_tags - $body .= "" - . '\n" - ; - - $footer = ''.$footer; - - } else if ($frameset) { // HP5 v5 - - switch ($framename) { - case 'top': - print_header($title, $heading, $navigation, "", "", true, $button, $loggedinas); - print $footer; - break; - - default: - // add a HotPot navigation frame at the top of the page - //$rows = empty($CFG->resource_framesize) ? 85 : $CFG->resource_framesize; - //$frameset = "\n\t".''.$frameset; - //$frameset_tags = preg_replace('|rows="(.*?)"|', 'rows="'.$rows.',\\1"', $frameset_tags); - - // put navigation into var NavBar=''; - // add form to TopFrame in "WriteFeedback" function - // OR add form to BottomFrame in "DisplayExercise" function - // submission form: '', '' - // give up form: '', '' - - print "\n"; - print "\n$title\n$styles\n$scripts\n"; - print "$frameset\n"; - print "\n"; - break; - } // end switch $framename - exit; - - // other files (maybe not even a HotPots) - } else if (preg_match('|]*)'.'>(.*)|is', $hp->html, $matches)) { - $body = $matches[2]; - $body_tags = $matches[1]; - } - - // print the quiz to the browser - - if ($get_js) { - print($scripts); - exit; - } - if ($get_css) { - print($styles); - exit; - } - - switch ($hotpot->navigation) { - - case HOTPOT_NAVIGATION_BAR: - //update_module_button($cm->id, $course->id, $strmodulename.'" style="font-size:0.8em') - print_header( - $title, $heading, $navigation, - "", $head.$styles.$scripts, true, $button, - $loggedinas, false, $body_tags - ); - if (!empty($available_msg)) { - notify($available_msg); - } - print $body.$footer; - break; - - case HOTPOT_NAVIGATION_FRAME: - - switch ($framename) { - case 'top': - print_header($title, $heading, $navigation, "", "", true, $button, $loggedinas); - print $footer; - break; - - case 'main': - if (!empty($available_msg)) { - $hp->insert_message('', $available_msg); - } - print $hp->html; - break; - - default: - $rows = empty($CFG->resource_framesize) ? 85 : $CFG->resource_framesize; - print "\n"; - print "$title\n"; - print "\n"; - print "id&framename=top\">\n"; - print "id&framename=main\">\n"; - print "\n"; - print "\n"; - break; - } // end switch $framename - break; - - case HOTPOT_NAVIGATION_IFRAME: - - switch ($framename) { - case 'main'; - print $hp->html; - break; - - default: - $iframe_id = 'hotpot_iframe'; - $body_tags = " onload=\"set_iframe_height('$iframe_id')\""; - - $iframe_js = ''."\n"; - - print_header( - $title, $heading, $navigation, - "", $head.$styles.$scripts.$iframe_js, true, $button, - $loggedinas, false, $body_tags - ); - if (!empty($available_msg)) { - notify($available_msg); - } - print "\n"; - print $footer; - break; - } // end switch $framename - break; - - default: - // HOTPOT_NAVIGATION_BUTTONS - // HOTPOT_NAVIGATION_GIVEUP - // HOTPOT_NAVIGATION_NONE - - if (!empty($available_msg)) { - $hp->insert_message('', $available_msg); - } - print($hp->html); - } - -/////////////////////////////////// -/// functions -/////////////////////////////////// - -function hotpot_feedback_teachers(&$course, &$hotpot) { - global $CFG; - $teachers = get_records_sql(" - SELECT - u.* - FROM - {$CFG->prefix}user AS u, - {$CFG->prefix}user_teachers AS t - WHERE - t.userid = u.id - AND t.course = $course->id - "); - - $teacherdetails = ''; - if (!empty($teachers)) { - $details = array(); - foreach ($teachers as $teacher) { - if ($hotpot->studentfeedback==HOTPOT_FEEDBACK_MOODLEMESSAGING) { - $detail = $teacher->id; - } else { - $detail =$teacher->email; - } - $details[] = "new Array('".fullname($teacher)."', '$detail')"; - } - $teacherdetails = 'new Array('.implode(',', $details).");\n"; - } - return $teacherdetails; -} -?> +course)) { + error("Course is misconfigured"); + } + if (! $hotpot = get_record("hotpot", "id", $cm->instance)) { + error("Course module is incorrect"); + } + + } else { + if (! $hotpot = get_record("hotpot", "id", $hp)) { + error("Course module is incorrect"); + } + if (! $course = get_record("course", "id", $hotpot->course)) { + error("Course is misconfigured"); + } + if (! $cm = get_coursemodule_from_instance("hotpot", $hotpot->id, $course->id)) { + error("Course Module ID was incorrect"); + } + } + require_login($course->id); + } + // set nextpage (for error messages) + $nextpage = "$CFG->wwwroot/course/view.php?id=$course->id"; + // header strings + $title = strip_tags($course->shortname.': '.$hotpot->name); + $heading = "$course->fullname"; + $target = empty($CFG->framename) ? '' : ' target="'.$CFG->framename.'"'; + $navigation = ''.get_string("modulenameplural", "hotpot")." -> $hotpot->name"; + if ($course->category) { + $navigation = ''.$course->shortname.' -> '.$navigation; + } + $button = update_module_button($cm->id, $course->id, get_string("modulename", "hotpot").'" style="font-size:0.75em;'); + $loggedinas = ''.user_login_string($course, $USER).''; + $time = time(); + $hppassword = optional_param('hppassword'); + if (HOTPOT_FIRST_ATTEMPT && !isteacher($course->id)) { + // check this quiz is available to this student + // error message, if quiz is unavailable + $error = ''; + // check quiz is visible + if (!hotpot_is_visible($cm)) { + $error = get_string("activityiscurrentlyhidden"); + // check network address + } else if ($hotpot->subnet && !address_in_subnet($_SERVER['REMOTE_ADDR'], $hotpot->subnet)) { + $error = get_string("subneterror", "quiz"); + // check number of attempts + } else if ($hotpot->attempts && $hotpot->attempts <= count_records('hotpot_attempts', 'hotpot', $hotpot->id, 'userid', $USER->id)) { + $error = get_string("nomoreattempts", "quiz"); + // get password + } else if ($hotpot->password && empty($hppassword)) { + print_header($title, $heading, $navigation, "", "", true, $button, $loggedinas, false); + print_heading($hotpot->name); + $boxalign = 'center'; + $boxwidth = 500; + if (trim(strip_tags($hotpot->summary))) { + print_simple_box_start($boxalign, $boxwidth); + print '
    '.format_text($hotpot->summary)."
    \n"; + print_simple_box_end(); + print "
    \n"; + } + print '
    '."\n"; + print_simple_box_start($boxalign, $boxwidth); + print '
    '; + print get_string('requirepasswordmessage', 'quiz').'

    '; + print ''.get_string('password').': '; + print ' '; + print ' '; + print "
    \n"; + print_simple_box_end(); + print "
    \n"; + print_footer(); + exit; + // check password + } else if ($hotpot->password && strcmp($hotpot->password, $hppassword)) { + $error = get_string("passworderror", "quiz"); + $nextpage = "view.php?id=$cm->id"; + // check quiz is open + } else if ($hotpot->timeopen && $hotpot->timeopen > $time) { + $error = get_string("quiznotavailable", "quiz", userdate($hotpot->timeopen))."
    \n"; + // check quiz is not closed + } else if ($hotpot->timeclose && $hotpot->timeclose < $time) { + $error = get_string("quizclosed", "quiz", userdate($hotpot->timeclose))."
    \n"; + } + if ($error) { + print_header($title, $heading, $navigation, "", "", true, $button, $loggedinas, false); + notice($error, $nextpage); + // + // script stops here, if quiz is unavailable to student + // + } + } + $available_msg = ''; + if (!empty($hotpot->timeclose) && $hotpot->timeclose > $time) { + // quiz is available until 'timeclose' + $available_msg = get_string("quizavailable", "quiz", userdate($hotpot->timeclose))."
    \n"; + } + // open and parse the source file + if(!$hp = new hotpot_xml_quiz($hotpot)) { + error("Quiz is unavailable at the moment"); + } + $get_js = optional_param('js'); + $get_css = optional_param('css'); + $framename = optional_param('framename'); + // look for (HP5 v5) + $frameset = ''; + $frameset_tags = ''; + if (preg_match_all('|]*)>(.*?)|is', $hp->html, $matches)) { + $last = count($matches[0])-1; + $frameset = $matches[2][$last]; + $frameset_tags = $matches[1][$last]; + } + // if HTML is being requested ... + if (empty($get_js) && empty($get_css)) { + if (empty($frameset)) { + // HP v6 + if ($hotpot->navigation==HOTPOT_NAVIGATION_FRAME || $hotpot->navigation==HOTPOT_NAVIGATION_IFRAME) { + $get_html = ($framename=='main') ? true : false; + } else { + $get_html = true; + } + } else { + // HP5 v5 + $get_html = empty($framename) ? true : false; + } + if ($get_html) { + + if (HOTPOT_FIRST_ATTEMPT) { + add_to_log($course->id, "hotpot", "view", "view.php?id=$cm->id", "$hotpot->id", "$cm->id"); + + $attemptid = hotpot_add_attempt($hotpot->id); + if (! is_numeric($attemptid)) { + error('Could not insert attempt record: '.$db->ErrorMsg); + } + } + $hp->adjust_media_urls(); + if (empty($frameset)) { + // HP6 v6 + switch ($hotpot->navigation) { + case HOTPOT_NAVIGATION_BUTTONS: + // do nothing (i.e. leave buttons as they are) + break; + case HOTPOT_NAVIGATION_GIVEUP: + $hp->insert_giveup_form($attemptid, '', ''); + break; + default: + $hp->remove_nav_buttons(); + } + if (isset($hp->real_outputformat) && $hp->real_outputformat==HOTPOT_OUTPUTFORMAT_MOBILE) { + $hp->insert_submission_form($attemptid, '', '', true); + } else { + $hp->insert_submission_form($attemptid, '', ''); + } + } else { + // HP5 v5 + switch ($hotpot->navigation) { + case HOTPOT_NAVIGATION_BUTTONS: + // convert URLs in nav buttons + break; + case HOTPOT_NAVIGATION_GIVEUP: + // $hp->insert_giveup_form($attemptid, '', ''); + break; + default: + // remove navigation buttons + $hp->html = preg_replace('#NavBar\+=(.*);#', '', $hp->html); + } + $hp->insert_submission_form($attemptid, "var NavBar='", "';"); + } + } + } + //FEEDBACK = new Array(); + //FEEDBACK[0] = ''; // url of feedback page/script + //FEEDBACK[1] = ''; // array of array('teachername', 'value'); + //FEEDBACK[2] = ''; // 'student name' [formmail only] + //FEEDBACK[3] = ''; // 'student email' [formmail only] + //FEEDBACK[4] = ''; // window width + //FEEDBACK[5] = ''; // window height + //FEEDBACK[6] = ''; // 'Send a message to teacher' [prompt/button text] + //FEEDBACK[7] = ''; // 'Title' + //FEEDBACK[8] = ''; // 'Teacher' + //FEEDBACK[9] = ''; // 'Message' + //FEEDBACK[10] = ''; // 'Close this window' + $feedback = array(); + switch ($hotpot->studentfeedback) { + case HOTPOT_FEEDBACK_NONE: + // do nothing + break; + case HOTPOT_FEEDBACK_WEBPAGE: + if (empty($hotpot->studentfeedbackurl)) { + $hotpot->studentfeedback = HOTPOT_FEEDBACK_NONE; + } else { + $feedback[0] = "'$hotpot->studentfeedbackurl'"; + } + break; + case HOTPOT_FEEDBACK_FORMMAIL: + $teachers = hotpot_feedback_teachers($course, $hotpot); + if (empty($teachers) || empty($hotpot->studentfeedbackurl)) { + $hotpot->studentfeedback = HOTPOT_FEEDBACK_NONE; + } else { + $feedback[0] = "'$hotpot->studentfeedbackurl'"; + $feedback[1] = $teachers; + $feedback[2] = "'".fullname($USER)."'"; + $feedback[3] = "'".$USER->email."'"; + $feedback[4] = 500; // width + $feedback[5] = 300; // height + } + break; + case HOTPOT_FEEDBACK_MOODLEFORUM: + $module = get_record('modules', 'name', 'forum'); + $forums = get_records('forum', 'course', "$course->id"); + if (empty($module) || empty($module->visible) || empty($forums)) { + $hotpot->studentfeedback = HOTPOT_FEEDBACK_NONE; + } else { + $feedback[0] = "'$CFG->wwwroot/mod/forum/index.php?id=$course->id'"; + } + break; + case HOTPOT_FEEDBACK_MOODLEMESSAGING: + $teachers = hotpot_feedback_teachers($course, $hotpot); + if (empty($CFG->messaging) || empty($teachers)) { + $hotpot->studentfeedback = HOTPOT_FEEDBACK_NONE; + } else { + $feedback[0] = "'$CFG->wwwroot/message/discussion.php?id='"; + $feedback[1] = $teachers; + $feedback[4] = 400; // width + $feedback[5] = 500; // height + } + break; + default: + // do nothing + } + if ($hotpot->studentfeedback != HOTPOT_FEEDBACK_NONE) { + $feedback[6] = "'Send a message to teacher'"; + $feedback[7] = "'Title'"; + $feedback[8] = "'Teacher'"; + $feedback[9] = "'Message'"; + $feedback[10] = "'Close this window'"; + $js = ''; + foreach ($feedback as $i=>$str) { + $js .= 'FEEDBACK['.$i."] = $str;\n"; + } + $js = '\n"; + $hp->html = preg_replace('||i', "$js", $hp->html, 1); + } + // insert hot-potatoes.js + $hp->insert_script(HOTPOT_JS); + // extract first tag + $head = ''; + $pattern = '|]*)>(.*?)|is'; + if (preg_match($pattern, $hp->html, $matches)) { + $head = $matches[2]; + // remove + $head = preg_replace('|<title[^>]*>(.*?)|is', '', $head); + } + // extract |is'; + if (preg_match_all($pattern, $head, $matches)) { + $count = count($matches[0]); + for ($i=0; $i<$count; $i++) { + $styles .= $matches[0][$i]."\n"; + $head = str_replace($matches[0][$i], '', $head); + } + } + // extract |is'; + if (preg_match_all($pattern, $head, $matches)) { + $count = count($matches[0]); + for ($i=0; $i<$count; $i++) { + $scripts .= $matches[0][$i]."\n"; + $head = str_replace($matches[0][$i], '', $head); + } + } + // extract tags + $body = ''; + $body_tags = ''; + $footer = ''; + // HP6 and some HP5 (v6 and v4) + if (preg_match('|]*'.'onLoad=(["\'])(.*?)(\\2)'.'[^>]*)'.'>(.*)|is', $hp->html, $matches)) { + $body = $matches[5]; // contents of first ... block + $body_tags = $matches[1]; + // workaround to ensure javascript onload routine for quiz is always executed + // $body_tags will only be inserted into the tag + // if it is included in the theme/$CFG->theme/header.html, + // so some old or modified themes may not insert $body_tags + $body .= "" + . '\n" + ; + $footer = ''.$footer; + } else if ($frameset) { // HP5 v5 + switch ($framename) { + case 'top': + print_header($title, $heading, $navigation, "", "", true, $button, $loggedinas); + print $footer; + break; + default: + // add a HotPot navigation frame at the top of the page + //$rows = empty($CFG->resource_framesize) ? 85 : $CFG->resource_framesize; + //$frameset = "\n\t".''.$frameset; + //$frameset_tags = preg_replace('|rows="(.*?)"|', 'rows="'.$rows.',\\1"', $frameset_tags); + // put navigation into var NavBar=''; + // add form to TopFrame in "WriteFeedback" function + // OR add form to BottomFrame in "DisplayExercise" function + // submission form: '', '' + // give up form: '', '' + print "\n"; + print "\n$title\n$styles\n$scripts\n"; + print "$frameset\n"; + print "\n"; + break; + } // end switch $framename + exit; + // other files (maybe not even a HotPots) + } else if (preg_match('|]*)'.'>(.*)|is', $hp->html, $matches)) { + $body = $matches[2]; + $body_tags = $matches[1]; + } + // print the quiz to the browser + if ($get_js) { + print($scripts); + exit; + } + if ($get_css) { + print($styles); + exit; + } + switch ($hotpot->navigation) { + case HOTPOT_NAVIGATION_BAR: + //update_module_button($cm->id, $course->id, $strmodulename.'" style="font-size:0.8em') + print_header( + $title, $heading, $navigation, + "", $head.$styles.$scripts, true, $button, + $loggedinas, false, $body_tags + ); + if (!empty($available_msg)) { + notify($available_msg); + } + print $body.$footer; + break; + case HOTPOT_NAVIGATION_FRAME: + switch ($framename) { + case 'top': + print_header($title, $heading, $navigation, "", "", true, $button, $loggedinas); + print $footer; + break; + case 'main': + if (!empty($available_msg)) { + $hp->insert_message('', $available_msg); + } + print $hp->html; + break; + default: + $rows = empty($CFG->resource_framesize) ? 85 : $CFG->resource_framesize; + print "\n"; + print "$title\n"; + print "\n"; + print "id&framename=top\">\n"; + print "id&framename=main\">\n"; + print "\n"; + print "\n"; + break; + } // end switch $framename + break; + case HOTPOT_NAVIGATION_IFRAME: + switch ($framename) { + case 'main'; + print $hp->html; + break; + default: + $iframe_id = 'hotpot_iframe'; + $body_tags = " onload=\"set_iframe_height('$iframe_id')\""; + $iframe_js = ''."\n"; + print_header( + $title, $heading, $navigation, + "", $head.$styles.$scripts.$iframe_js, true, $button, + $loggedinas, false, $body_tags + ); + if (!empty($available_msg)) { + notify($available_msg); + } + print "\n"; + print $footer; + break; + } // end switch $framename + break; + default: + // HOTPOT_NAVIGATION_BUTTONS + // HOTPOT_NAVIGATION_GIVEUP + // HOTPOT_NAVIGATION_NONE + if (!empty($available_msg)) { + $hp->insert_message('', $available_msg); + } + print($hp->html); + } +/////////////////////////////////// +/// functions +/////////////////////////////////// +function hotpot_feedback_teachers(&$course, &$hotpot) { + global $CFG; + $teachers = get_records_sql(" + SELECT + u.* + FROM + {$CFG->prefix}user AS u, + {$CFG->prefix}user_teachers AS t + WHERE + t.userid = u.id + AND t.course = $course->id + "); + $teacherdetails = ''; + if (!empty($teachers)) { + $details = array(); + foreach ($teachers as $teacher) { + if ($hotpot->studentfeedback==HOTPOT_FEEDBACK_MOODLEMESSAGING) { + $detail = $teacher->id; + } else { + $detail =$teacher->email; + } + $details[] = "new Array('".fullname($teacher)."', '$detail')"; + } + $teacherdetails = 'new Array('.implode(',', $details).");\n"; + } + return $teacherdetails; +} +?>