exercise.ajax.php 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819
  1. <?php
  2. /* For licensing terms, see /license.txt */
  3. /**
  4. * Responses to AJAX calls
  5. */
  6. require_once api_get_path(SYS_CODE_PATH).'exercice/exercise.class.php';
  7. require_once api_get_path(SYS_CODE_PATH).'exercice/question.class.php';
  8. require_once api_get_path(SYS_CODE_PATH).'exercice/answer.class.php';
  9. use \ChamiloSession as Session;
  10. api_protect_course_script(true);
  11. $action = $_REQUEST['a'];
  12. $course_id = api_get_course_int_id();
  13. $debug = false;
  14. if ($debug) {
  15. error_log("$action ajax call");
  16. }
  17. $session_id = isset($_REQUEST['session_id']) ? intval($_REQUEST['session_id']) : api_get_session_id();
  18. $course_code = isset($_REQUEST['cidReq']) ? $_REQUEST['cidReq'] : api_get_course_id();
  19. switch ($action) {
  20. case 'get_question_info':
  21. if (api_is_course_admin()) {
  22. $questionId = $_REQUEST['questionId'];
  23. $courseId = api_get_course_int_id();
  24. $question = Question::read($questionId, $courseId);
  25. if (!empty($question)) {
  26. $categoryToString = Testcategory::getCategoryNamesForQuestion($questionId, $courseId, true, false);
  27. $question->category_list = $categoryToString;
  28. echo json_encode($question);
  29. } else {
  30. echo 0;
  31. }
  32. }
  33. break;
  34. case 'get_question':
  35. /** @var Exercise $objExercise */
  36. $objExercise = Session::read('objExercise');
  37. $questionId = $_REQUEST['questionId'];
  38. $attemptList = isset($_REQUEST['attemptList']) ? $_REQUEST['attemptList'] : null;
  39. $remindList = isset($_REQUEST['remindList']) ? $_REQUEST['remindList'] : null;
  40. $i = $_REQUEST['i'];
  41. $current_question = $_REQUEST['current_question'];
  42. $questions_in_media = $_REQUEST['questions_in_media'];
  43. $last_question_in_media = $_REQUEST['last_question_in_media'];
  44. $realQuestionList = isset($_REQUEST['realQuestionList']) ? $_REQUEST['realQuestionList'] : null;
  45. $objExercise->renderQuestion(
  46. $questionId,
  47. $attemptList,
  48. $remindList,
  49. $i,
  50. $current_question,
  51. $questions_in_media,
  52. $last_question_in_media,
  53. $realQuestionList,
  54. false
  55. );
  56. break;
  57. case 'get_categories_by_media':
  58. $questionId = $_REQUEST['questionId'];
  59. $mediaId = $_REQUEST['mediaId'];
  60. $exerciseId = $_REQUEST['exerciseId'];
  61. $question = Question::read($questionId);
  62. if (empty($mediaId)) {
  63. echo 0;
  64. break;
  65. }
  66. $categoryId = $question->allQuestionWithMediaHaveTheSameCategory($exerciseId, $mediaId, null, null, true);
  67. if (!empty($categoryId)) {
  68. $category = new Testcategory($categoryId);
  69. echo json_encode(
  70. array(
  71. 'title' => $category->title,
  72. 'value' => $category->id
  73. )
  74. );
  75. } else {
  76. echo -1;
  77. }
  78. break;
  79. case 'exercise_category_exists':
  80. $type = isset($_REQUEST['type']) ? $_REQUEST['type'] : 'simple';
  81. $category = new Testcategory(null, null, null, null, $type);
  82. $category->getCategory($_REQUEST['id']);
  83. if (empty($category->id)) {
  84. echo 0;
  85. } else {
  86. if (isset($course_id)) {
  87. // Global
  88. if ($category->c_id == 0) {
  89. echo 1;
  90. exit;
  91. } else {
  92. // Local
  93. if ($category->c_id == $course_id) {
  94. echo 1;
  95. exit;
  96. }
  97. }
  98. } else {
  99. echo 0;
  100. exit;
  101. }
  102. }
  103. break;
  104. case 'search_category_parent':
  105. $type = isset($_REQUEST['type']) ? $_REQUEST['type'] : 'simple';
  106. $filterByGlobal = isset($_REQUEST['filter_by_global']) ? $_REQUEST['filter_by_global'] : null;
  107. $cat = new Testcategory(null, null, null, null, $type);
  108. $items = $cat->get_categories_by_keyword($_REQUEST['tag']);
  109. $em = $this->get('orm.em');
  110. $repo = $em->getRepository('Entity\CQuizCategory');
  111. $json_items = array();
  112. if (!empty($items)) {
  113. foreach ($items as $item) {
  114. if ($item['c_id'] == 0) {
  115. if ($filterByGlobal) {
  116. $cat = $em->find('Entity\CQuizCategory', $item['iid']);
  117. $idList = array();
  118. if ($cat) {
  119. $path = $repo->getPath($cat);
  120. if (!empty($path)) {
  121. /** @var Entity\CQuizCategory $cat */
  122. foreach ($path as $cat) {
  123. $idList[] = $cat->getIid();
  124. }
  125. }
  126. }
  127. if (isset($idList) && !empty($idList)) {
  128. if (!in_array($filterByGlobal, $idList)) {
  129. continue;
  130. }
  131. }
  132. }
  133. $item['title'] .= " [".get_lang('Global')."]";
  134. } else {
  135. if (isset($course_id)) {
  136. if ($item['c_id'] != $item['c_id']) {
  137. continue;
  138. }
  139. }
  140. }
  141. $json_items[] = array(
  142. 'key' => $item['iid'],
  143. 'value' => $item['title']
  144. );
  145. }
  146. }
  147. echo json_encode($json_items);
  148. break;
  149. case 'get_live_stats':
  150. if (!api_is_allowed_to_edit(null, true)) {
  151. break;
  152. }
  153. // 1. Setting variables needed by jqgrid
  154. $action = $_GET['a'];
  155. $exercise_id = intval($_GET['exercise_id']);
  156. $page = intval($_REQUEST['page']); //page
  157. $limit = intval($_REQUEST['rows']); //quantity of rows
  158. $sidx = $_REQUEST['sidx']; //index to filter
  159. $sord = $_REQUEST['sord']; //asc or desc
  160. if (!in_array($sord, array('asc','desc'))) {
  161. $sord = 'desc';
  162. }
  163. // get index row - i.e. user click to sort $sord = $_GET['sord'];
  164. // get the direction
  165. if (!$sidx) {
  166. $sidx = 1;
  167. }
  168. $track_exercise = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
  169. $user_table = Database::get_main_table(TABLE_MAIN_USER);
  170. $track_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
  171. $minutes = intval($_REQUEST['minutes']);
  172. $now = time() - 60*$minutes; //1 hour
  173. $now = api_get_utc_datetime($now);
  174. $where_condition = " orig_lp_id = 0 AND exe_exo_id = $exercise_id AND start_date > '$now' ";
  175. $sql = "SELECT COUNT(DISTINCT exe_id) FROM $track_exercise WHERE $where_condition ";
  176. $result = Database::query($sql);
  177. $count = Database::fetch_row($result);
  178. $count = $count[0];
  179. //3. Calculating first, end, etc
  180. $total_pages = 0;
  181. if ($count > 0) {
  182. if (!empty($limit)) {
  183. $total_pages = ceil($count/$limit);
  184. }
  185. }
  186. if ($page > $total_pages) {
  187. $page = $total_pages;
  188. }
  189. $start = $limit * $page - $limit;
  190. if ($start < 0) {
  191. $start = 0;
  192. }
  193. $sql = "SELECT exe_id,
  194. exe_user_id,
  195. firstname,
  196. lastname,
  197. aa.status,
  198. start_date,
  199. exe_result,
  200. exe_weighting,
  201. exe_result/exe_weighting as score,
  202. exe_duration,
  203. questions_to_check,
  204. orig_lp_id
  205. FROM $user_table u
  206. INNER JOIN (
  207. SELECT t.exe_id, t.exe_user_id, status,
  208. start_date, exe_result, exe_weighting, exe_result/exe_weighting as score, exe_duration, questions_to_check, orig_lp_id
  209. FROM $track_exercise t LEFT JOIN $track_attempt a ON (a.exe_id = t.exe_id AND t.exe_user_id = a.user_id )
  210. WHERE t.status = 'incomplete' AND
  211. $where_condition
  212. GROUP BY exe_user_id
  213. ) as aa
  214. ON aa.exe_user_id = user_id
  215. ORDER BY $sidx $sord LIMIT $start, $limit";
  216. $result = Database::query($sql);
  217. $results = array();
  218. while ($row = Database::fetch_array($result, 'ASSOC')) {
  219. $results[] = $row;
  220. }
  221. $oExe = new exercise();
  222. $oExe->read($exercise_id);
  223. $response = new stdClass();
  224. $response->page = $page;
  225. $response->total = $total_pages;
  226. $response->records = $count;
  227. $i=0;
  228. if (!empty($results)) {
  229. foreach($results as $row) {
  230. $sql = "SELECT SUM(count_question_id) as count_question_id FROM (
  231. SELECT 1 as count_question_id FROM $track_attempt a
  232. WHERE user_id = {$row['exe_user_id']} and exe_id = {$row['exe_id']}
  233. GROUP by question_id
  234. ) as count_table";
  235. $result_count = Database::query($sql);
  236. $count_questions = Database::fetch_array($result_count,'ASSOC');
  237. $count_questions = $count_questions['count_question_id'];
  238. $row['count_questions'] = $count_questions;
  239. $response->rows[$i]['id'] = $row['exe_id'];
  240. $remaining = strtotime($row['start_date'])+($oExe->expired_time*60) - strtotime(api_get_utc_datetime(time()));
  241. $h = floor($remaining/3600);
  242. $m = floor(($remaining - ($h*3600))/60);
  243. $s = ($remaining - ($h*3600) - ($m*60));
  244. $array = array(
  245. $row['firstname'],
  246. $row['lastname'],
  247. api_format_date($row['start_date'], DATE_TIME_FORMAT_LONG).' ['.($h>0?$h.':':'').sprintf("%02d",$m).':'.sprintf("%02d",$s).']',
  248. $row['count_questions'],
  249. round($row['score']*100).'%'
  250. );
  251. $response->rows[$i]['cell'] = $array;
  252. $i++;
  253. }
  254. }
  255. echo json_encode($response);
  256. break;
  257. case 'update_exercise_list_order':
  258. if (api_is_allowed_to_edit(null, true)) {
  259. $new_list = $_REQUEST['exercise_list'];
  260. $table = Database::get_course_table(TABLE_QUIZ_ORDER);
  261. $counter = 1;
  262. //Drop all
  263. Database::query("DELETE FROM $table WHERE session_id = $session_id AND c_id = $course_id");
  264. //Insert all
  265. foreach ($new_list as $new_order_id) {
  266. Database::insert($table, array('exercise_order' => $counter, 'session_id' => $session_id, 'exercise_id' => intval($new_order_id), 'c_id' => $course_id));
  267. $counter++;
  268. }
  269. Display::display_confirmation_message(get_lang('Saved'));
  270. }
  271. break;
  272. case 'update_question_order':
  273. $course_info = api_get_course_info($course_code);
  274. $course_id = $course_info['real_id'];
  275. $exercise_id = isset($_REQUEST['exercise_id']) ? $_REQUEST['exercise_id'] : null;
  276. if (empty($exercise_id)) {
  277. return Display::display_error_message(get_lang('Error'));
  278. }
  279. if (api_is_allowed_to_edit(null, true)) {
  280. $new_question_list = $_POST['question_id_list'];
  281. $TBL_QUESTIONS = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
  282. $counter = 1;
  283. foreach ($new_question_list as $new_order_id) {
  284. Database::update(
  285. $TBL_QUESTIONS,
  286. array('question_order' => $counter),
  287. array('question_id = ? AND c_id = ? AND exercice_id = ? ' => array(intval($new_order_id), $course_id, $exercise_id)));
  288. $counter++;
  289. }
  290. Display::display_confirmation_message(get_lang('Saved'));
  291. }
  292. break;
  293. case 'add_question_to_reminder':
  294. $objExercise = Session::read('objExercise');
  295. if (empty($objExercise)) {
  296. echo 0;
  297. exit;
  298. } else {
  299. $objExercise->edit_question_to_remind($_REQUEST['exe_id'], $_REQUEST['question_id'], $_REQUEST['action']);
  300. }
  301. break;
  302. case 'save_exercise_by_now':
  303. $course_info = api_get_course_info($course_code);
  304. $course_id = $course_info['real_id'];
  305. //Use have permissions?
  306. if (api_is_allowed_to_session_edit()) {
  307. // Exercise information.
  308. /** @var \Exercise $objExercise */
  309. $objExercise = Session::read('objExercise');
  310. if (empty($objExercise)) {
  311. if ($debug) {
  312. error_log('objExercise is empty');
  313. }
  314. echo 'error';
  315. exit;
  316. }
  317. $question_list = Session::read('question_list_uncompressed');
  318. // If exercise or question is not set then exit.
  319. if (empty($question_list)) {
  320. echo 'error';
  321. if ($debug) {
  322. error_log('question_list is empty');
  323. }
  324. }
  325. // "all" or "simple" strings means that there's one or all questions exercise type
  326. $type = isset($_REQUEST['type']) ? $_REQUEST['type'] : null;
  327. // Questions choices
  328. $choice = isset($_REQUEST['choice']) ? $_REQUEST['choice'] : null;
  329. // Hotspot coordinates from all questions
  330. $hot_spot_coordinates = isset($_REQUEST['hotspot']) ? $_REQUEST['hotspot'] : null;
  331. // There is a reminder?
  332. $remind_list = isset($_REQUEST['remind_list']) && !empty($_REQUEST['remind_list'])? array_keys($_REQUEST['remind_list']) : null;
  333. // Needed in manage_answer
  334. $learnpath_id = isset($_REQUEST['learnpath_id']) ? intval($_REQUEST['learnpath_id']) : 0;
  335. $learnpath_item_id = isset($_REQUEST['learnpath_item_id']) ? intval($_REQUEST['learnpath_item_id']) : 0;
  336. // Attempt id
  337. $exe_id = $_REQUEST['exe_id'];
  338. if ($debug) {
  339. error_log("exe_id = $exe_id");
  340. error_log("type = $type ");
  341. error_log("choice = ".print_r($choice, 1)." ");
  342. error_log("hot_spot_coordinates = ".print_r($hot_spot_coordinates, 1));
  343. error_log("remind_list = ".print_r($remind_list, 1));
  344. }
  345. // Question info.
  346. $question_id = isset($_REQUEST['question_id']) ? intval($_REQUEST['question_id']) : null;
  347. // Getting information of the current exercise.
  348. $exercise_stat_info = $objExercise->getStatTrackExerciseInfoByExeId($exe_id);
  349. $exercise_id = $exercise_stat_info['exe_exo_id'];
  350. $attempt_list = array();
  351. // First time here we create an attempt (getting the exe_id).
  352. if (empty($exercise_stat_info)) {
  353. } else {
  354. // We know the user we get the exe_id.
  355. $exe_id = $exercise_stat_info['exe_id'];
  356. $total_score = $exercise_stat_info['exe_result'];
  357. // Getting the list of attempts.
  358. $attempt_list = getAllExerciseEventByExeId($exe_id);
  359. }
  360. // Updating Reminder algorythme.
  361. if ($objExercise->type == ONE_PER_PAGE) {
  362. $bd_reminder_list = explode(',', $exercise_stat_info['questions_to_check']);
  363. // Fixing reminder order
  364. $fixedRemindList = array();
  365. if (!empty($bd_reminder_list)) {
  366. foreach ($question_list as $questionId) {
  367. if (in_array($questionId, $bd_reminder_list)) {
  368. $fixedRemindList[] = $questionId;
  369. }
  370. }
  371. }
  372. $bd_reminder_list = $fixedRemindList;
  373. if (empty($remind_list)) {
  374. $remind_list = $bd_reminder_list;
  375. $new_list = array();
  376. foreach ($bd_reminder_list as $item) {
  377. if ($item != $question_id) {
  378. $new_list[] = $item;
  379. }
  380. }
  381. $remind_list = $new_list;
  382. } else {
  383. if (isset($remind_list[0])) {
  384. if (!in_array($remind_list[0], $bd_reminder_list)) {
  385. array_push($bd_reminder_list, $remind_list[0]);
  386. }
  387. $remind_list = $bd_reminder_list;
  388. }
  389. }
  390. }
  391. // No exe id? Can't save answer!
  392. if (empty($exe_id)) {
  393. // Fires an error.
  394. echo 'error';
  395. error_log('exe_id empty');
  396. exit;
  397. } else {
  398. Session::write('exe_id', $exe_id);
  399. }
  400. // Getting the total weight if the request is simple
  401. $total_weight = 0;
  402. if ($type == 'simple') {
  403. foreach ($question_list as $my_question_id) {
  404. $objQuestionTmp = Question::read($my_question_id, $course_id);
  405. $total_weight += $objQuestionTmp->selectWeighting();
  406. }
  407. }
  408. unset($objQuestionTmp);
  409. // Looping the question list
  410. if ($debug) {
  411. error_log("Looping question list".print_r($question_list, 1));
  412. error_log("Trying to save question: $question_id ");
  413. }
  414. foreach ($question_list as $my_question_id) {
  415. if ($type == 'simple' && $question_id != $my_question_id) {
  416. continue;
  417. }
  418. $my_choice = isset($choice[$my_question_id]) ? $choice[$my_question_id] : null;
  419. if ($debug) {
  420. error_log("Process to save question_id = $my_question_id ");
  421. error_log("my_choice = ".print_r($my_choice, 1)."");
  422. }
  423. // Creates a temporary Question object
  424. $objQuestionTmp = Question::read($my_question_id, $course_id);
  425. if ($objExercise->type == ONE_PER_PAGE && $objQuestionTmp->type == UNIQUE_ANSWER) {
  426. if (in_array($my_question_id, $remind_list)) {
  427. if (empty($my_choice)) {
  428. echo 'answer_required';
  429. exit;
  430. }
  431. }
  432. }
  433. // Getting free choice data.
  434. if ($objQuestionTmp->type == FREE_ANSWER && $type == 'all') {
  435. $my_choice = isset($_REQUEST['free_choice'][$my_question_id]) && !empty($_REQUEST['free_choice'][$my_question_id])? $_REQUEST['free_choice'][$my_question_id]: null;
  436. }
  437. if ($type == 'all') {
  438. $total_weight += $objQuestionTmp->selectWeighting();
  439. }
  440. // This variable came from exercise_submit_modal.php
  441. $hotspot_delineation_result = null;
  442. if (isset($_SESSION['hotspot_delineation_result']) && isset($_SESSION['hotspot_delineation_result'][$objExercise->selectId()])) {
  443. $hotspot_delineation_result = $_SESSION['hotspot_delineation_result'][$objExercise->selectId()][$my_question_id];
  444. }
  445. if ($type == 'simple') {
  446. // Getting old attempt in order to decrees the total score.
  447. $old_result = $objExercise->manageAnswers(
  448. $exe_id,
  449. $my_question_id,
  450. null,
  451. 'exercise_show',
  452. array(),
  453. false,
  454. true,
  455. false
  456. );
  457. // Removing old score.
  458. $total_score = $total_score - $old_result['score'];
  459. if ($debug) {
  460. error_log("old score = ".$old_result['score']);
  461. error_log("total_score = ".$total_score."");
  462. }
  463. }
  464. // Deleting old attempt
  465. if (isset($attempt_list) && !empty($attempt_list[$my_question_id])) {
  466. if ($debug) {
  467. error_log("delete_attempt exe_id : $exe_id, my_question_id: $my_question_id");
  468. }
  469. delete_attempt($exe_id, api_get_user_id(), $course_id, $session_id, $my_question_id);
  470. if ($objQuestionTmp->type == HOT_SPOT) {
  471. delete_attempt_hotspot($exe_id, api_get_user_id(), $course_id, $my_question_id);
  472. }
  473. if (isset($attempt_list[$my_question_id]) && isset($attempt_list[$my_question_id]['marks'])) {
  474. $total_score -= $attempt_list[$my_question_id]['marks'];
  475. }
  476. }
  477. // We're inside *one* question. Go through each possible answer for this question
  478. if ($debug) {
  479. error_log("Calling objExercise->manageAnswers to save the question");
  480. }
  481. $result = $objExercise->manageAnswers(
  482. $exe_id,
  483. $my_question_id,
  484. $my_choice,
  485. 'exercise_result',
  486. $hot_spot_coordinates,
  487. true,
  488. false,
  489. false,
  490. $hotspot_delineation_result
  491. );
  492. // Adding the new score
  493. $total_score += $result['score'];
  494. if ($debug) {
  495. error_log("End objExercise->manageAnswers");
  496. error_log("total_score: $total_score ");
  497. error_log("total_weight: $total_weight ");
  498. }
  499. $duration = 0;
  500. $now = time();
  501. if ($type == 'all') {
  502. $exercise_stat_info = $objExercise->getStatTrackExerciseInfoByExeId($exe_id);
  503. }
  504. $key = ExerciseLib::get_time_control_key($exercise_id, $exercise_stat_info['orig_lp_id'], $exercise_stat_info['orig_lp_item_id']);
  505. $durationTime = Session::read('duration_time');
  506. if (isset($durationTime[$key]) && !empty($durationTime[$key])) {
  507. $duration = $now - $durationTime[$key];
  508. if (!empty($exercise_stat_info['exe_duration'])) {
  509. $duration += $exercise_stat_info['exe_duration'];
  510. }
  511. $duration = intval($duration);
  512. } else {
  513. if (!empty($exercise_stat_info['exe_duration'])) {
  514. $duration = $exercise_stat_info['exe_duration'];
  515. }
  516. }
  517. $durationTime = array(
  518. $key => time()
  519. );
  520. Session::write('duration_time', $durationTime);
  521. update_event_exercise(
  522. $exe_id,
  523. $objExercise->selectId(),
  524. $total_score,
  525. $total_weight,
  526. $session_id,
  527. $exercise_stat_info['orig_lp_id'],
  528. $exercise_stat_info['orig_lp_item_id'],
  529. $exercise_stat_info['orig_lp_item_view_id'],
  530. $duration,
  531. 'incomplete',
  532. $remind_list
  533. );
  534. // Destruction of the Question object
  535. unset($objQuestionTmp);
  536. if ($debug) {
  537. error_log(" -- end question -- ");
  538. }
  539. }
  540. if ($debug) {
  541. error_log(" ------ end ajax call ------- ");
  542. }
  543. }
  544. if ($objExercise->type == ONE_PER_PAGE) {
  545. echo 'one_per_page';
  546. exit;
  547. }
  548. echo 'ok';
  549. break;
  550. case 'correct_exercise_result':
  551. $is_allowedToEdit = api_is_allowed_to_edit(null, true) || api_is_drh();
  552. $is_tutor = api_is_allowed_to_edit(true);
  553. //Send student email @todo move this code in a class, library
  554. if (isset($_POST['comments']) && $_POST['comments'] == 'update' && ($is_allowedToEdit || $is_tutor) && $_POST['exeid'] == strval(intval($_POST['exeid']))) {
  555. $exeId = intval($_POST['exeid']);
  556. $TBL_QUESTIONS = Database :: get_course_table(TABLE_QUIZ_QUESTION);
  557. $TBL_TRACK_EXERCICES = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
  558. $TBL_TRACK_ATTEMPT = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
  559. $TBL_TRACK_ATTEMPT_RECORDING = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING);
  560. $TBL_LP_ITEM_VIEW = Database :: get_course_table(TABLE_LP_ITEM_VIEW);
  561. $track_exercise_info = ExerciseLib::get_exercise_track_exercise_info($exeId);
  562. if (empty($track_exercise_info)) {
  563. echo 0;
  564. }
  565. $test = $track_exercise_info['title'];
  566. $student_id = $track_exercise_info['exe_user_id'];
  567. $session_id = $track_exercise_info['session_id'];
  568. $lp_id = $track_exercise_info['orig_lp_id'];
  569. //$lp_item_id = $track_exercise_info['orig_lp_item_id'];
  570. $lp_item_view_id = $track_exercise_info['orig_lp_item_view_id'];
  571. $course_info = api_get_course_info();
  572. // Teacher data
  573. $teacher_info = api_get_user_info(api_get_user_id());
  574. $from_name = api_get_person_name(
  575. $teacher_info['firstname'],
  576. $teacher_info['lastname'],
  577. null,
  578. PERSON_NAME_EMAIL_ADDRESS
  579. );
  580. $url = api_get_path(WEB_CODE_PATH).'exercice/result.php?id='.$track_exercise_info['exe_id'].'&'.api_get_cidreq().'&show_headers=1&id_session='.$session_id;
  581. $commentIds = array();
  582. $marks = array();
  583. $comments = array();
  584. $result = array();
  585. $values = explode(',', $_POST['vals']);
  586. if (empty($values)) {
  587. echo 0;
  588. exit;
  589. }
  590. $countComments = count($commentIds);
  591. foreach ($values as $questionId) {
  592. $questionId = intval($questionId);
  593. $comment = isset($_POST['comments_'.$questionId]) ? $_POST['comments_'.$questionId] : null;
  594. $mark = isset($_POST['marks_'.$questionId]) ? $_POST['marks_'.$questionId] : null;
  595. $mark = Database::escape_string($mark);
  596. $comment = Database::escape_string($comment);
  597. $query = "UPDATE $TBL_TRACK_ATTEMPT SET marks = '$mark', teacher_comment = '$comment'
  598. WHERE question_id = ".$questionId." AND exe_id=".$exeId;
  599. Database::query($query);
  600. //Saving results in the track recording table
  601. $recording_changes = 'INSERT INTO '.$TBL_TRACK_ATTEMPT_RECORDING.' (exe_id, question_id, marks, insert_date, author, teacher_comment)
  602. VALUES ('."'$exeId','".$questionId."','$mark','".api_get_utc_datetime()."','".api_get_user_id()."'".',"'.$comment.'")';
  603. Database::query($recording_changes);
  604. }
  605. $qry = 'SELECT DISTINCT question_id, marks FROM '.$TBL_TRACK_ATTEMPT.' WHERE exe_id = '.$exeId.' GROUP BY question_id';
  606. $res = Database::query($qry);
  607. $tot = 0;
  608. while ($row = Database :: fetch_array($res, 'ASSOC')) {
  609. $tot += $row['marks'];
  610. }
  611. $sql = "UPDATE $TBL_TRACK_EXERCICES SET exe_result = '".floatval($tot)."' WHERE exe_id = ".$exeId;
  612. Database::query($sql);
  613. if (isset($_POST['send_notification'])) {
  614. //@todo move this somewhere else
  615. $subject = get_lang('ExamSheetVCC');
  616. $message = '<p>'.get_lang('DearStudentEmailIntroduction').'</p><p>'.get_lang('AttemptVCC');
  617. $message .= '<h3>'.get_lang('CourseName').'</h3><p>'.Security::remove_XSS($course_info['name']).'';
  618. $message .= '<h3>'.get_lang('Exercise').'</h3><p>'.Security::remove_XSS($test);
  619. //Only for exercises not in a LP
  620. if ($lp_id == 0) {
  621. $message .= '<p>'.get_lang('ClickLinkToViewComment').' <a href="#url#">#url#</a><br />';
  622. }
  623. $message .= '<p>'.get_lang('Regards').'</p>';
  624. $message .= $from_name;
  625. $message = str_replace("#test#", Security::remove_XSS($test), $message);
  626. $message = str_replace("#url#", $url, $message);
  627. MessageManager::send_message_simple($student_id, $subject, $message, api_get_user_id());
  628. }
  629. $origin = $_POST['origin'];
  630. // Updating LP score here
  631. if (isset($origin) && in_array($origin, array('tracking_course', 'user_course', 'correct_exercise_in_lp'))) {
  632. $sql_update_score = "UPDATE $TBL_LP_ITEM_VIEW SET score = '".floatval($tot)."' WHERE c_id = ".$course_id." AND id = ".$lp_item_view_id;
  633. Database::query($sql_update_score);
  634. }
  635. echo 1;
  636. exit;
  637. }
  638. echo 0;
  639. break;
  640. case 'get_modificator':
  641. set_time_limit(0);
  642. $sessions = SessionManager::get_session_by_course($_REQUEST['cId']);
  643. if (empty($sessions)) {
  644. echo '0.00';
  645. } else {
  646. $sessionInfo = current($sessions);
  647. $sessionId = $sessionInfo['id'];
  648. }
  649. $params = array(
  650. 'exerciseId' => $_REQUEST['exerciseId'],
  651. 'sessionId' => $sessionId,
  652. 'cId' => $_REQUEST['cId'],
  653. 'quizDistributionId' => $_REQUEST['distributionId'],
  654. 'categoryId' => $_REQUEST['categoryId']
  655. );
  656. /** @var Entity\CQuizDistributionRelSessionRelCategory $quizDistributionRelSessionRelCategory */
  657. $quizDistributionRelSessionRelCategory = $app['orm.em']->getRepository('Entity\CQuizDistributionRelSessionRelCategory')->findOneBy($params);
  658. if ($quizDistributionRelSessionRelCategory) {
  659. echo $quizDistributionRelSessionRelCategory->getModifier();
  660. } else {
  661. echo '0.00';
  662. }
  663. break;
  664. case 'save_modificator':
  665. set_time_limit(0);
  666. // Save to all sessions from this course:
  667. $sessions = SessionManager::get_session_by_course($_REQUEST['cId']);
  668. foreach ($sessions as $session) {
  669. $sessionId = $session['id'];
  670. $params = array(
  671. 'exerciseId' => $_REQUEST['exerciseId'],
  672. 'sessionId' => $sessionId,
  673. 'cId' => $_REQUEST['cId'],
  674. 'quizDistributionId' => $_REQUEST['distributionId'],
  675. 'categoryId' => $_REQUEST['categoryId']
  676. );
  677. $quizDistributionRelSessionRelCategory = $app['orm.em']->getRepository('Entity\CQuizDistributionRelSessionRelCategory')->findOneBy($params);
  678. if (empty($quizDistributionRelSessionRelCategory)) {
  679. $quizDistributionRelSessionRelCategory = new Entity\CQuizDistributionRelSessionRelCategory();
  680. $quizDistributionRelSessionRelCategory->setExerciseId($_REQUEST['exerciseId']);
  681. $quizDistributionRelSessionRelCategory->setSessionId($sessionId);
  682. $quizDistributionRelSessionRelCategory->setCId($_REQUEST['cId']);
  683. $quizDistributionRelSessionRelCategory->setQuizDistributionId($_REQUEST['distributionId']);
  684. $quizDistributionRelSessionRelCategory->setCategoryId($_REQUEST['categoryId']);
  685. }
  686. $quizDistributionRelSessionRelCategory->setModifier($_REQUEST['value']);
  687. event_system('update_modificator', 'modifier', $_REQUEST['value']);
  688. event_system('update_modificator', 'exerciseId', $_REQUEST['exerciseId']);
  689. event_system('update_modificator', 'distributionId', $_REQUEST['distributionId']);
  690. $app['orm.em']->persist($quizDistributionRelSessionRelCategory);
  691. $app['orm.em']->flush();
  692. }
  693. echo 1;
  694. break;
  695. default:
  696. echo '';
  697. }
  698. exit;