PageRenderTime 72ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/question/type/imagedit/questiontype.php

https://github.com/nadavkav/RTL-BIDI-Hebrew-Moodle-Plugins
PHP | 350 lines | 194 code | 53 blank | 103 comment | 37 complexity | 32890589788f941dca1a4aa171d0e63e MD5 | raw file
Possible License(s): Apache-2.0, GPL-3.0
  1. <?php
  2. /**
  3. * The question type class for the imagedit question type.
  4. *
  5. * The imagedit question type allows a student to edit a copy of the teacher's image
  6. * as the answer to a question. The file is uploaded to a specific directory inside
  7. * the course's tree. each attempt gets a new image. images are stored in a user's directory
  8. * specified by:
  9. *
  10. * {$CFG->dataroot}/{$_GET['courseid']}/users/{$USER->id}/question{$_GET['qid']}_qatt{$_GET['qatt']}_{$filename}
  11. *
  12. * Once a file has been uploaded, the student can not submit again to replace
  13. * the file, and he/she cannot delete the file.
  14. *
  15. * @author Nadav Kavalerchik
  16. * based on the work of : Adriane Boyd (adrianeboyd@gmail.com) with fileresponse
  17. * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
  18. * @package aab_imagedit
  19. *
  20. */
  21. // include library routines for this question type
  22. //require_once(dirname(__FILE__) . '/locallib.php');
  23. class imagedit_qtype extends default_questiontype {
  24. function name() {
  25. return 'imagedit';
  26. }
  27. function is_manual_graded() {
  28. return true;
  29. }
  30. function is_usable_by_random() {
  31. return false;
  32. }
  33. /**
  34. * Loads the question type specific options for the question.
  35. *
  36. * @return boolean to indicate success or failure
  37. */
  38. function get_question_options(&$question) {
  39. // Get additional information from database
  40. // and attach it to the question object
  41. if (!$question->options = get_record('question_imagedit', 'question', $question->id)) {
  42. notify('Error: Missing question options!');
  43. return false;
  44. }
  45. // Get data from question_answers (for feedback)
  46. parent::get_question_options($question);
  47. return true;
  48. }
  49. /**
  50. * Save the units and the answers associated with this question.
  51. * @return boolean to indicate success or failure.
  52. */
  53. function save_question_options($question) {
  54. // Save question options in question_answers
  55. $result = true;
  56. $update = true;
  57. $answer = get_record("question_answers", "question", $question->id);
  58. if (!$answer) {
  59. $answer = new stdClass;
  60. $answer->question = $question->id;
  61. $update = false;
  62. }
  63. $answer->answer = $question->feedback;
  64. $answer->imgurl = $question->imgurl;
  65. $answer->feedback = $question->feedback;
  66. $answer->fraction = $question->fraction;
  67. if ($update) {
  68. if (!update_record("question_answers", $answer)) {
  69. $result = new stdClass;
  70. $result->error = "Could not update quiz answer!";
  71. }
  72. } else {
  73. if (!$answer->id = insert_record("question_answers", $answer)) {
  74. $result = new stdClass;
  75. $result->error = "Could not insert quiz answer!";
  76. }
  77. }
  78. // If the previous step succeeded, save question options in
  79. // question_imagedit table
  80. if ($result) {
  81. if ($options = get_record("question_imagedit", "question", $question->id)) {
  82. $options->maxbytes = $question->maxbytes;
  83. $options->imgurl = $question->imgurl;
  84. $options->essay = $question->essay;
  85. if (!update_record("question_imagedit", $options)) {
  86. $result = new stdClass;
  87. $result->error = "Could not update quiz imagedit options! (id=$options->id)";
  88. }
  89. } else {
  90. unset($options);
  91. $options->question = $question->id;
  92. $options->maxbytes = $question->maxbytes;
  93. $options->imgurl = $question->imgurl;
  94. $options->essay = $question->essay;
  95. if (!insert_record("question_imagedit", $options)) {
  96. $result = new stdClass;
  97. $result->error = "Could not insert quiz imagedit options!";
  98. }
  99. }
  100. }
  101. return $result;
  102. }
  103. /**
  104. * Deletes question from the question-type specific tables
  105. *
  106. * @param integer $questionid The question being deleted
  107. * @return boolean to indicate success or failure.
  108. */
  109. function delete_question($questionid) {
  110. delete_records("question_imagedit", "question", $questionid);
  111. return true;
  112. }
  113. /**
  114. * Deletes files submitted in these states
  115. *
  116. * @param string $stateslist Comma separated list of state ids to be deleted
  117. * @return boolean to indicate success or failure.
  118. */
  119. function delete_states($stateslist) {
  120. global $CFG;
  121. $states = explode(',', $stateslist);
  122. foreach ($states as $stateid) {
  123. $state = get_record("question_states", "id", "$stateid");
  124. $attemptid = $state->attempt;
  125. $questionid = $state->question;
  126. // delete any files submitted in this attempt
  127. $dir = quiz_file_area_name($attemptid, $questionid);
  128. if (file_exists($CFG->dataroot.'/'.$dir)) {
  129. fulldelete($CFG->dataroot.'/'.$dir);
  130. $dirparts = explode('/', $dir);
  131. // the directory is two levels deep, so delete the lower directory, too
  132. array_pop($dirparts);
  133. $dir = implode('/', $dirparts);
  134. fulldelete($CFG->dataroot.'/'.$dir);
  135. }
  136. }
  137. return true;
  138. }
  139. /**
  140. * Format question display
  141. */
  142. function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) {
  143. global $CFG;
  144. require_once($CFG->libdir.'/formslib.php');
  145. $readonly = empty($options->readonly) ? '' : 'disabled="disabled"';
  146. static $htmleditorused = false;
  147. // Print formulation
  148. $questiontext = $this->format_text($question->questiontext, $question->questiontextformat, $cmoptions);
  149. $image = get_question_image($question);
  150. $maxbytes = $question->options->maxbytes;
  151. //$imgurl = $question->options->imgurl;
  152. $showessay = $question->options->essay;
  153. $answers = &$question->options->answers;
  154. $readonly = empty($options->readonly) ? '' : 'disabled="disabled"';
  155. // Only use the rich text editor for the first essay question on a page.
  156. $usehtmleditor = can_use_html_editor() && !$htmleditorused;
  157. $formatoptions = new stdClass;
  158. $formatoptions->noclean = true;
  159. $formatoptions->para = false;
  160. $inputname = $question->name_prefix;
  161. /// set question text and media
  162. $questiontext = format_text($question->questiontext,
  163. $question->questiontextformat,
  164. $formatoptions, $cmoptions->course);
  165. // feedback handling
  166. $feedback = '';
  167. if ($options->feedback && !empty($answers)) {
  168. foreach ($answers as $answer) {
  169. $feedback = format_text($answer->feedback, '', $formatoptions, $cmoptions->course);
  170. }
  171. }
  172. // get essay response value
  173. if (isset($state->responses[''])) {
  174. $answers = explode(',',$state->responses['']);
  175. $value = stripslashes_safe($answers[0]);
  176. if (!empty($answers[1])) $imgurl = $answers[1]; // get image from the answers array (textarea)
  177. } else {
  178. $value = "";
  179. //$imgurl = null;
  180. }
  181. // essay answer
  182. $answer = '';
  183. if ($showessay) {
  184. if (empty($options->readonly)) {
  185. // the student needs to type in their answer so print out a text editor
  186. $answer = print_textarea($usehtmleditor, 18, 80, 630, 400, $inputname, $value, $cmoptions->course, true);
  187. } else {
  188. // it is read only, so just format the students answer and output it
  189. $safeformatoptions = new stdClass;
  190. $safeformatoptions->para = false;
  191. $answer = format_text($value, FORMAT_MOODLE,
  192. $safeformatoptions, $cmoptions->course);
  193. }
  194. }
  195. // set the file input form
  196. $struploadform = upload_print_form_fragment(1, array($question->name_prefix . "file"), null, false, null, 0, $maxbytes, true);
  197. // set file upload feedback and display of uploaded file
  198. $uploadfeedback = '';
  199. if (isset($state->uploadfeedback)) {
  200. $uploadfeedback = $state->uploadfeedback;
  201. }
  202. // $struploadedfile = '';
  203. // no need to display files. file upload was disabled // (nadavkav)
  204. //$currentfile = get_student_answer($state->attempt, $question->id);
  205. // if (!empty($currentfile)) {
  206. // $struploadedfile = get_string('answer', 'quiz').': '.$currentfile;
  207. // }
  208. // string prompts for form
  209. // if (!empty($currentfile)) {
  210. // $struploadfile = get_string('uploadnew', 'qtype_imagedit');
  211. // } else {
  212. // $struploadfile = get_string('uploadafile');
  213. // }
  214. // $strmaxsize = get_string('maximumupload').' '. display_size($maxbytes);
  215. include("$CFG->dirroot/question/type/imagedit/display.html");
  216. if ($usehtmleditor) {
  217. use_html_editor($inputname);
  218. $htmleditorused = true;
  219. }
  220. }
  221. /**
  222. * Upload the file and prepare for manual grading
  223. */
  224. function grade_responses(&$question, &$state, $cmoptions) {
  225. global $CFG;
  226. $state->raw_grade = 0;
  227. $state->penalty = 0;
  228. // no need for file uploads (it is an image editor question type) // (nadavkav)
  229. //$state->uploadfeedback = imagedit_upload_response($question->name_prefix.'file', $cmoptions->course, $state->attempt, $question->id, $question->options->maxbytes);
  230. $state->responses[''] .= ",".$_POST['imgurl'.$question->id]; // add image to the response array //(nadavkav)
  231. if ($question->options->essay) {
  232. clean_param($state->responses[''], PARAM_CLEANHTML);
  233. }
  234. return true;
  235. }
  236. /**
  237. * Backup the data in the question
  238. *
  239. * This is used in question/backuplib.php
  240. */
  241. function backup($bf, $preferences, $question, $level=6) {
  242. $status = true;
  243. $fileresponses = get_records("question_imagedit", "question", $question, "id ASC");
  244. // If there is a question
  245. if ($fileresponses) {
  246. // Iterate over each
  247. foreach ($fileresponses as $fileresponse) {
  248. $status = $status && fwrite($bf, start_tag("FILERESPONSE", $level, true));
  249. // Print contents
  250. $status = $status && fwrite($bf, full_tag("MAXBYTES", $level+1, false,$fileresponse->maxbytes));
  251. $status = $status && fwrite($bf, full_tag("ESSAY", $level+1, false, $fileresponse->essay));
  252. $status = $status && fwrite($bf, end_tag("FILERESPONSE", $level, true));
  253. }
  254. // Now print question_answers
  255. $status = $status && question_backup_answers($bf, $preferences, $question, $level);
  256. }
  257. return $status;
  258. }
  259. /**
  260. * Restores the data in the question
  261. *
  262. * This is used in question/restorelib.php
  263. */
  264. function restore($oldquestion, $newquestion, $info, $restore) {
  265. $status = true;
  266. // Get the fileresponses array
  267. $fileresponses = $info['#']['FILERESPONSE'];
  268. // Iterate over fileresponses
  269. for($i = 0; $i < sizeof($fileresponses); $i++) {
  270. $frinfo = $fileresponses[$i];
  271. // Now, build the question_fileresponse record structure
  272. $fileresponse = new stdClass;
  273. $fileresponse->question = $newquestion;
  274. $fileresponse->maxbytes = backup_todb($frinfo['#']['MAXBYTES']['0']['#']);
  275. $fileresponse->essay = backup_todb($frinfo['#']['ESSAY']['0']['#']);
  276. // The structure is equal to the db, so insert the question_fileresponse
  277. $newid = insert_record("question_imagedit", $fileresponse);
  278. // Do some output
  279. if (($i+1) % 50 == 0) {
  280. if (!defined('RESTORE_SILENTLY')) {
  281. echo ".";
  282. if (($i+1) % 1000 == 0) {
  283. echo "<br />";
  284. }
  285. }
  286. backup_flush(300);
  287. }
  288. if (!$newid) {
  289. $status = false;
  290. }
  291. }
  292. return $status;
  293. }
  294. }
  295. // Register this question type with the system.
  296. question_register_questiontype(new imagedit_qtype());
  297. ?>