Update from 1.11.x

pull/3063/head
Julio 7 years ago
parent 6a826b4024
commit be1e996a69
  1. 108
      main/auth/courses_controller.php
  2. 51
      main/auth/courses_list.php
  3. 6
      main/auth/profile.php
  4. 36
      main/auth/set_temp_password.php
  5. 5
      main/auth/sso/sso.Drupal.class.php
  6. 5
      main/auth/sso/sso.class.php
  7. 18
      main/calendar/agenda.php
  8. 1
      main/calendar/agenda_js.php
  9. 20
      main/calendar/agenda_list.php
  10. 61
      main/calendar/planification.php
  11. 4
      main/course_description/index.php
  12. 112
      main/course_home/activity.php
  13. 32
      main/course_home/course_home.php
  14. 2
      main/course_info/about.php
  15. 15
      main/course_info/infocours.php
  16. 2
      main/cron/check_lp_total_time.php
  17. 2
      main/document/add_link.php
  18. 2
      main/document/create_document.php
  19. 2
      main/document/document_quota.php
  20. 4
      main/document/edit_document.php
  21. 4
      main/document/edit_odf.php
  22. 38
      main/document/showinframes.php
  23. 2
      main/exercise/MatchingDraggable.php
  24. 3
      main/exercise/MultipleAnswerTrueFalseDegreeCertainty.php
  25. 21
      main/exercise/ReadingComprehension.php
  26. 43
      main/exercise/TestCategory.php
  27. 71
      main/exercise/admin.php
  28. 4
      main/exercise/aiken.php
  29. 2
      main/exercise/answer.class.php
  30. 509
      main/exercise/exercise.class.php
  31. 286
      main/exercise/exercise.php
  32. 16
      main/exercise/exercise_admin.php
  33. 6
      main/exercise/exercise_report.php
  34. 12
      main/exercise/exercise_result.php
  35. 60
      main/exercise/exercise_show.php
  36. 105
      main/exercise/exercise_submit.php
  37. 30
      main/exercise/exercise_submit_modal.php
  38. 875
      main/exercise/export/exercise_import.inc.php
  39. 36
      main/exercise/fill_blanks.class.php
  40. 2
      main/exercise/freeanswer.class.php
  41. 12
      main/exercise/hotpotatoes.lib.php
  42. 2
      main/exercise/hotpotatoes.php
  43. 2
      main/exercise/hotspot.class.php
  44. 25
      main/exercise/hotspot_admin.inc.php
  45. 53
      main/exercise/hotspot_answers.as.php
  46. 1
      main/exercise/matching.class.php
  47. 63
      main/exercise/overview.php
  48. 90
      main/exercise/question.class.php
  49. 22
      main/exercise/question_admin.inc.php
  50. 106
      main/exercise/question_list_admin.inc.php
  51. 607
      main/exercise/question_pool.php
  52. 111
      main/exercise/recalculate.php
  53. 16
      main/exercise/result.php
  54. 10
      main/exercise/tests_category.php
  55. 2
      main/exercise/unique_answer.class.php
  56. 16
      main/exercise/upload_exercise.php
  57. 1
      main/extra/group_space_tracking.php
  58. 8
      main/extra/upgrade_school_calendar.php
  59. 2
      main/extra/userInfo.php

@ -57,20 +57,11 @@ class CoursesController
}
/**
* It's used for listing categories,
* render to categories_list view.
*
* @param string $action
* @param string $message confirmation message(optional)
* @param string $error error message(optional)
* It's used for listing categories, render to categories_list view.
*/
public function categoryList($action, $message = '', $error = '')
public function categoryList()
{
api_block_anonymous_users();
$data = [];
$data['user_course_categories'] = CourseManager::get_user_course_categories(api_get_user_id());
$stok = Security::get_token();
$actions = Display::url(
Display::return_icon('back.png', get_lang('Back'), '', '32'),
@ -117,28 +108,24 @@ class CoursesController
$limit = []
) {
$data = [];
$browse_course_categories = CoursesAndSessionsCatalog::getCourseCategories();
$listCategories = CoursesAndSessionsCatalog::getCourseCategoriesTree();
$data['countCoursesInCategory'] = CourseCategory::countCoursesInCategory($category_code);
if ($action === 'display_random_courses') {
// Random value is used instead limit filter
$data['browse_courses_in_category'] = CoursesAndSessionsCatalog::getCoursesInCategory(
null,
12
);
$data['browse_courses_in_category'] = CoursesAndSessionsCatalog::getCoursesInCategory(null, 12);
$data['countCoursesInCategory'] = count($data['browse_courses_in_category']);
} else {
if (!isset($category_code)) {
$category_code = $browse_course_categories[0][1]['code']; // by default first category
$category_code = $listCategories['ALL']['code']; // by default first category
}
$limit = isset($limit) ? $limit : self::getLimitArray();
$data['browse_courses_in_category'] = CoursesAndSessionsCatalog::getCoursesInCategory(
$category_code,
null,
$limit
);
$listCourses = CoursesAndSessionsCatalog::getCoursesInCategory($category_code, null, $limit);
$data['browse_courses_in_category'] = $listCourses;
}
$data['browse_course_categories'] = $browse_course_categories;
$data['list_categories'] = $listCategories;
$data['code'] = Security::remove_XSS($category_code);
// getting all the courses to which the user is subscribed to
@ -197,10 +184,7 @@ class CoursesController
$data = [];
$limit = !empty($limit) ? $limit : self::getLimitArray();
$browse_course_categories = CoursesAndSessionsCatalog::getCourseCategories();
$data['countCoursesInCategory'] = CourseCategory::countCoursesInCategory(
'ALL',
$search_term
);
$data['countCoursesInCategory'] = CourseCategory::countCoursesInCategory('ALL', $search_term);
$data['browse_courses_in_category'] = CoursesAndSessionsCatalog::search_courses(
$search_term,
$limit,
@ -234,58 +218,6 @@ class CoursesController
$this->view->render();
}
/**
* Auto user subscription to a course.
*/
public function subscribe_user($course_code, $search_term, $category_code)
{
$courseInfo = api_get_course_info($course_code);
if (empty($courseInfo)) {
return false;
}
// The course must be open in order to access the auto subscription
if (in_array(
$courseInfo['visibility'],
[
COURSE_VISIBILITY_CLOSED,
COURSE_VISIBILITY_REGISTERED,
COURSE_VISIBILITY_HIDDEN,
]
)
) {
Display::addFlash(
Display::return_message(
get_lang('SubscribingNotAllowed'),
'warning'
)
);
} else {
// Redirect to subscription
if (api_is_anonymous()) {
header('Location: '.api_get_path(WEB_CODE_PATH).'auth/inscription.php?c='.$course_code);
exit;
}
$result = $this->model->subscribe_user($course_code);
if (!$result) {
Display::addFlash(
Display::return_message(
get_lang('CourseRegistrationCodeIncorrect'),
'warning'
)
);
} else {
Display::addFlash(
Display::return_message($result['message'], 'normal', false)
);
if (isset($result['content'])) {
Display::addFlash($result['content']);
}
}
}
}
/**
* Create a category
* render to listing view.
@ -796,7 +728,7 @@ class CoursesController
public function sessionListBySearch(array $limit)
{
$q = isset($_REQUEST['q']) ? Security::remove_XSS($_REQUEST['q']) : null;
$hiddenLinks = isset($_GET['hidden_links']) ? intval($_GET['hidden_links']) == 1 : false;
$hiddenLinks = isset($_GET['hidden_links']) ? (int) $_GET['hidden_links'] == 1 : false;
$courseUrl = CourseCategory::getCourseCategoryUrl(
1,
$limit['length'],
@ -812,7 +744,7 @@ class CoursesController
$tpl = new Template();
$tpl->assign('show_courses', CoursesAndSessionsCatalog::showCourses());
$tpl->assign('show_sessions', CoursesAndSessionsCatalog::showSessions());
$tpl->assign('show_tutor', (api_get_setting('show_session_coach') === 'true' ? true : false));
$tpl->assign('show_tutor', api_get_setting('show_session_coach') === 'true' ? true : false);
$tpl->assign('course_url', $courseUrl);
$tpl->assign('already_subscribed_label', $this->getAlreadyRegisteredInSessionLabel());
$tpl->assign('hidden_links', $hiddenLinks);
@ -831,8 +763,8 @@ class CoursesController
*/
public static function getLimitArray()
{
$pageCurrent = isset($_REQUEST['pageCurrent']) ? intval($_GET['pageCurrent']) : 1;
$pageLength = isset($_REQUEST['pageLength']) ? intval($_GET['pageLength']) : CoursesAndSessionsCatalog::PAGE_LENGTH;
$pageCurrent = isset($_REQUEST['pageCurrent']) ? (int) $_GET['pageCurrent'] : 1;
$pageLength = isset($_REQUEST['pageLength']) ? (int) $_GET['pageLength'] : CoursesAndSessionsCatalog::PAGE_LENGTH;
return [
'start' => ($pageCurrent - 1) * $pageLength,
@ -923,8 +855,10 @@ class CoursesController
$catName = $cat->getName();
}
$coachId = $session->getGeneralCoach()->getId();
$coachName = $session->getGeneralCoach()->getCompleteName();
$generalCoach = $session->getGeneralCoach();
$coachId = $generalCoach ? $generalCoach->getId() : 0;
$coachName = $generalCoach ? $session->getGeneralCoach()->getCompleteName() : '';
$actions = null;
if (api_is_platform_admin()) {
$actions = api_get_path(WEB_CODE_PATH).'session/resume_session.php?id_session='.$session->getId();
@ -940,7 +874,9 @@ class CoursesController
'nbr_courses' => $session->getNbrCourses(),
'nbr_users' => $session->getNbrUsers(),
'coach_id' => $coachId,
'coach_url' => api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$coachId,
'coach_url' => $generalCoach
? api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$coachId
: '',
'coach_name' => $coachName,
'coach_avatar' => UserManager::getUserPicture(
$coachId,

@ -15,21 +15,20 @@
api_block_anonymous_users();
$stok = Security::get_token();
$courses_without_category = isset($courses_in_category[0]) ? $courses_in_category[0] : null;
?>
<!-- Actions: The menu with the different options in cathe course management -->
<div id="actions" class="actions">
<?php if ($action != 'createcoursecategory') {
?>
<a href="<?php echo api_get_self(); ?>?action=createcoursecategory">
<?php echo Display::return_icon('new_folder.png', get_lang('CreateCourseCategory'), '', '32'); ?></a>
<?php
} ?>
</div>
<?php
echo '<div id="actions" class="actions">';
if ($action != 'createcoursecategory') {
echo '<a href="'.api_get_self().'?action=createcoursecategory">';
echo Display::return_icon('new_folder.png', get_lang('CreateCourseCategory'), '', '32');
echo '</a>';
}
echo '</div>';
if (!empty($message)) {
echo Display::return_message($message, 'confirm', false);
}
$allowCollapsable = api_get_configuration_value('allow_user_course_category_collapsable');
// COURSES WITH CATEGORIES
if (!empty($user_course_categories)) {
$counter = 0;
@ -37,6 +36,7 @@ if (!empty($user_course_categories)) {
foreach ($user_course_categories as $row) {
echo Display::page_subheader($row['title']);
echo '<a name="category'.$row['id'].'"></a>';
$url = api_get_path(WEB_CODE_PATH).'auth/courses.php?categoryid='.$row['id'].'&sec_token='.$stok;
if (isset($_GET['categoryid']) && $_GET['categoryid'] == $row['id']) {
?>
<!-- We display the edit form for the category -->
@ -48,9 +48,20 @@ if (!empty($user_course_categories)) {
</form>
<?php
}
$max_category_key = count($user_course_categories);
if ($action != 'unsubscribe') {
?>
if ($allowCollapsable) {
if ($row['collapsed'] == 0) {
echo Display::url(
'<i class="fa fa-folder-open"></i>',
$url.'&action=set_collapsable&option=1'
);
} else {
echo Display::url(
'<i class="fa fa-folder"></i>',
$url.'&action=set_collapsable&option=0'
);
}
} ?>
<a href="courses.php?action=sortmycourses&amp;categoryid=<?php echo $row['id']; ?>&amp;sec_token=<?php echo $stok; ?>#category<?php echo $row['id']; ?>">
<?php echo Display::display_icon('edit.png', get_lang('Edit'), '', 22); ?>
</a>
@ -78,10 +89,16 @@ if (!empty($user_course_categories)) {
<?php
} ?>
<a href="courses.php?action=deletecoursecategory&amp;id=<?php echo $row['id']; ?>&amp;sec_token=<?php echo $stok; ?>">
<?php echo Display::display_icon('delete.png', get_lang('Delete'), ['onclick' => "javascript: if (!confirm('".addslashes(api_htmlentities(get_lang("CourseCategoryAbout2bedeleted"), ENT_QUOTES, api_get_system_encoding()))."')) return false;"], 22); ?>
<?php echo Display::display_icon(
'delete.png',
get_lang('Delete'),
['onclick' => "javascript: if (!confirm('".addslashes(api_htmlentities(get_lang('CourseCategoryAbout2bedeleted'), ENT_QUOTES, api_get_system_encoding()))."')) return false;"],
22
); ?>
</a>
<?php
}
$counter++;
echo '<br /><br />';
// Show the courses inside this category
@ -103,7 +120,7 @@ if (!empty($user_course_categories)) {
if (api_get_setting('display_coursecode_in_courselist') === 'true' &&
api_get_setting('display_teacher_in_courselist') === 'true'
) {
echo " - ";
echo ' - ';
}
if (api_get_setting('display_teacher_in_courselist') === 'true') {
@ -120,7 +137,7 @@ if (!empty($user_course_categories)) {
<input type="hidden" name="sec_token" value="<?php echo $stok; ?>">
<input type="hidden" name="course_2_edit_category" value="<?php echo $edit_course; ?>" />
<select name="course_categories">
<option value="0"><?php echo get_lang("NoCourseCategory"); ?></option>
<option value="0"><?php echo get_lang('NoCourseCategory'); ?></option>
<?php foreach ($user_course_categories as $row) {
?>
<option value="<?php echo $row['id']; ?>"><?php echo $row['title']; ?></option>
@ -221,7 +238,7 @@ if (!empty($courses_without_category)) {
if (api_get_setting('display_coursecode_in_courselist') === 'true' &&
api_get_setting('display_teacher_in_courselist') === 'true'
) {
echo " - ";
echo ' - ';
}
if (api_get_setting('display_teacher_in_courselist') === 'true') {
echo $course['tutor'];

@ -639,7 +639,7 @@ if ($form->validate()) {
$sql .= ", official_code = '".Database::escape_string($user_data['official_code'])."'";
}
$sql .= " WHERE user_id = '".api_get_user_id()."'";
$sql .= " WHERE id = '".api_get_user_id()."'";
Database::query($sql);
$webserviceUrl = api_get_plugin_setting('logintcc', 'webservice_url');
@ -741,6 +741,10 @@ if ($form->validate()) {
Session::write('_user', $userInfo);
if ($hook) {
Database::getManager()->clear(User::class); //Avoid cache issue (user entity is used before)
$user = api_get_user_entity(api_get_user_id()); //Get updated user info for hook event
$hook->setEventData(['user' => $user]);
$hook->notifyUpdateUser(HOOK_EVENT_TYPE_POST);
}

@ -11,45 +11,45 @@ use ChamiloSession as Session;
$cidReset = true;
require_once __DIR__.'/../inc/global.inc.php';
$this_section = SECTION_COURSES;
$course_id = isset($_GET['course_id']) ? intval($_GET['course_id']) : null;
$session_id = isset($_GET['session_id']) ? intval($_GET['session_id']) : null;
$user_id = api_get_user_id();
$courseId = isset($_GET['course_id']) ? intval($_GET['course_id']) : null;
$sessionId = isset($_GET['session_id']) ? intval($_GET['session_id']) : null;
$userId = api_get_user_id();
/**
* Security check.
*/
if (empty($course_id)) {
if (empty($courseId)) {
api_not_allowed();
}
$course_info = api_get_course_info_by_id($course_id);
$tpl = new Template(null);
$courseInfo = api_get_course_info_by_id($courseId);
// Build the form
$form = new FormValidator(
'set_temp_password',
'POST',
api_get_self().'?course_id='.$course_id.'&session_id='.$session_id
api_get_self().'?course_id='.$courseId.'&session_id='.$sessionId
);
$form->addElement('header', get_lang('CourseRequiresPassword'));
$form->addElement('hidden', 'course_id', $course_id);
$form->addElement('hidden', 'session_id', $session_id);
$form->addElement('hidden', 'course_id', $courseId);
$form->addElement('hidden', 'session_id', $sessionId);
$form->addElement('password', 'course_password', get_lang('Password'));
$form->addButtonSave(get_lang('Accept'));
if ($form->validate()) {
$form_values = $form->exportValues();
if (sha1($form_values['course_password']) === $course_info['registration_code']) {
Session::write('course_password_'.$course_info['real_id'], true);
header('Location: '.api_get_course_url($course_info['code'], $session_id));
$formValues = $form->exportValues();
if (sha1($formValues['course_password']) === $courseInfo['registration_code']) {
Session::write('course_password_'.$courseInfo['real_id'], true);
header('Location: '.api_get_course_url($courseInfo['code'], $sessionId).
'&action=subscribe&sec_token='.Security::get_existing_token());
exit;
} else {
$tpl->assign('error_message', Display::return_message(get_lang('CourseRegistrationCodeIncorrect'), 'error', true));
Display::addFlash(
Display::return_message(get_lang('CourseRegistrationCodeIncorrect'), 'error')
);
}
}
$tpl->assign('form', $form->toHtml());
$content = $tpl->get_template('auth/set_temp_password.tpl');
$tpl->assign('content', $tpl->fetch($content));
$tpl = new Template(null);
$tpl->assign('content', $form->toHtml());
$tpl->display_one_col_template();

@ -293,6 +293,9 @@ class ssoDrupal
*/
private function decode_cookie($cookie)
{
return unserialize(base64_decode($cookie));
return UnserializeApi::unserialize(
'not_allowed_classes',
base64_decode($cookie)
);
}
}

@ -296,6 +296,9 @@ class sso
*/
private function decode_cookie($cookie)
{
return unserialize(base64_decode($cookie));
return UnserializeApi::unserialize(
'not_allowed_classes',
base64_decode($cookie)
);
}
}

@ -15,7 +15,7 @@ if (!empty($course_info)) {
api_protect_course_script(true);
}
$action = isset($_GET['action']) ? $_GET['action'] : null;
$action = isset($_GET['action']) ? Security::remove_XSS($_GET['action']) : null;
$this_section = SECTION_COURSES;
$url = null;
@ -29,6 +29,15 @@ if (empty($action)) {
exit;
}
$logInfo = [
'tool' => TOOL_CALENDAR_EVENT,
'tool_id' => 0,
'tool_id_detail' => 0,
'action' => $action,
'info' => '',
];
Event::registerLog($logInfo);
$group_id = api_get_group_id();
$groupInfo = GroupManager::get_group_properties($group_id);
$eventId = isset($_REQUEST['id']) ? $_REQUEST['id'] : null;
@ -81,7 +90,12 @@ $nameTools = get_lang('Agenda');
Event::event_access_tool(TOOL_CALENDAR_EVENT);
if ($type === 'fromjs') {
// split the "id" parameter only if string and there are _ separators
if (preg_match('/_/', $eventId)) {
$id_list = explode('_', $eventId);
} else {
$id_list = $eventId;
}
$eventId = $id_list[1];
$event_type = $id_list[0];
$event_type = $event_type === 'platform' ? 'admin' : $event_type;
@ -306,6 +320,8 @@ if (!empty($actionName)) {
"url" => $url,
"name" => get_lang('Agenda'),
];
} else {
$actionName = '';
}
// Tool introduction

@ -27,7 +27,6 @@ $htmlHeadXtra[] = api_get_asset('fullcalendar/dist/locale-all.js');
$htmlHeadXtra[] = api_get_asset('fullcalendar/dist/gcal.js');
$htmlHeadXtra[] = api_get_css_asset('fullcalendar/dist/fullcalendar.min.css');
$htmlHeadXtra[] = api_get_css_asset('qtip2/jquery.qtip.min.css');
$htmlHeadXtra[] = api_get_asset('js-cookie/src/js.cookie.js');
if (api_is_platform_admin() && ($type == 'admin' || $type == 'platform')) {
$type = 'admin';

@ -6,6 +6,16 @@
*/
require_once __DIR__.'/../inc/global.inc.php';
$action = isset($_GET['action']) ? Security::remove_XSS($_GET['action']) : 'calendar_list';
$logInfo = [
'tool' => TOOL_CALENDAR_EVENT,
'tool_id' => 0,
'tool_id_detail' => 0,
'action' => $action,
];
Event::registerLog($logInfo);
$type = isset($_REQUEST['type']) ? $_REQUEST['type'] : null;
$interbreadcrumb[] = [
@ -20,12 +30,12 @@ if (!empty($groupId)) {
$groupProperties = GroupManager::get_group_properties($groupId);
$groupId = $groupProperties['iid'];
$interbreadcrumb[] = [
"url" => api_get_path(WEB_CODE_PATH)."group/group.php?".api_get_cidreq(),
"name" => get_lang('Groups'),
'url' => api_get_path(WEB_CODE_PATH)."group/group.php?".api_get_cidreq(),
'name' => get_lang('Groups'),
];
$interbreadcrumb[] = [
"url" => api_get_path(WEB_CODE_PATH)."group/group_space.php?".api_get_cidreq(),
"name" => get_lang('GroupSpace').' '.$groupProperties['name'],
'url' => api_get_path(WEB_CODE_PATH)."group/group_space.php?".api_get_cidreq(),
'name' => get_lang('GroupSpace').' '.$groupProperties['name'],
];
}
@ -83,7 +93,7 @@ $tpl->assign('agenda_actions', $actions);
$tpl->assign('is_allowed_to_edit', api_is_allowed_to_edit());
if (api_is_allowed_to_edit()) {
if (isset($_GET['action']) && $_GET['action'] == 'change_visibility') {
if ($action == 'change_visibility') {
$courseInfo = api_get_course_info();
$courseCondition = '';
// This happens when list agenda is not inside a course

@ -0,0 +1,61 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CoreBundle\Component\Utils\ChamiloApi;
$cidReset = true;
require_once __DIR__.'/../inc/global.inc.php';
api_block_anonymous_users();
$current_course_tool = TOOL_CALENDAR_EVENT;
$this_section = SECTION_MYAGENDA;
$timezone = new DateTimeZone(api_get_timezone());
$now = new DateTime('now', $timezone);
$currentYear = (int) $now->format('Y');
$searchYear = isset($_GET['year']) ? (int) $_GET['year'] : $currentYear;
$userInfo = api_get_user_info();
$userId = $userInfo['id'];
$sessions = [];
if (api_is_drh()) {
$count = SessionManager::get_sessions_followed_by_drh($userId, null, null, true);
} else {
$count = UserManager::get_sessions_by_category($userId, false, true, true, true);
}
$sessionsList = UserManager::getSubscribedSessionsByYear($userInfo, $searchYear);
if ($count > 50) {
$message = Display::return_message('TooMuchSessionsInPlanification', 'warning');
api_not_allowed(true, $message);
}
$sessions = UserManager::getSessionsCalendarByYear($sessionsList, $searchYear);
$colors = ChamiloApi::getColorPalette(false, true, count($sessions));
$agenda = new Agenda('personal');
$actions = $agenda->displayActions('list', $userId);
$toolName = get_lang('SessionsPlanCalendar');
$interbreadcrumb[] = [
'url' => api_get_path(WEB_CODE_PATH).'calendar/agenda_js.php?type=personal',
'name' => get_lang('Agenda'),
];
$template = new Template($toolName);
$template->assign('toolbar', $actions);
$template->assign('student_id', $userId);
$template->assign('search_year', $searchYear);
$template->assign('colors', $colors);
$template->assign('sessions', $sessions);
$layout = $template->get_template('agenda/planification.tpl');
$template->display($layout);

@ -19,7 +19,7 @@ define('ADD_BLOCK', 8);
$this_section = SECTION_COURSES;
$action = !empty($_GET['action']) ? Security::remove_XSS($_GET['action']) : 'listing';
// protect a course script
$logInfo = [
'tool' => TOOL_COURSE_DESCRIPTION,
'tool_id' => 0,
@ -29,7 +29,7 @@ $logInfo = [
];
Event::registerLog($logInfo);
// get actions
// protect a course script
api_protect_course_script(true);
$description_type = '';

@ -42,10 +42,6 @@ if ($enabled === 'true') {
$pluginExtra = $plugin->getTeacherLink();
}
// COURSE ADMIN ONLY VIEW
$blocks = [];
// Start of tools for CourseAdmins (teachers/tutors)
if ($session_id === 0 && api_is_course_admin() && api_is_allowed_to_edit(null, true)) {
$content .= '<div class="alert alert-success" style="border:0px; margin-top: 0px;padding:0px;">
@ -55,46 +51,7 @@ if ($session_id === 0 && api_is_course_admin() && api_is_allowed_to_edit(null, t
$content .= '</div>
<div class="alert alert-success" id="id_confirmation_message" style="display:none"></div>
</div>';
$content .= $pluginExtra;
if (api_get_setting('show_session_data') == 'true' && $session_id > 0) {
$content .= '
<div class="row">
<div class="col-xs-12 col-md-12">
<span class="viewcaption">'.get_lang('SessionData').'</span>
<table class="course_activity_home">'.
CourseHome::show_session_data($session_id).'
</table>
</div>
</div>';
}
$my_list = CourseHome::get_tools_category(TOOL_AUTHORING);
$blocks[] = [
'title' => get_lang('Authoring'),
'class' => 'course-tools-author',
'content' => CourseHome::show_tools_category($my_list),
];
$list1 = CourseHome::get_tools_category(TOOL_INTERACTION);
$list2 = CourseHome::get_tools_category(TOOL_COURSE_PLUGIN);
$my_list = array_merge($list1, $list2);
$blocks[] = [
'title' => get_lang('Interaction'),
'class' => 'course-tools-interaction',
'content' => CourseHome::show_tools_category($my_list),
];
$my_list = CourseHome::get_tools_category(TOOL_ADMIN_PLATFORM);
$blocks[] = [
'title' => get_lang('Administration'),
'class' => 'course-tools-administration',
'content' => CourseHome::show_tools_category($my_list),
];
} elseif (api_is_coach()) {
$content .= $pluginExtra;
if (api_get_setting('show_session_data') === 'true' && $session_id > 0) {
@ -105,76 +62,9 @@ if ($session_id === 0 && api_is_course_admin() && api_is_allowed_to_edit(null, t
$content .= CourseHome::show_session_data($session_id);
$content .= '</table></div></div>';
}
$my_list = CourseHome::get_tools_category(TOOL_STUDENT_VIEW);
$blocks[] = [
'content' => CourseHome::show_tools_category($my_list),
];
$sessionsCopy = api_get_setting('allow_session_course_copy_for_teachers');
if ($sessionsCopy === 'true') {
// Adding only maintenance for coaches.
$myList = CourseHome::get_tools_category(TOOL_ADMIN_PLATFORM);
$onlyMaintenanceList = [];
foreach ($myList as $item) {
if ($item['name'] === 'course_maintenance') {
$item['link'] = 'course_info/maintenance_coach.php';
$onlyMaintenanceList[] = $item;
}
}
$blocks[] = [
'title' => get_lang('Administration'),
'content' => CourseHome::show_tools_category($onlyMaintenanceList),
];
}
} else {
$tools = CourseHome::get_tools_category(TOOL_STUDENT_VIEW);
$isDrhOfCourse = CourseManager::isUserSubscribedInCourseAsDrh(
api_get_user_id(),
api_get_course_info()
);
// Force user icon for DRH
if ($isDrhOfCourse) {
$addUserTool = true;
foreach ($tools as $tool) {
if ($tool['name'] === 'user') {
$addUserTool = false;
break;
}
}
if ($addUserTool) {
$tools[] = [
'c_id' => api_get_course_int_id(),
'name' => 'user',
'link' => 'user/user.php',
'image' => 'members.gif',
'visibility' => '1',
'admin' => '0',
'address' => 'squaregrey.gif',
'added_tool' => '0',
'target' => '_self',
'category' => 'interaction',
'session_id' => api_get_session_id(),
];
}
}
if (count($tools) > 0) {
$blocks[] = ['content' => CourseHome::show_tools_category($tools)];
}
if ($isDrhOfCourse) {
$drhTool = CourseHome::get_tools_category(TOOL_DRH);
$blocks[] = ['content' => CourseHome::show_tools_category($drhTool)];
}
}
$blocks = CourseHome::getUserBlocks();
$activityView = new Template('', false, false, false, false, false, false);
$activityView->assign('blocks', $blocks);

@ -2,6 +2,7 @@
/* For licensing terms, see /license.txt */
use ChamiloSession as Session;
use Fhaculty\Graph\Graph;
/**
* HOME PAGE FOR EACH COURSE.
@ -138,21 +139,19 @@ if ($isSpecialCourse) {
}
}
if (isset($_GET['action']) && $_GET['action'] == 'subscribe') {
$action = !empty($_GET['action']) ? Security::remove_XSS($_GET['action']) : '';
if ($action == 'subscribe') {
if (Security::check_token('get')) {
Security::clear_token();
$auth = new Auth();
$msg = $auth->subscribe_user($course_code);
$result = CourseManager::autoSubscribeToCourse($course_code);
if ($result) {
if (CourseManager::is_user_subscribed_in_course($user_id, $course_code)) {
Session::write('is_allowed_in_course', true);
}
if (!empty($msg)) {
$show_message .= Display::return_message(
get_lang($msg['message']),
'info',
false
);
}
header('Location: '.api_get_self());
exit;
}
}
@ -166,6 +165,15 @@ if (!isset($coursesAlreadyVisited[$course_code])) {
Session::write('coursesAlreadyVisited', $coursesAlreadyVisited);
}
$logInfo = [
'tool' => 'course-main',
'tool_id' => 0,
'tool_id_detail' => 0,
'action' => $action,
'info' => '',
];
Event::registerLog($logInfo);
/*Auto launch code */
$autoLaunchWarning = '';
$showAutoLaunchLpWarning = false;
@ -385,7 +393,11 @@ if ($allow === true) {
);
if (!empty($item) && isset($item['value']) && !empty($item['value'])) {
$graph = unserialize($item['value']);
/** @var Graph $graph */
$graph = UnserializeApi::unserialize(
'career',
$item['value']
);
$diagram = Career::renderDiagram($careerInfo, $graph);
}
}

@ -51,7 +51,7 @@ $courseDescriptionTools = $em->getRepository('ChamiloCourseBundle:CCourseDescrip
$courseValues = new ExtraFieldValue('course');
$userValues = new ExtraFieldValue('user');
$urlCourse = api_get_path(WEB_PATH).'main/course/about.php?course_id='.$courseId;
$urlCourse = api_get_path(WEB_PATH)."course/$courseId/about";
$courseTeachers = $course->getTeachers();
$teachersData = [];

@ -723,7 +723,6 @@ $form->addHtml('
$form->addHtml('</div>');
// Exercise
if (api_get_configuration_value('allow_exercise_auto_launch')) {
$form->addHtml('<div class="panel panel-default">');
$form->addHtml('
<div class="panel-heading" role="tab" id="heading-exercise">
@ -734,7 +733,7 @@ if (api_get_configuration_value('allow_exercise_auto_launch')) {
href="#collapse-exercise" aria-expanded="false" aria-controls="collapse-exercise">
');
$form->addHtml(
Display::return_icon('quiz.png', get_lang('Exercise')).' '.get_lang('Exercise')
Display::return_icon('quiz.png', get_lang('Exercises')).' '.get_lang('Exercises')
);
$form->addHtml('
</a>
@ -746,6 +745,8 @@ if (api_get_configuration_value('allow_exercise_auto_launch')) {
<div class="panel-body">
');
if (api_get_configuration_value('allow_exercise_auto_launch')) {
// Auto launch exercise
$group = [];
$group[] = $form->createElement(
@ -764,6 +765,14 @@ if (api_get_configuration_value('allow_exercise_auto_launch')) {
);
$group[] = $form->createElement('radio', 'enable_exercise_auto_launch', null, get_lang('Deactivate'), 0);
$form->addGroup($group, '', [get_lang('ExerciseAutoLaunch')]);
}
$form->addElement(
'number',
'quiz_question_limit_per_day',
[get_lang('QuizQuestionsLimitPerDay'), get_lang('QuizQuestionsLimitPerDayComment')],
['step' => 1, 'min' => 0]
);
if (is_settings_editable()) {
$form->addButtonSave(get_lang('SaveSettings'), 'submit_save');
@ -774,12 +783,12 @@ if (api_get_configuration_value('allow_exercise_auto_launch')) {
}
$form->freeze();
}
$form->addHtml('
</div>
</div>
');
$form->addHtml('</div>');
}
// THEMATIC ADVANCE SETTINGS
$group = [];

@ -19,7 +19,7 @@ $max = 10;
$counter = 0;
// Check Sessions
$_configuration['access_url'] = 6;
$sessions = SessionManager::get_sessions_admin();
$sessions = SessionManager::formatSessionsAdminForGrid();
foreach ($sessions as $session) {
$sessionId = $session['id'];
if (!empty($testSessionId)) {

@ -175,7 +175,7 @@ echo DocumentManager::build_directory_selector(
// Add tooltip and correctly parse its inner HTML
echo '<script>
$(document).ready(function() {
$(function() {
$("[data-toggle=\'tooltip\']").tooltip({
content:
function() {

@ -17,7 +17,7 @@ $this_section = SECTION_COURSES;
$groupRights = Session::read('group_member_with_upload_rights');
$htmlHeadXtra[] = '
<script>
$(document).ready(function() {
$(function() {
$(".scrollbar-light").scrollbar();
expandColumnToogle("#hide_bar_template", {

@ -125,7 +125,7 @@ $session[] = [
$quota_data = json_encode($session);
$htmlHeadXtra[] = "<script>
$(document).ready(function(){
$(function() {
var data = ".$quota_data.";
var plot1 = jQuery.jqplot('chart1', [data], {
seriesDefaults: {

@ -34,7 +34,7 @@ $groupRights = Session::read('group_member_with_upload_rights');
// Template's javascript
$htmlHeadXtra[] = '
<script>
$(document).ready(function() {
$(function() {
$(".scrollbar-light").scrollbar();
expandColumnToogle("#hide_bar_template", {
@ -533,7 +533,7 @@ if ($owner_id == api_get_user_id() ||
} else {
// Add tooltip and correctly parse its inner HTML
echo '<script>
$(document).ready(function() {
$(function() {
$("[data-toggle=\'tooltip\']").tooltip(
{
content:

@ -76,8 +76,8 @@ $htmlHeadXtra[] = api_get_js('wodotexteditor/wodotexteditor.js');
$htmlHeadXtra[] = api_get_js('wodotexteditor/localfileeditor.js');
$htmlHeadXtra[] = api_get_js('wodotexteditor/FileSaver.js');
$htmlHeadXtra[] = '
<script type="text/javascript" charset="utf-8">
$(document).on(\'ready\', function() {
<script>
$(function() {
createEditor(\''.$fileUrl.'\');
});
</script>

@ -103,7 +103,7 @@ if (!$is_allowed_to_edit && !$is_visible) {
}
$pathinfo = pathinfo($header_file);
$playerSupportedFiles = ['mp4', 'ogv', 'flv', 'm4v', 'webm'];
$playerSupportedFiles = ['mp3', 'mp4', 'ogv', 'flv', 'm4v', 'webm'];
$playerSupported = false;
if (in_array(strtolower($pathinfo['extension']), $playerSupportedFiles)) {
$playerSupported = true;
@ -188,7 +188,7 @@ if (in_array(strtolower($pathinfo['extension']), $web_odf_supported_files)) {
var topbarHeight = $("#topbar").height();
$("#viewerJSContent").height((bodyHeight - topbarHeight));
}
$(document).ready(function() {
$(function() {
$(window).resize(resizeIframe());
});
</script>'
@ -207,9 +207,7 @@ if (isset($document_data['parents']) && isset($document_data['parents'][0])) {
if ($isChatFolder) {
$htmlHeadXtra[] = api_get_js('highlight/highlight.pack.js');
$htmlHeadXtra[] = api_get_css(api_get_path(WEB_CSS_PATH).'chat.css');
$htmlHeadXtra[] = api_get_css(
api_get_path(WEB_LIBRARY_PATH).'javascript/highlight/styles/github.css'
);
$htmlHeadXtra[] = api_get_css(api_get_path(WEB_LIBRARY_PATH).'javascript/highlight/styles/github.css');
$htmlHeadXtra[] = '
<script>
hljs.initHighlightingOnLoad();
@ -258,15 +256,14 @@ if (!$playerSupported && $execute_iframe) {
if ($originIsLearnpath) {
Display::display_reduced_header();
} else {
Display::display_header('');
Display::display_header();
}
echo '<div class="text-center">';
$file_url = api_get_path(WEB_COURSE_PATH).$courseInfo['path'].'/document'.$header_file;
$file_url_web = $file_url.'?'.api_get_cidreq();
if ($show_web_odf) {
echo '<div class="text-center">';
$browser = api_get_navigator();
$pdfUrl = api_get_path(WEB_LIBRARY_PATH).'javascript/ViewerJS/index.html#'.$file_url;
if ($browser['name'] == 'Mozilla' && preg_match('|.*\.pdf|i', $header_file)) {
@ -277,12 +274,11 @@ if ($show_web_odf) {
src="'.$pdfUrl.'">
</iframe>';
echo '</div>';
}
echo '</div>';
}
if ($playerSupported) {
echo DocumentManager::generateVideoPreview($file_url_web, $extension);
echo DocumentManager::generateMediaPreview($file_url_web, $extension);
}
if ($is_freemind_available) {
@ -355,7 +351,6 @@ if ($execute_iframe) {
$content = Security::remove_XSS(file_get_contents($file_url_sys));
echo $content;
} else {
if (api_is_allowed_to_edit()) {
$parentId = $document_data['parent_id'];
$url = api_get_path(WEB_CODE_PATH).'document/document.php?'.api_get_cidreq().'&id='.$parentId;
$actionsLeft = Display::url(
@ -363,6 +358,23 @@ if ($execute_iframe) {
$url
);
$groupMemberWithEditRights = false;
$groupId = api_get_group_id();
if (!empty($groupId)) {
$groupInfo = GroupManager::get_group_properties($groupId);
if ($groupInfo) {
$groupMemberWithEditRights = GroupManager::allowUploadEditDocument(
api_get_user_id(),
api_get_course_int_id(),
$groupInfo,
$document_data
);
}
}
$allowToEdit = api_is_allowed_to_edit(null, true) || $groupMemberWithEditRights;
if ($allowToEdit) {
$actionsLeft .= Display::url(
Display::return_icon(
'edit.png',
@ -398,9 +410,9 @@ if ($execute_iframe) {
api_get_path(WEB_CODE_PATH).'document/document.php?'.api_get_cidreq(
).'&action=export_to_pdf&id='.$document_id
);
}
echo $toolbar = Display::toolbarAction('actions-documents', [$actionsLeft]);
}
echo '<iframe
id="mainFrame"

@ -184,7 +184,6 @@ class MatchingDraggable extends Question
$form->addHtml('<tr>');
$form->addHtml('<td>'.chr(64 + $i).'</td>');
//$form->addText("option[$i]", null);
$form->addHtmlEditor(
"option[$i]",
null,
@ -272,6 +271,7 @@ class MatchingDraggable extends Question
$header .= '<th>'.get_lang('ExpectedChoice').'</th>';
$header .= '<th>'.get_lang('Status').'</th>';
} else {
$header .= '<th>'.get_lang('YourChoice').'</th>';
$header .= '<th>'.get_lang('CorrespondsTo').'</th>';
}
$header .= '</tr>';

@ -1204,6 +1204,7 @@ class MultipleAnswerTrueFalseDegreeCertainty extends Question
$and = '';
$questionId = (int) $questionId;
$position = (int) $position;
$exeId = (int) $exeId;
if ($questionId >= 0) {
$and .= " AND question_id = $questionId";
@ -1246,7 +1247,7 @@ class MultipleAnswerTrueFalseDegreeCertainty extends Question
$objectExercise = new Exercise();
$objectExercise->read($exerciseId);
return $objectExercise->get_count_question_list();
return $objectExercise->getQuestionCount();
}
return 0;

@ -51,6 +51,14 @@ class ReadingComprehension extends UniqueAnswer
*/
public $refreshTime = 3;
/**
* Indicates how show the question list.
* 1 = all in one page; 2 = one per page (default).
*
* @var int
*/
private $exerciseType = 2;
/**
* Constructor.
*/
@ -189,6 +197,18 @@ class ReadingComprehension extends UniqueAnswer
return $select_level;
}
/**
* @param int $type
*
* @return ReadingComprehension
*/
public function setExerciseType($type)
{
$this->exerciseType = (int) $type;
return $this;
}
/**
* @param $wordsCount
* @param $turns
@ -205,6 +225,7 @@ class ReadingComprehension extends UniqueAnswer
$view->assign('words_count', $wordsCount);
$view->assign('turns', $turns);
$view->assign('refresh_time', $this->refreshTime);
$view->assign('exercise_type', $this->exerciseType);
$view->display($template);
}
}

@ -22,6 +22,8 @@ class TestCategory
*/
public function __construct()
{
$this->name = '';
$this->description = '';
}
/**
@ -73,15 +75,15 @@ class TestCategory
// check if name already exists
$sql = "SELECT count(*) AS nb FROM $table
WHERE title = '".$this->name."' AND c_id = $courseId";
WHERE title = '".Database::escape_string($this->name)."' AND c_id = $courseId";
$result = Database::query($sql);
$row = Database::fetch_array($result);
// lets add in BDD if not the same name
if ($row['nb'] <= 0) {
$params = [
'c_id' => $courseId,
'title' => (string) $this->name,
'description' => (string) $this->description,
'title' => $this->name,
'description' => $this->description,
];
$newId = Database::insert($table, $params);
@ -116,7 +118,7 @@ class TestCategory
{
$table = Database::get_course_table(TABLE_QUIZ_QUESTION_CATEGORY);
$tbl_question_rel_cat = Database::get_course_table(TABLE_QUIZ_QUESTION_REL_CATEGORY);
$id = intval($id);
$id = (int) $id;
$course_id = api_get_course_int_id();
$category = $this->getCategory($id);
@ -130,9 +132,9 @@ class TestCategory
WHERE category_id = $id AND c_id=".$course_id;
Database::query($sql);
// item_property update
$course_info = api_get_course_info_by_id($course_id);
$courseInfo = api_get_course_info_by_id($course_id);
api_item_property_update(
$course_info,
$courseInfo,
TOOL_TEST_CATEGORY,
$this->id,
'TestCategoryDeleted',
@ -193,7 +195,7 @@ class TestCategory
public function getCategoryQuestionsNumber()
{
$table = Database::get_course_table(TABLE_QUIZ_QUESTION_REL_CATEGORY);
$id = intval($this->id);
$id = (int) $this->id;
$sql = "SELECT count(*) AS nb
FROM $table
WHERE category_id = $id AND c_id=".api_get_course_int_id();
@ -305,10 +307,8 @@ class TestCategory
*
* @return string
*/
public static function getCategoryNameForQuestion(
$questionId,
$courseId = 0
) {
public static function getCategoryNameForQuestion($questionId, $courseId = 0)
{
if (empty($courseId)) {
$courseId = api_get_course_int_id();
}
@ -399,9 +399,7 @@ class TestCategory
public static function getListOfCategoriesNameForTest($exerciseId, $grouped_by_category = true)
{
$result = [];
$categories = self::getListOfCategoriesIDForTest(
$exerciseId
);
$categories = self::getListOfCategoriesIDForTest($exerciseId);
foreach ($categories as $catInfo) {
$categoryId = $catInfo['id'];
@ -552,7 +550,7 @@ class TestCategory
$TBL_EXERCICE_QUESTION = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
$TBL_QUESTION_REL_CATEGORY = Database::get_course_table(TABLE_QUIZ_QUESTION_REL_CATEGORY);
$categoryTable = Database::get_course_table(TABLE_QUIZ_QUESTION_CATEGORY);
$exerciseId = intval($exerciseId);
$exerciseId = (int) $exerciseId;
$courseId = api_get_course_int_id();
$sql = "SELECT DISTINCT qrc.question_id, qrc.category_id
@ -699,7 +697,7 @@ class TestCategory
{
$tabResult = [];
$tabCatName = []; // tab of category name
while (list($cat_id, $tabquestion) = each($in_tab)) {
foreach ($in_tab as $cat_id => $tabquestion) {
$category = new TestCategory();
$category = $category->getCategory($cat_id);
$tabCatName[$cat_id] = $category->name;
@ -708,7 +706,7 @@ class TestCategory
// sort table by value, keeping keys as they are
asort($tabCatName);
// keys of $tabCatName are keys order for $in_tab
while (list($key, $val) = each($tabCatName)) {
foreach ($tabCatName as $key => $val) {
$tabResult[$key] = $in_tab[$key];
}
@ -723,9 +721,9 @@ class TestCategory
{
$tbl_track_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
$tbl_question_rel_category = Database::get_course_table(TABLE_QUIZ_QUESTION_REL_CATEGORY);
$in_cat_id = intval($in_cat_id);
$in_exe_id = intval($in_exe_id);
$in_user_id = intval($in_user_id);
$in_cat_id = (int) $in_cat_id;
$in_exe_id = (int) $in_exe_id;
$in_user_id = (int) $in_user_id;
$query = "SELECT DISTINCT
marks,
@ -937,12 +935,15 @@ class TestCategory
$courseId = (int) $courseId;
$table = Database::get_course_table(TABLE_QUIZ_REL_CATEGORY);
$categoryTable = Database::get_course_table(TABLE_QUIZ_QUESTION_CATEGORY);
$exercise->id = (int) $exercise->id;
$sql = "SELECT * FROM $table qc
LEFT JOIN $categoryTable c
ON (qc.c_id = c.c_id AND c.id = qc.category_id)
WHERE qc.c_id = $courseId AND exercise_id = {$exercise->id} ";
if (!empty($order)) {
$order = Database::escape_string($order);
$sql .= "ORDER BY $order";
}
@ -1158,7 +1159,7 @@ class TestCategory
if (empty($courseId)) {
$courseId = api_get_course_int_id();
}
$courseId = intval($courseId);
$courseId = (int) $courseId;
$tbl_cat = Database::get_course_table(TABLE_QUIZ_QUESTION_CATEGORY);
$sql = "SELECT id FROM $tbl_cat
WHERE c_id = $courseId AND title = '".Database::escape_string($title)."'";

@ -56,13 +56,13 @@ api_protect_course_script(true);
$is_allowedToEdit = api_is_allowed_to_edit(null, true, false, false);
$sessionId = api_get_session_id();
$studentViewActive = api_is_student_view_active();
$showPagination = api_get_configuration_value('show_question_pagination');
if (!$is_allowedToEdit) {
api_not_allowed(true);
}
if (empty($exerciseId)) {
$exerciseId = isset($_GET['exerciseId']) ? intval($_GET['exerciseId']) : '0';
}
$exerciseId = isset($_GET['exerciseId']) ? (int) $_GET['exerciseId'] : '0';
/* stripslashes POST data */
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
@ -79,19 +79,11 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
}
$newQuestion = isset($_GET['newQuestion']) ? $_GET['newQuestion'] : 0;
if (empty($modifyAnswers)) {
$modifyAnswers = isset($_GET['modifyAnswers']) ? $_GET['modifyAnswers'] : 0;
}
$editQuestion = isset($_GET['editQuestion']) ? $_GET['editQuestion'] : 0;
if (empty($modifyQuestion)) {
$page = isset($_GET['page']) && !empty($_GET['page']) ? (int) $_GET['page'] : 1;
$modifyQuestion = isset($_GET['modifyQuestion']) ? $_GET['modifyQuestion'] : 0;
}
if (empty($deleteQuestion)) {
$deleteQuestion = isset($_GET['deleteQuestion']) ? $_GET['deleteQuestion'] : 0;
}
$clone_question = isset($_REQUEST['clone_question']) ? $_REQUEST['clone_question'] : 0;
if (empty($questionId)) {
$questionId = Session::read('questionId');
@ -124,6 +116,7 @@ if (isset($_REQUEST['convertAnswer'])) {
Session::write('objQuestion', $objQuestion);
}
$objAnswer = Session::read('objAnswer');
$_course = api_get_course_info();
// document path
$documentPath = api_get_path(SYS_COURSE_PATH).$_course['path'].'/document';
@ -166,12 +159,16 @@ if (!is_object($objExercise)) {
// creation of a new exercise if wrong or not specified exercise ID
if ($exerciseId) {
$objExercise->read($exerciseId);
$parseQuestionList = $showPagination > 0 ? false : true;
if ($editQuestion) {
$parseQuestionList = false;
$showPagination = true;
}
$objExercise->read($exerciseId, $parseQuestionList);
}
// saves the object into the session
Session::write('objExercise', $objExercise);
}
// Exercise can be edited in their course.
if ($objExercise->sessionId != $sessionId) {
api_not_allowed(true);
@ -185,7 +182,7 @@ if (!$fromExercise) {
}
}
$nbrQuestions = $objExercise->selectNbrQuestions();
$nbrQuestions = $objExercise->getQuestionCount();
// Question object creation.
if ($editQuestion || $newQuestion || $modifyQuestion || $modifyAnswers) {
@ -254,9 +251,9 @@ if (!empty($clone_question) && !empty($objExercise->id)) {
$new_answer_obj->duplicate($new_question_obj);
// Reloading tne $objExercise obj
$objExercise->read($objExercise->id);
$objExercise->read($objExercise->id, false);
header('Location: admin.php?'.api_get_cidreq().'&exerciseId='.$objExercise->id);
header('Location: admin.php?'.api_get_cidreq().'&exerciseId='.$objExercise->id.'&page='.$page);
exit;
}
@ -279,24 +276,24 @@ if (api_is_in_gradebook()) {
];
}
$interbreadcrumb[] = ["url" => "exercise.php?".api_get_cidreq(), 'name' => get_lang('Exercises')];
$interbreadcrumb[] = ['url' => 'exercise.php?'.api_get_cidreq(), 'name' => get_lang('Exercises')];
if (isset($_GET['newQuestion']) || isset($_GET['editQuestion'])) {
$interbreadcrumb[] = [
"url" => "admin.php?exerciseId=".$objExercise->id.'&'.api_get_cidreq(),
"name" => $objExercise->selectTitle(true),
'url' => 'admin.php?exerciseId='.$objExercise->id.'&'.api_get_cidreq(),
'name' => $objExercise->selectTitle(true),
];
} else {
$interbreadcrumb[] = [
"url" => "#",
"name" => $objExercise->selectTitle(true),
'url' => '#',
'name' => $objExercise->selectTitle(true),
];
}
// shows a link to go back to the question pool
if (!$exerciseId && $nameTools != get_lang('ExerciseManagement')) {
$interbreadcrumb[] = [
"url" => api_get_path(WEB_CODE_PATH)."exercise/question_pool.php?fromExercise=$fromExercise&".api_get_cidreq(),
"name" => get_lang('QuestionPool'),
'url' => api_get_path(WEB_CODE_PATH)."exercise/question_pool.php?fromExercise=$fromExercise&".api_get_cidreq(),
'name' => get_lang('QuestionPool'),
];
}
@ -306,6 +303,7 @@ if ($modifyIn == 'thisExercise') {
$modifyIn = 'allExercises';
}
}
$htmlHeadXtra[] = api_get_js('jqueryui-touch-punch/jquery.ui.touch-punch.min.js');
$htmlHeadXtra[] = api_get_js('jquery.jsPlumb.all.js');
@ -350,6 +348,7 @@ if ($inATest) {
Display::return_icon('settings.png', get_lang('ModifyExercise'), '', ICON_SIZE_MEDIUM).'</a>';
$maxScoreAllQuestions = 0;
if ($showPagination === false) {
$questionList = $objExercise->selectQuestionList(true, true);
if (!empty($questionList)) {
foreach ($questionList as $questionItemId) {
@ -359,22 +358,33 @@ if ($inATest) {
}
}
}
}
echo '</div>';
if ($objExercise->added_in_lp()) {
echo Display::return_message(get_lang('AddedToLPCannotBeAccessed'), 'warning');
}
echo '<div class="alert alert-info">';
echo sprintf(
if ($editQuestion && $objQuestion->existsInAnotherExercises()) {
echo Display::return_message(
Display::returnFontAwesomeIcon('exclamation-triangle"')
.get_lang('ThisQuestionExistsInAnotherExercisesWarning'),
'warning',
false
);
}
$alert = '';
if ($showPagination === false) {
$alert .= sprintf(
get_lang('XQuestionsWithTotalScoreY'),
$objExercise->selectNbrQuestions(),
$nbrQuestions,
$maxScoreAllQuestions
);
}
if ($objExercise->random > 0) {
echo '<br />'.sprintf(get_lang('OnlyXQuestionsPickedRandomly'), $objExercise->random);
$alert .= '<br />'.sprintf(get_lang('OnlyXQuestionsPickedRandomly'), $objExercise->random);
}
echo '</div>';
echo Display::return_message($alert, 'normal', false);
} elseif (isset($_GET['newQuestion'])) {
// we are in create a new question from question pool not in a test
echo '<div class="actions">';
@ -399,7 +409,6 @@ if ($newQuestion || $editQuestion) {
$objExercise->edit_exercise_in_lp = true;
require 'question_admin.inc.php';
}
if ($editQuestion) {
// Question preview if teacher clicked the "switch to student"
if ($studentViewActive && $is_allowedToEdit) {

@ -27,8 +27,8 @@ if (!api_is_allowed_to_edit(null, true)) {
// the breadcrumbs
$interbreadcrumb[] = [
"url" => 'exercise.php?'.api_get_cidreq(),
"name" => get_lang('Exercises'),
'url' => 'exercise.php?'.api_get_cidreq(),
'name' => get_lang('Exercises'),
];
$is_allowedToEdit = api_is_allowed_to_edit(null, true);
// import file

@ -80,7 +80,7 @@ class Answer
// fills arrays
$objExercise = new Exercise($this->course_id);
$exerciseId = isset($_REQUEST['exerciseId']) ? $_REQUEST['exerciseId'] : null;
$objExercise->read($exerciseId);
$objExercise->read($exerciseId, false);
} else {
$objExercise = $exercise;
}

@ -1,6 +1,7 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CoreBundle\Component\Utils\ChamiloApi;
use Chamilo\CoreBundle\Entity\TrackEHotspot;
use ChamiloSession as Session;
@ -186,7 +187,6 @@ class Exercise
$this->text_when_finished = $object->text_when_finished;
$this->display_category_name = $object->display_category_name;
$this->pass_percentage = $object->pass_percentage;
$this->sessionId = $object->session_id;
$this->is_gradebook_locked = api_resource_is_locked_by_gradebook($id, LINK_EXERCISE);
$this->review_answers = (isset($object->review_answers) && $object->review_answers == 1) ? true : false;
$this->globalCategoryId = isset($object->global_category_id) ? $object->global_category_id : null;
@ -218,10 +218,9 @@ class Exercise
$this->force_edit_exercise_in_lp = api_get_configuration_value('force_edit_exercise_in_lp');
$this->edit_exercise_in_lp = true;
if ($this->exercise_was_added_in_lp) {
$this->edit_exercise_in_lp = $this->force_edit_exercise_in_lp == true;
} else {
$this->edit_exercise_in_lp = true;
}
if (!empty($object->end_time)) {
@ -763,7 +762,7 @@ class Exercise
$count = 0;
if (Database::num_rows($result)) {
$row = Database::fetch_array($result);
$count = $row['count'];
$count = (int) $row['count'];
}
return $count;
@ -962,29 +961,38 @@ class Exercise
$result['question_list'] = isset($question_list) ? $question_list : [];
$result['category_with_questions_list'] = isset($questions_by_category) ? $questions_by_category : [];
$parentsLoaded = [];
// Adding category info in the category list with question list:
if (!empty($questions_by_category)) {
$newCategoryList = [];
$em = Database::getManager();
foreach ($questions_by_category as $categoryId => $questionList) {
$cat = new TestCategory();
$cat = $cat->getCategory($categoryId);
if ($cat) {
$cat = (array) $cat;
$cat['iid'] = $cat['id'];
}
$categoryParentInfo = null;
// Parent is not set no loop here
if (!empty($cat['parent_id'])) {
if (isset($cat['parent_id']) && !empty($cat['parent_id'])) {
/** @var \Chamilo\CourseBundle\Entity\CQuizCategory $categoryEntity */
if (!isset($parentsLoaded[$cat['parent_id']])) {
$categoryEntity = $em->find('ChamiloCoreBundle:CQuizCategory', $cat['parent_id']);
$parentsLoaded[$cat['parent_id']] = $categoryEntity;
} else {
$categoryEntity = $parentsLoaded[$cat['parent_id']];
}
$repo = $em->getRepository('ChamiloCoreBundle:CQuizCategory');
$path = $repo->getPath($categoryEntity);
$index = 0;
if ($this->categoryMinusOne) {
//$index = 1;
}
/** @var \Chamilo\CourseBundle\Entity\CQuizCategory $categoryParent */
foreach ($path as $categoryParent) {
$visibility = $categoryParent->getVisibility();
@ -1024,7 +1032,7 @@ class Exercise
/**
* returns the array with the question ID list.
*
* @param bool $from_db Whether the results should be fetched in the database or just from memory
* @param bool $fromDatabase Whether the results should be fetched in the database or just from memory
* @param bool $adminView Whether we should return all questions (admin view) or
* just a list limited by the max number of random questions
*
@ -1032,9 +1040,9 @@ class Exercise
*
* @return array - question ID list
*/
public function selectQuestionList($from_db = false, $adminView = false)
public function selectQuestionList($fromDatabase = false, $adminView = false)
{
if ($from_db && !empty($this->id)) {
if ($fromDatabase && !empty($this->id)) {
$nbQuestions = $this->getQuestionCount();
$questionSelectionType = $this->getQuestionSelectionType();
@ -1076,7 +1084,7 @@ class Exercise
*/
public function selectNbrQuestions()
{
return sizeof($this->questionList);
return count($this->questionList);
}
/**
@ -1118,7 +1126,7 @@ class Exercise
// Random with no limit
if ($random == -1) {
$randomLimit = "ORDER BY RAND() ";
$randomLimit = ' ORDER BY RAND() ';
}
// Admin see the list in default order
@ -1163,6 +1171,33 @@ class Exercise
return $inList;
}
/**
* If current exercise has a question.
*
* @param int $questionId
*
* @return int
*/
public function hasQuestion($questionId)
{
$questionId = (int) $questionId;
$TBL_EXERCICE_QUESTION = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
$TBL_QUESTIONS = Database::get_course_table(TABLE_QUIZ_QUESTION);
$sql = "SELECT q.id
FROM $TBL_EXERCICE_QUESTION e
INNER JOIN $TBL_QUESTIONS q
ON (e.question_id = q.id AND e.c_id = q.c_id)
WHERE
q.id = $questionId AND
e.c_id = {$this->course_id} AND
e.exercice_id = ".$this->id;
$result = Database::query($sql);
return Database::num_rows($result) > 0;
}
/**
* changes the exercise title.
*
@ -1491,18 +1526,18 @@ class Exercise
$propagate_neg = (int) $this->propagate_neg;
$saveCorrectAnswers = isset($this->saveCorrectAnswers) && $this->saveCorrectAnswers ? 1 : 0;
$review_answers = isset($this->review_answers) && $this->review_answers ? 1 : 0;
$randomByCat = intval($this->randomByCat);
$randomByCat = (int) $this->randomByCat;
$text_when_finished = $this->text_when_finished;
$display_category_name = intval($this->display_category_name);
$pass_percentage = intval($this->pass_percentage);
$display_category_name = (int) $this->display_category_name;
$pass_percentage = (int) $this->pass_percentage;
$session_id = $this->sessionId;
// If direct we do not show results
$results_disabled = intval($this->results_disabled);
$results_disabled = (int) $this->results_disabled;
if ($feedback_type == EXERCISE_FEEDBACK_TYPE_DIRECT) {
$results_disabled = 0;
}
$expired_time = intval($this->expired_time);
$expired_time = (int) $this->expired_time;
// Exercise already exists
if ($id) {
@ -1913,46 +1948,7 @@ class Exercise
);
// Type of results display on the final page
$radios_results_disabled = [];
$radios_results_disabled[] = $form->createElement(
'radio',
'results_disabled',
null,
get_lang('ShowScoreAndRightAnswer'),
'0',
['id' => 'result_disabled_0']
);
$radios_results_disabled[] = $form->createElement(
'radio',
'results_disabled',
null,
get_lang('DoNotShowScoreNorRightAnswer'),
'1',
['id' => 'result_disabled_1', 'onclick' => 'check_results_disabled()']
);
$radios_results_disabled[] = $form->createElement(
'radio',
'results_disabled',
null,
get_lang('OnlyShowScore'),
'2',
['id' => 'result_disabled_2']
);
$radios_results_disabled[] = $form->createElement(
'radio',
'results_disabled',
null,
get_lang('ShowScoreEveryAttemptShowAnswersLastAttempt'),
'4',
['id' => 'result_disabled_4']
);
$form->addGroup(
$radios_results_disabled,
null,
get_lang('ShowResultsToStudents')
);
$this->setResultDisabledGroup($form);
// Type of questions disposition on page
$radios = [];
@ -1982,7 +1978,7 @@ class Exercise
$form->addGroup($radios, null, get_lang('QuestionsPerPage'));
} else {
// if is Direct feedback but has not questions we can allow to modify the question type
if ($this->selectNbrQuestions() == 0) {
if ($this->getQuestionCount() === 0) {
// feedback type
$radios_feedback = [];
$radios_feedback[] = $form->createElement(
@ -2017,32 +2013,8 @@ class Exercise
null,
[get_lang('FeedbackType'), get_lang('FeedbackDisplayOptions')]
);
$radios_results_disabled = [];
$radios_results_disabled[] = $form->createElement(
'radio',
'results_disabled',
null,
get_lang('ShowScoreAndRightAnswer'),
'0',
['id' => 'result_disabled_0']
);
$radios_results_disabled[] = $form->createElement(
'radio',
'results_disabled',
null,
get_lang('DoNotShowScoreNorRightAnswer'),
'1',
['id' => 'result_disabled_1', 'onclick' => 'check_results_disabled()']
);
$radios_results_disabled[] = $form->createElement(
'radio',
'results_disabled',
null,
get_lang('OnlyShowScore'),
'2',
['id' => 'result_disabled_2', 'onclick' => 'check_results_disabled()']
);
$form->addGroup($radios_results_disabled, null, get_lang('ShowResultsToStudents'), '');
$this->setResultDisabledGroup($form);
// Type of questions disposition on page
$radios = [];
@ -2056,37 +2028,8 @@ class Exercise
);
$form->addGroup($radios, null, get_lang('ExerciseType'));
} else {
// Show options freeze
$radios_results_disabled[] = $form->createElement(
'radio',
'results_disabled',
null,
get_lang('ShowScoreAndRightAnswer'),
'0',
['id' => 'result_disabled_0']
);
$radios_results_disabled[] = $form->createElement(
'radio',
'results_disabled',
null,
get_lang('DoNotShowScoreNorRightAnswer'),
'1',
['id' => 'result_disabled_1', 'onclick' => 'check_results_disabled()']
);
$radios_results_disabled[] = $form->createElement(
'radio',
'results_disabled',
null,
get_lang('OnlyShowScore'),
'2',
['id' => 'result_disabled_2', 'onclick' => 'check_results_disabled()']
);
$result_disable_group = $form->addGroup(
$radios_results_disabled,
null,
get_lang('ShowResultsToStudents')
);
$result_disable_group->freeze();
$group = $this->setResultDisabledGroup($form);
$group->freeze();
// we force the options to the DirectFeedback exercisetype
$form->addElement('hidden', 'exerciseFeedbackType', EXERCISE_FEEDBACK_TYPE_DIRECT);
@ -3075,7 +3018,7 @@ class Exercise
$myRemindList = []
) {
global $origin, $safe_lp_id, $safe_lp_item_id, $safe_lp_item_view_id;
$nbrQuestions = $this->get_count_question_list();
$nbrQuestions = $this->getQuestionCount();
$buttonList = [];
$html = $label = '';
$hotspot_get = isset($_POST['hotspot']) ? Security::remove_XSS($_POST['hotspot']) : null;
@ -3229,7 +3172,11 @@ class Exercise
*/
public function showTimeControlJS($time_left)
{
$time_left = intval($time_left);
$time_left = (int) $time_left;
$script = "redirectExerciseToResult();";
if ($this->type == ALL_ON_ONE_PAGE) {
$script = "save_now_all('validate');";
}
return "<script>
function openClockWarning() {
@ -3247,6 +3194,7 @@ class Exercise
send_form();
}
});
$('#clock_warning').dialog('open');
$('#counter_to_redirect').epiclock({
mode: $.epiclock.modes.countdown,
@ -3259,7 +3207,7 @@ class Exercise
function send_form() {
if ($('#exercise_form').length) {
save_now_all('validate');
$script
} else {
// In exercise_reminder.php
final_submit();
@ -3304,6 +3252,7 @@ class Exercise
* @param int $propagate_neg
* @param array $hotspot_delineation_result
* @param bool $showTotalScoreAndUserChoicesInLastAttempt
* @param bool $updateResults
*
* @todo reduce parameters of this function
*
@ -3320,7 +3269,8 @@ class Exercise
$show_result = true,
$propagate_neg = 0,
$hotspot_delineation_result = [],
$showTotalScoreAndUserChoicesInLastAttempt = true
$showTotalScoreAndUserChoicesInLastAttempt = true,
$updateResults = false
) {
$debug = false;
//needed in order to use in the exercise_attempt() for the time
@ -3411,8 +3361,8 @@ class Exercise
if ($answerType == MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY) {
$choiceTmp = $choice;
$choice = $choiceTmp["choice"];
$choiceDegreeCertainty = $choiceTmp["choiceDegreeCertainty"];
$choice = isset($choiceTmp['choice']) ? $choiceTmp['choice'] : '';
$choiceDegreeCertainty = isset($choiceTmp['choiceDegreeCertainty']) ? $choiceTmp['choiceDegreeCertainty'] : '';
}
if ($answerType == FREE_ANSWER ||
@ -3478,7 +3428,6 @@ class Exercise
if ($debug) {
error_log('Start answer loop ');
}
for ($answerId = 1; $answerId <= $nbrAnswers; $answerId++) {
$answer = $objAnswerTmp->selectAnswer($answerId);
$answerComment = $objAnswerTmp->selectComment($answerId);
@ -3589,8 +3538,10 @@ class Exercise
if (!empty($studentChoice)) {
if ($studentChoice == $answerCorrect) {
// correct answer and student is Unsure or PrettySur
if ($quiz_question_options[$studentChoiceDegree]['position'] >= 3
&& $quiz_question_options[$studentChoiceDegree]['position'] < 9) {
if (isset($quiz_question_options[$studentChoiceDegree]) &&
$quiz_question_options[$studentChoiceDegree]['position'] >= 3 &&
$quiz_question_options[$studentChoiceDegree]['position'] < 9
) {
$questionScore += $true_score;
} else {
// student ignore correct answer
@ -3681,21 +3632,15 @@ class Exercise
}
$studentChoice = isset($choice[$answerAutoId]) ? $choice[$answerAutoId] : '';
$real_answers[$answerId] = false;
if ($answerCorrect == $studentChoice) {
//$answerCorrect = 1;
$real_answers[$answerId] = true;
} else {
//$answerCorrect = 0;
$real_answers[$answerId] = false;
}
} else {
$studentChoice = isset($choice[$answerAutoId]) ? $choice[$answerAutoId] : '';
$real_answers[$answerId] = false;
if ($answerCorrect == $studentChoice) {
//$answerCorrect = 1;
$real_answers[$answerId] = true;
} else {
//$answerCorrect = 0;
$real_answers[$answerId] = false;
}
}
break;
@ -3711,31 +3656,27 @@ class Exercise
$studentChoice = isset($choice[$answerAutoId]) ? $choice[$answerAutoId] : null;
if ($answerCorrect == 1) {
$real_answers[$answerId] = false;
if ($studentChoice) {
$real_answers[$answerId] = true;
} else {
$real_answers[$answerId] = false;
}
} else {
$real_answers[$answerId] = true;
if ($studentChoice) {
$real_answers[$answerId] = false;
} else {
$real_answers[$answerId] = true;
}
}
} else {
$studentChoice = isset($choice[$answerAutoId]) ? $choice[$answerAutoId] : null;
if ($answerCorrect == 1) {
$real_answers[$answerId] = false;
if ($studentChoice) {
$real_answers[$answerId] = true;
} else {
$real_answers[$answerId] = false;
}
} else {
$real_answers[$answerId] = true;
if ($studentChoice) {
$real_answers[$answerId] = false;
} else {
$real_answers[$answerId] = true;
}
}
}
@ -3755,7 +3696,7 @@ class Exercise
}
$str = $answerFromDatabase = Database::result($result, 0, 'answer');
}
//ofaj
if ($saved_results == false && strpos($answerFromDatabase, 'font color') !== false) {
// the question is encoded like this
// [A] B [C] D [E] F::10,10,10@1
@ -4285,19 +4226,27 @@ class Exercise
// Try with id
if (isset($real_list[$i_answer_id])) {
$user_answer = Display::span($real_list[$i_answer_id]);
$user_answer = Display::span(
$real_list[$i_answer_id],
['style' => 'color: #008000; font-weight: bold;']
);
}
// Try with $i_answer_id_auto
if (empty($user_answer)) {
if (isset($real_list[$i_answer_id_auto])) {
$user_answer = Display::span($real_list[$i_answer_id_auto]);
$user_answer = Display::span(
$real_list[$i_answer_id_auto],
['style' => 'color: #008000; font-weight: bold;']
);
}
}
if ($this->showExpectedChoice()) {
if (isset($real_list[$i_answer_correct_answer])) {
$user_answer = Display::span($real_list[$i_answer_correct_answer]);
}
$user_answer = Display::span(
$real_list[$i_answer_correct_answer],
['style' => 'color: #008000; font-weight: bold;']
);
}
} else {
$user_answer = Display::span(
@ -4305,7 +4254,9 @@ class Exercise
['style' => 'color: #FF0000; text-decoration: line-through;']
);
if ($this->showExpectedChoice()) {
$user_answer = '';
if (isset($real_list[$s_user_answer])) {
$user_answer = Display::span($real_list[$s_user_answer]);
}
}
}
}
@ -4324,6 +4275,12 @@ class Exercise
}
}
if ($results_disabled == RESULT_DISABLE_SHOW_ONLY_IN_CORRECT_ANSWER) {
if ($s_user_answer != $i_answer_correct_answer) {
continue;
}
}
if ($show_result) {
if ($this->showExpectedChoice() == false &&
$showTotalScoreAndUserChoicesInLastAttempt === false
@ -4613,7 +4570,7 @@ class Exercise
if ($debug) {
error_log('Showing questions $from '.$from);
}
if ($from == 'exercise_result') {
if ($from === 'exercise_result') {
//display answers (if not matching type, or if the answer is correct)
if (!in_array($answerType, [MATCHING, DRAGGABLE, MATCHING_DRAGGABLE]) ||
$answerCorrect
@ -4744,7 +4701,6 @@ class Exercise
// force to show whether the choice is correct or not
$showTotalScoreAndUserChoicesInLastAttempt = true;
ExerciseShowFunctions::display_hotspot_answer(
$feedback_type,
++$correctAnswerId,
@ -4884,7 +4840,6 @@ class Exercise
if ($debug > 0) {
error_log(__LINE__.' - answerId is >1 so we\'re probably in OAR', 0);
}
$inter = $result['success'];
$delineation_cord = $objAnswerTmp->selectHotspotCoordinates($answerId);
$poly_answer = convert_coordinates($delineation_cord, '|');
$max_coord = poly_get_max($poly_user, $poly_answer);
@ -5141,26 +5096,6 @@ class Exercise
case HOT_SPOT_DELINEATION:
$user_answer = $user_array;
if ($next) {
//$tbl_track_e_hotspot = Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTSPOT);
// Save into db
/* $sql = "INSERT INTO $tbl_track_e_hotspot (
* hotspot_user_id,
* hotspot_course_code,
* hotspot_exe_id,
* hotspot_question_id,
* hotspot_answer_id,
* hotspot_correct,
* hotspot_coordinate
* )
VALUES (
* '".Database::escape_string($_user['user_id'])."',
* '".Database::escape_string($_course['id'])."',
* '".Database::escape_string($exeId)."', '".Database::escape_string($questionId)."',
* '".Database::escape_string($answerId)."',
* '".Database::escape_string($studentChoice)."',
* '".Database::escape_string($user_array)."')";
$result = Database::query($sql,__FILE__,__LINE__);
*/
$user_answer = $user_array;
// we compare only the delineation not the other points
$answer_question = $_SESSION['hotspot_coord'][1];
@ -5253,11 +5188,6 @@ class Exercise
if ($debug > 0) {
error_log(__LINE__.' - answerId is >1 so we\'re probably in OAR', 0);
}
//check the intersection between the oar and the user
//echo 'user'; print_r($x_user_list); print_r($y_user_list);
//echo 'official';print_r($x_list);print_r($y_list);
//$result = get_intersection_data($x_list,$y_list,$x_user_list,$y_user_list);
$inter = $result['success'];
$delineation_cord = $objAnswerTmp->selectHotspotCoordinates($answerId);
$poly_answer = convert_coordinates($delineation_cord, '|');
$max_coord = poly_get_max($poly_user, $poly_answer);
@ -5315,7 +5245,6 @@ class Exercise
)
);
echo '</tr>';
break;
case ANNOTATION:
ExerciseShowFunctions::displayAnnotationAnswer(
@ -5627,20 +5556,22 @@ class Exercise
) {
if ($choice != 0) {
$reply = array_keys($choice);
for ($i = 0; $i < sizeof($reply); $i++) {
$countReply = count($reply);
for ($i = 0; $i < $countReply; $i++) {
$chosenAnswer = $reply[$i];
if ($answerType == MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY) {
if ($choiceDegreeCertainty != 0) {
$replyDegreeCertainty = array_keys($choiceDegreeCertainty);
$answerDegreeCertainty = $replyDegreeCertainty[$i];
$answerDegreeCertainty = isset($replyDegreeCertainty[$i]) ? $replyDegreeCertainty[$i] : '';
$answerValue = isset($choiceDegreeCertainty[$answerDegreeCertainty]) ? $choiceDegreeCertainty[$answerDegreeCertainty] : '';
Event::saveQuestionAttempt(
$questionScore,
$chosenAnswer.':'.$choice[$chosenAnswer].':'.
$choiceDegreeCertainty[$answerDegreeCertainty],
$chosenAnswer.':'.$choice[$chosenAnswer].':'.$answerValue,
$quesId,
$exeId,
$i,
$this->id
$this->id,
$updateResults
);
}
} else {
@ -5650,7 +5581,8 @@ class Exercise
$quesId,
$exeId,
$i,
$this->id
$this->id,
$updateResults
);
}
if ($debug) {
@ -5776,7 +5708,7 @@ class Exercise
}
} else {
if ($debug) {
error_log("Empty: exerciseResultCoordinates");
error_log('Empty: exerciseResultCoordinates');
}
}
Event::saveQuestionAttempt($questionScore, implode('|', $answer), $quesId, $exeId, 0, $this->id);
@ -6326,9 +6258,9 @@ class Exercise
}
// 4. We check if the student have attempts
if ($isVisible) {
$exerciseAttempts = $this->selectAttempts();
if ($isVisible) {
if ($exerciseAttempts > 0) {
$attemptCount = Event::get_attempt_count_not_finished(
api_get_user_id(),
@ -6346,6 +6278,19 @@ class Exercise
);
$isVisible = false;
}
} else {
$isLimitReached = ExerciseLib::isQuestionsLimitPerDayReached(
api_get_user_id(),
$this->selectNbrQuestions(),
api_get_course_int_id(),
api_get_session_id()
);
if ($isLimitReached) {
$maxQuestionsAnswered = (int) api_get_course_setting('quiz_question_limit_per_day');
$message = sprintf(get_lang('QuizQuestionsLimitPerDayXReached'), $maxQuestionsAnswered);
$isVisible = false;
}
}
}
@ -6595,7 +6540,7 @@ class Exercise
if ($isRandomByCategory == 2) {
$tabCategoryQuestions = TestCategory::sortTabByBracketLabel($tabCategoryQuestions);
}
while (list($cat_id, $tabquestion) = each($tabCategoryQuestions)) {
foreach ($tabCategoryQuestions as $tabquestion) {
$number_of_random_question = $this->random;
if ($this->random == -1) {
$number_of_random_question = count($this->questionList);
@ -6867,21 +6812,6 @@ class Exercise
return $html;
}
/**
* @return int
*/
public function get_count_question_list()
{
// Real question count
$question_count = 0;
$question_list = $this->get_question_list();
if (!empty($question_list)) {
$question_count = count($question_list);
}
return $question_count;
}
/**
* Get categories added in the exercise--category matrix.
*
@ -7348,15 +7278,9 @@ class Exercise
}
$attributes = ['id' => 'remind_list['.$questionId.']'];
if (is_array($remindList) && in_array($questionId, $remindList)) {
//$attributes['checked'] = 1;
//$remind_highlight = ' remind_highlight ';
}
// Showing the question
$exercise_actions = null;
echo '<a id="questionanchor'.$questionId.'"></a><br />';
echo '<div id="question_div_'.$questionId.'" class="main_question '.$remind_highlight.'" >';
@ -7492,9 +7416,9 @@ class Exercise
INNER JOIN $TBL_QUESTIONS q
ON (e.question_id = q.id AND e.c_id = q.c_id)
INNER JOIN $categoryRelTable catRel
ON (catRel.question_id = e.question_id)
ON (catRel.question_id = e.question_id AND catRel.c_id = e.c_id)
INNER JOIN $categoryTable cat
ON (cat.id = catRel.category_id)
ON (cat.id = catRel.category_id AND cat.c_id = e.c_id)
WHERE
e.c_id = {$this->course_id} AND
e.exercice_id = ".intval($this->id);
@ -7550,7 +7474,7 @@ class Exercise
}
// here we've got an array with first key, the category_id, second key, score of question for this cat
while (list($key, $tab_scores) = each($tab_categories_scores)) {
foreach ($tab_categories_scores as $tab_scores) {
rsort($tab_scores);
for ($i = 0; $i < min($numberRandomQuestions, count($tab_scores)); $i++) {
$out_max_score += $tab_scores[$i];
@ -7614,8 +7538,8 @@ class Exercise
*/
public function getExercisesByCourseSession($courseId, $sessionId)
{
$courseId = intval($courseId);
$sessionId = intval($sessionId);
$courseId = (int) $courseId;
$sessionId = (int) $sessionId;
$tbl_quiz = Database::get_course_table(TABLE_QUIZ_TEST);
$sql = "SELECT * FROM $tbl_quiz cq
@ -7649,7 +7573,9 @@ class Exercise
return [];
}
$sessionId = intval($sessionId);
$sessionId = (int) $sessionId;
$courseId = (int) $courseId;
$ids = is_array($quizId) ? $quizId : [$quizId];
$ids = array_map('intval', $ids);
$ids = implode(',', $ids);
@ -7816,7 +7742,6 @@ class Exercise
);
$corrects = [];
foreach ($attempts as $attempt) {
foreach ($attempt['question_list'] as $answers) {
foreach ($answers as $answer) {
@ -7916,8 +7841,10 @@ class Exercise
$hideLabel = api_get_configuration_value('exercise_hide_label');
$label = '<div class="rib rib-'.$class.'">
<h3>'.$scoreLabel.'</h3>
</div>
<h4>'.get_lang('Score').': '.$result.'</h4>';
</div>';
if (!empty($result)) {
$label .= '<h4>'.get_lang('Score').': '.$result.'</h4>';
}
if ($hideLabel === true) {
$answerUsed = (int) $array['used'];
$answerMissing = (int) $array['missing'] - $answerUsed;
@ -7942,13 +7869,16 @@ class Exercise
</div>'
;
} else {
return '<div class="ribbon">
$html = '<div class="ribbon">
<div class="rib rib-'.$class.'">
<h3>'.$scoreLabel.'</h3>
</div>
<h4>'.get_lang('Score').': '.$result.'</h4>
</div>'
;
</div>';
if (!empty($result)) {
$html .= '<h4>'.get_lang('Score').': '.$result.'</h4>';
}
$html .= '</div>';
return $html;
}
}
@ -7992,6 +7922,42 @@ class Exercise
return strip_tags(api_html_entity_decode($this->title));
}
/**
* @param int $start
* @param int $lenght
*
* @return array
*/
public function getQuestionForTeacher($start = 0, $lenght = 10)
{
$start = (int) $start;
if ($start < 0) {
$start = 0;
}
$lenght = (int) $lenght;
$TBL_EXERCICE_QUESTION = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
$TBL_QUESTIONS = Database::get_course_table(TABLE_QUIZ_QUESTION);
$sql = "SELECT DISTINCT e.question_id, e.question_order
FROM $TBL_EXERCICE_QUESTION e
INNER JOIN $TBL_QUESTIONS q
ON (e.question_id = q.id AND e.c_id = q.c_id)
WHERE
e.c_id = {$this->course_id} AND
e.exercice_id = '".$this->id."'
ORDER BY question_order
LIMIT $start, $lenght
";
$result = Database::query($sql);
$questionList = [];
while ($object = Database::fetch_object($result)) {
$questionList[$object->question_order] = $object->question_id;
}
return $questionList;
}
/**
* Gets the question list ordered by the question_order setting (drag and drop).
*
@ -8201,17 +8167,17 @@ class Exercise
'<table width="730" height="136" border="0" cellpadding="3" cellspacing="3">';
$msg .= $open_question_list;
$msg .= '</table><br />';
$msg1 = str_replace("#exercise#", $this->exercise, $msg);
$msg = str_replace("#firstName#", $user_info['firstname'], $msg1);
$msg1 = str_replace("#lastName#", $user_info['lastname'], $msg);
$msg = str_replace("#mail#", $user_info['email'], $msg1);
$msg = str_replace("#course#", $courseInfo['name'], $msg1);
$msg = str_replace("#exercise#", $this->exercise, $msg);
$msg = str_replace("#firstName#", $user_info['firstname'], $msg);
$msg = str_replace("#lastName#", $user_info['lastname'], $msg);
$msg = str_replace("#mail#", $user_info['email'], $msg);
$msg = str_replace("#course#", $courseInfo['name'], $msg);
if ($origin != 'learnpath') {
$msg .= '<br /><a href="#url#">'.get_lang('ClickToCommentAndGiveFeedback').'</a>';
}
$msg1 = str_replace("#url#", $url_email, $msg);
$mail_content = $msg1;
$msg = str_replace("#url#", $url_email, $msg);
$subject = get_lang('OpenQuestionsAttempted');
if (!empty($teachers)) {
@ -8219,7 +8185,7 @@ class Exercise
MessageManager::send_message_simple(
$user_id,
$subject,
$mail_content
$msg
);
}
}
@ -8355,4 +8321,95 @@ class Exercise
}
$this->mediaList = $mediaList;
}
/**
* @param FormValidator $form
*
* @return HTML_QuickForm_group
*/
private function setResultDisabledGroup(FormValidator $form)
{
$resultDisabledGroup = [];
$resultDisabledGroup[] = $form->createElement(
'radio',
'results_disabled',
null,
get_lang('ShowScoreAndRightAnswer'),
'0',
['id' => 'result_disabled_0']
);
$resultDisabledGroup[] = $form->createElement(
'radio',
'results_disabled',
null,
get_lang('DoNotShowScoreNorRightAnswer'),
'1',
['id' => 'result_disabled_1', 'onclick' => 'check_results_disabled()']
);
$resultDisabledGroup[] = $form->createElement(
'radio',
'results_disabled',
null,
get_lang('OnlyShowScore'),
'2',
['id' => 'result_disabled_2', 'onclick' => 'check_results_disabled()']
);
if ($this->selectFeedbackType() == EXERCISE_FEEDBACK_TYPE_DIRECT) {
$group = $form->addGroup(
$resultDisabledGroup,
null,
get_lang('ShowResultsToStudents')
);
return $group;
}
$resultDisabledGroup[] = $form->createElement(
'radio',
'results_disabled',
null,
get_lang('ShowScoreEveryAttemptShowAnswersLastAttempt'),
'4',
['id' => 'result_disabled_4']
);
$resultDisabledGroup[] = $form->createElement(
'radio',
'results_disabled',
null,
get_lang('DontShowScoreOnlyWhenUserFinishesAllAttemptsButShowFeedbackEachAttempt'),
'5',
['id' => 'result_disabled_5', 'onclick' => 'check_results_disabled()']
);
$resultDisabledGroup[] = $form->createElement(
'radio',
'results_disabled',
null,
get_lang('ExerciseRankingMode'),
'6',
['id' => 'result_disabled_6']
);
$resultDisabledGroup[] = $form->createElement(
'radio',
'results_disabled',
null,
get_lang('ExerciseShowOnlyGlobalScoreAndCorrectAnswers'),
'7',
['id' => 'result_disabled_7']
);
$group = $form->addGroup(
$resultDisabledGroup,
null,
get_lang('ShowResultsToStudents')
);
return $group;
}
}

@ -27,6 +27,9 @@ $htmlHeadXtra[] = api_get_css_asset('qtip2/jquery.qtip.min.css');
// Access control
api_protect_course_script(true);
$limitTeacherAccess = api_get_configuration_value('limit_exercise_teacher_access');
require_once 'hotpotatoes.lib.php';
/* Constants and variables */
@ -50,7 +53,7 @@ $TBL_EXERCISES = Database::get_course_table(TABLE_QUIZ_TEST);
$TBL_TRACK_EXERCISES = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
// document path
$documentPath = api_get_path(SYS_COURSE_PATH).$courseInfo['path']."/document";
$documentPath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document';
// picture path
$picturePath = $documentPath.'/images';
// audio path
@ -62,10 +65,9 @@ $exercisePath = api_get_self();
$exfile = explode('/', $exercisePath);
$exfile = strtolower($exfile[sizeof($exfile) - 1]);
$exercisePath = substr($exercisePath, 0, strpos($exercisePath, $exfile));
$exercisePath = $exercisePath."exercise.php";
$exercisePath = $exercisePath.'exercise.php';
// Clear the exercise session
Session::erase('objExercise');
Session::erase('objQuestion');
Session::erase('objAnswer');
@ -82,9 +84,9 @@ $choice = isset($_REQUEST['choice']) ? Security::remove_XSS($_REQUEST['choice'])
$hpchoice = isset($_REQUEST['hpchoice']) ? Security::remove_XSS($_REQUEST['hpchoice']) : null;
$exerciseId = isset($_REQUEST['exerciseId']) ? (int) $_REQUEST['exerciseId'] : null;
$file = isset($_REQUEST['file']) ? Database::escape_string($_REQUEST['file']) : null;
$learnpath_id = isset($_REQUEST['learnpath_id']) ? intval($_REQUEST['learnpath_id']) : null;
$learnpath_item_id = isset($_REQUEST['learnpath_item_id']) ? intval($_REQUEST['learnpath_item_id']) : null;
$page = isset($_REQUEST['page']) ? intval($_REQUEST['page']) : null;
$learnpath_id = isset($_REQUEST['learnpath_id']) ? (int) $_REQUEST['learnpath_id'] : null;
$learnpath_item_id = isset($_REQUEST['learnpath_item_id']) ? (int) $_REQUEST['learnpath_item_id'] : null;
$page = isset($_REQUEST['page']) ? (int) $_REQUEST['page'] : null;
if ($page < 0) {
$page = 1;
@ -106,7 +108,10 @@ if (api_get_course_setting('enable_exercise_auto_launch') == 1 &&
$nameTools = get_lang('Exercises');
$errorXmlExport = null;
if ($is_allowedToEdit && !empty($choice) && $choice == 'exportqti2') {
if ($is_allowedToEdit && !empty($choice) && $choice === 'exportqti2') {
if ($limitTeacherAccess && !api_is_platform_admin()) {
api_not_allowed(true);
}
require_once api_get_path(SYS_CODE_PATH).'exercise/export/qti2/qti2_export.php';
$export = export_exercise_to_qti($exerciseId, true);
@ -142,10 +147,8 @@ if ($is_allowedToEdit && !empty($choice) && $choice == 'exportqti2') {
if ($origin != 'learnpath') {
//so we are not in learnpath tool
Display :: display_header($nameTools, get_lang('Exercise'));
if (isset($_GET['message'])) {
if (in_array($_GET['message'], ['ExerciseEdited'])) {
echo Display::return_message(get_lang($_GET['message']), 'confirmation');
}
if (isset($_GET['message']) && in_array($_GET['message'], ['ExerciseEdited'])) {
echo Display::return_message(get_lang('ExerciseEdited'), 'confirmation');
}
} else {
Display::display_reduced_header();
@ -153,6 +156,15 @@ if ($origin != 'learnpath') {
Event::event_access_tool(TOOL_QUIZ);
$logInfo = [
'tool' => TOOL_QUIZ,
'tool_id' => (int) $exerciseId,
'tool_id_detail' => 0,
'action' => isset($_REQUEST['learnpath_id']) ? 'learnpath_id' : '',
'action_details' => isset($_REQUEST['learnpath_id']) ? (int) $_REQUEST['learnpath_id'] : '',
];
Event::registerLog($logInfo);
// Tool introduction
Display::display_introduction_section(TOOL_QUIZ);
@ -169,6 +181,10 @@ if ($is_allowedToEdit) {
if ($choice === 'clean_all_test') {
$check = Security::check_token('get');
if ($check) {
if ($limitTeacherAccess && !api_is_platform_admin()) {
api_not_allowed(true);
}
// list of exercises in a course/session
// we got variable $courseId $courseInfo session api_get_session_id()
$exerciseList = ExerciseLib::get_all_exercises_for_course_id(
@ -221,6 +237,10 @@ if ($is_allowedToEdit) {
case 'delete':
// deletes an exercise
if ($exercise_action_locked == false) {
if ($limitTeacherAccess && !api_is_platform_admin()) {
// Teacher cannot delete an exercise
break;
}
$objExerciseTmp->delete();
$link_info = GradebookUtils::isResourceInCourseGradebook(
api_get_course_id(),
@ -235,6 +255,11 @@ if ($is_allowedToEdit) {
}
break;
case 'enable':
if ($limitTeacherAccess && !api_is_platform_admin()) {
// Teacher change exercise
break;
}
// enables an exercise
if (empty($sessionId)) {
$objExerciseTmp->enable();
@ -257,6 +282,10 @@ if ($is_allowedToEdit) {
echo Display::return_message(get_lang('VisibilityChanged'), 'confirmation');
break;
case 'disable':
if ($limitTeacherAccess && !api_is_platform_admin()) {
// Teacher change exercise
break;
}
// disables an exercise
if (empty($sessionId)) {
$objExerciseTmp->disable();
@ -300,7 +329,12 @@ if ($is_allowedToEdit) {
);
break;
case 'clean_results':
//clean student results
if ($limitTeacherAccess && !api_is_platform_admin()) {
// Teacher change exercise
break;
}
// Clean student results
if ($exercise_action_locked == false) {
$quantity_results_deleted = $objExerciseTmp->cleanResults(true);
$title = $objExerciseTmp->selectTitle();
@ -331,6 +365,10 @@ if ($is_allowedToEdit) {
if (!empty($hpchoice)) {
switch ($hpchoice) {
case 'delete':
if ($limitTeacherAccess && !api_is_platform_admin()) {
// Teacher change exercise
break;
}
// deletes an exercise
$imgparams = [];
$imgcount = 0;
@ -360,7 +398,12 @@ if ($is_allowedToEdit) {
}
break;
case 'enable': // enables an exercise
$newVisibilityStatus = "1"; //"visible"
if ($limitTeacherAccess && !api_is_platform_admin()) {
// Teacher change exercise
break;
}
$newVisibilityStatus = '1'; //"visible"
$query = "SELECT id FROM $TBL_DOCUMENT
WHERE c_id = $courseId AND path='".Database::escape_string($file)."'";
$res = Database::query($query);
@ -376,7 +419,11 @@ if ($is_allowedToEdit) {
break;
case 'disable': // disables an exercise
$newVisibilityStatus = "0"; //"invisible"
if ($limitTeacherAccess && !api_is_platform_admin()) {
// Teacher change exercise
break;
}
$newVisibilityStatus = '0'; //"invisible"
$query = "SELECT id FROM $TBL_DOCUMENT
WHERE c_id = $courseId AND path='".Database::escape_string($file)."'";
$res = Database::query($query);
@ -410,8 +457,7 @@ HotPotGCt($documentPath, 1, $userId);
//condition for the session
$course_code = api_get_course_id();
$session_id = api_get_session_id();
$condition_session = api_get_session_condition($session_id, true, true);
$condition_session = api_get_session_condition($sessionId, true, true);
// Only for administrators
if ($is_allowedToEdit) {
@ -451,14 +497,15 @@ if ($is_allowedToEdit) {
$res = Database::query($sql);
$hp_count = Database :: num_rows($res);
} else {
$sql = "SELECT * FROM $TBL_DOCUMENT d, $TBL_ITEM_PROPERTY ip
$sql = "SELECT * FROM $TBL_DOCUMENT d
INNER JOIN $TBL_ITEM_PROPERTY ip
ON (d.id = ip.ref AND d.c_id = ip.c_id)
WHERE
d.id = ip.ref AND
ip.tool = '".TOOL_DOCUMENT."' AND
d.path LIKE '".Database::escape_string($uploadPath.'/%/%')."' AND
ip.visibility ='1' AND
d.c_id = ".$courseId." AND
ip.c_id = ".$courseId;
d.c_id = $courseId AND
ip.c_id = $courseId";
$res = Database::query($sql);
$hp_count = Database::num_rows($res);
}
@ -487,7 +534,7 @@ if ($is_allowedToEdit && $origin != 'learnpath') {
echo '<a href="'.api_get_path(WEB_CODE_PATH).'exercise/aiken.php?'.api_get_cidreq().'">'.Display::return_icon('import_aiken.png', get_lang('ImportAikenQuiz'), '', ICON_SIZE_MEDIUM).'</a>';
echo '<a href="'.api_get_path(WEB_CODE_PATH).'exercise/upload_exercise.php?'.api_get_cidreq().'">'.Display::return_icon('import_excel.png', get_lang('ImportExcelQuiz'), '', ICON_SIZE_MEDIUM).'</a>';
echo Display::url(
$cleanAll = Display::url(
Display::return_icon(
'clean_all.png',
get_lang('CleanAllStudentsResultsForAllTests'),
@ -502,6 +549,14 @@ if ($is_allowedToEdit && $origin != 'learnpath') {
'data-target' => '#confirm-delete',
]
);
if ($limitTeacherAccess) {
if (api_is_platform_admin()) {
echo $cleanAll;
}
} else {
echo $cleanAll;
}
}
if ($is_allowedToEdit) {
@ -527,7 +582,6 @@ if ($total > $limit) {
}
$i = 1;
$online_icon = Display::return_icon(
'online.png',
get_lang('Visible'),
@ -541,7 +595,6 @@ $offline_icon = Display::return_icon(
$exerciseList = [];
$list_ordered = null;
while ($row = Database::fetch_array($result, 'ASSOC')) {
$exerciseList[$row['iid']] = $row;
}
@ -726,7 +779,7 @@ if (!empty($exerciseList)) {
$count_exercise_not_validated = (int) Event::count_exercise_result_not_validated(
$my_exercise_id,
$courseId,
$session_id
$sessionId
);
$move = Display::return_icon(
@ -755,7 +808,7 @@ if (!empty($exerciseList)) {
$sqlresult = Database::query($sql);
$rowi = intval(Database :: result($sqlresult, 0, 0));
if ($session_id == $row['session_id']) {
if ($sessionId == $row['session_id']) {
// Questions list
$actions = Display::url(
Display::return_icon('edit.png', get_lang('Edit'), '', ICON_SIZE_SMALL),
@ -763,15 +816,29 @@ if (!empty($exerciseList)) {
);
// Test settings
$actions .= Display::url(
$settings = Display::url(
Display::return_icon('settings.png', get_lang('Configure'), '', ICON_SIZE_SMALL),
'exercise_admin.php?'.api_get_cidreq().'&exerciseId='.$row['id']
);
if ($limitTeacherAccess && !api_is_platform_admin()) {
$settings = '';
}
$actions .= $settings;
// Exercise results
$actions .= '<a href="exercise_report.php?'.api_get_cidreq().'&exerciseId='.$row['id'].'">'.
$resultsLink = '<a href="exercise_report.php?'.api_get_cidreq().'&exerciseId='.$row['id'].'">'.
Display::return_icon('test_results.png', get_lang('Results'), '', ICON_SIZE_SMALL).'</a>';
if ($limitTeacherAccess) {
if (api_is_platform_admin()) {
$actions .= $resultsLink;
}
} else {
// Exercise results
$actions .= $resultsLink;
}
// Auto launch
if ($autoLaunchAvailable) {
$autoLaunch = $exercise->getAutoLaunch();
@ -810,7 +877,7 @@ if (!empty($exerciseList)) {
// Clean exercise
if ($locked == false) {
$actions .= Display::url(
$clean = Display::url(
Display::return_icon(
'clean.png',
get_lang('CleanStudentResults'),
@ -824,7 +891,7 @@ if (!empty($exerciseList)) {
]
);
} else {
$actions .= Display::return_icon(
$clean = Display::return_icon(
'clean_na.png',
get_lang('ResourceLockedByGradebook'),
'',
@ -832,10 +899,16 @@ if (!empty($exerciseList)) {
);
}
if ($limitTeacherAccess && !api_is_platform_admin()) {
$clean = '';
}
$actions .= $clean;
// Visible / invisible
// Check if this exercise was added in a LP
if ($exercise->exercise_was_added_in_lp == true) {
$actions .= Display::return_icon(
$visibility = Display::return_icon(
'invisible.png',
get_lang('AddedToLPCannotBeAccessed'),
'',
@ -843,7 +916,7 @@ if (!empty($exerciseList)) {
);
} else {
if ($row['active'] == 0 || $visibility == 0) {
$actions .= Display::url(
$visibility = Display::url(
Display::return_icon(
'invisible.png',
get_lang('Activate'),
@ -854,7 +927,7 @@ if (!empty($exerciseList)) {
);
} else {
// else if not active
$actions .= Display::url(
$visibility = Display::url(
Display::return_icon(
'visible.png',
get_lang('Deactivate'),
@ -865,8 +938,15 @@ if (!empty($exerciseList)) {
);
}
}
if ($limitTeacherAccess && !api_is_platform_admin()) {
$visibility = '';
}
$actions .= $visibility;
// Export qti ...
$actions .= Display::url(
$export = Display::url(
Display::return_icon(
'export_qti2.png',
'IMS/QTI',
@ -875,6 +955,12 @@ if (!empty($exerciseList)) {
),
'exercise.php?choice=exportqti2&exerciseId='.$row['id'].'&'.api_get_cidreq()
);
if ($limitTeacherAccess && !api_is_platform_admin()) {
$export = '';
}
$actions .= $export;
} else {
// not session
$actions = Display::return_icon(
@ -884,7 +970,7 @@ if (!empty($exerciseList)) {
// Check if this exercise was added in a LP
if ($exercise->exercise_was_added_in_lp == true) {
$actions .= Display::return_icon(
$visiblity = Display::return_icon(
'invisible.png',
get_lang('AddedToLPCannotBeAccessed'),
'',
@ -892,7 +978,7 @@ if (!empty($exerciseList)) {
);
} else {
if ($row['active'] == 0 || $visibility == 0) {
$actions .= Display::url(
$visiblity = Display::url(
Display::return_icon(
'invisible.png',
get_lang('Activate'),
@ -903,7 +989,7 @@ if (!empty($exerciseList)) {
);
} else {
// else if not active
$actions .= Display::url(
$visiblity = Display::url(
Display::return_icon(
'visible.png',
get_lang('Deactivate'),
@ -915,6 +1001,12 @@ if (!empty($exerciseList)) {
}
}
if ($limitTeacherAccess && !api_is_platform_admin()) {
$visiblity = '';
}
$actions .= $visiblity;
$actions .= '<a href="exercise_report.php?'.api_get_cidreq().'&exerciseId='.$row['id'].'">'.
Display::return_icon('test_results.png', get_lang('Results'), '', ICON_SIZE_SMALL).'</a>';
$actions .= Display::url(
@ -928,9 +1020,10 @@ if (!empty($exerciseList)) {
}
// Delete
if ($session_id == $row['session_id']) {
$delete = '';
if ($sessionId == $row['session_id']) {
if ($locked == false) {
$actions .= Display::url(
$delete = Display::url(
Display::return_icon(
'delete.png',
get_lang('Delete'),
@ -944,7 +1037,7 @@ if (!empty($exerciseList)) {
]
);
} else {
$actions .= Display::return_icon(
$delete = Display::return_icon(
'delete_na.png',
get_lang('ResourceLockedByGradebook'),
'',
@ -953,6 +1046,12 @@ if (!empty($exerciseList)) {
}
}
if ($limitTeacherAccess && !api_is_platform_admin()) {
$delete = '';
}
$actions .= $delete;
// Number of questions
$random_label = null;
if ($row['random'] > 0 || $row['random'] == -1) {
@ -966,9 +1065,9 @@ if (!empty($exerciseList)) {
$my_exercise_id,
$random_number_of_question
);
$number_of_questions = $nbQuestionsTotal." ";
$number_of_questions .= ($nbQuestionsTotal > 1) ? get_lang("QuestionsLowerCase") : get_lang("QuestionLowerCase");
$number_of_questions .= " - ";
$number_of_questions = $nbQuestionsTotal.' ';
$number_of_questions .= ($nbQuestionsTotal > 1) ? get_lang('QuestionsLowerCase') : get_lang('QuestionLowerCase');
$number_of_questions .= ' - ';
$number_of_questions .= min(TestCategory::getNumberMaxQuestionByCat($my_exercise_id), $random_number_of_question).' '.get_lang('QuestionByCategory');
} else {
$random_label = ' ('.get_lang('Random').') ';
@ -981,10 +1080,6 @@ if (!empty($exerciseList)) {
} else {
$number_of_questions = $rowi;
}
//Attempts
//$attempts = ExerciseLib::get_count_exam_results($row['id']).' '.get_lang('Attempts');
//$item .= Display::tag('td',$attempts);
$item .= Display::tag('td', $number_of_questions);
} else {
// Student only.
@ -1042,7 +1137,16 @@ if (!empty($exerciseList)) {
// Exam is ready to be taken
if ($is_actived_time) {
// Show results 697 $attempt_text = get_lang('LatestAttempt').' : ';
if ($my_result_disabled == 0 || $my_result_disabled == 2) {
if (
in_array(
$my_result_disabled,
[
RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS,
RESULT_DISABLE_SHOW_SCORE_ONLY,
RESULT_DISABLE_RANKING,
]
)
) {
//More than one attempt
if ($num > 0) {
$row_track = Database :: fetch_array($qryres);
@ -1064,10 +1168,18 @@ if (!empty($exerciseList)) {
$start_time = api_strtotime($row['start_time'], 'UTC');
$end_time = api_strtotime($row['end_time'], 'UTC');
if ($today < $start_time) {
$attempt_text = sprintf(get_lang('ExerciseWillBeActivatedFromXToY'), api_convert_and_format_date($row['start_time']), api_convert_and_format_date($row['end_time']));
$attempt_text = sprintf(
get_lang('ExerciseWillBeActivatedFromXToY'),
api_convert_and_format_date($row['start_time']),
api_convert_and_format_date($row['end_time'])
);
} else {
if ($today > $end_time) {
$attempt_text = sprintf(get_lang('ExerciseWasActivatedFromXToY'), api_convert_and_format_date($row['start_time']), api_convert_and_format_date($row['end_time']));
$attempt_text = sprintf(
get_lang('ExerciseWasActivatedFromXToY'),
api_convert_and_format_date($row['start_time']),
api_convert_and_format_date($row['end_time'])
);
}
}
} else {
@ -1089,7 +1201,16 @@ if (!empty($exerciseList)) {
} else {
// Normal behaviour.
// Show results.
if ($my_result_disabled == 0 || $my_result_disabled == 2) {
if (
in_array(
$my_result_disabled,
[
RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS,
RESULT_DISABLE_SHOW_SCORE_ONLY,
RESULT_DISABLE_RANKING,
]
)
) {
if ($num > 0) {
$row_track = Database :: fetch_array($qryres);
$attempt_text = get_lang('LatestAttempt').' : ';
@ -1101,7 +1222,6 @@ if (!empty($exerciseList)) {
$attempt_text = get_lang('NotAttempted');
}
} else {
//$attempt_text = get_lang('CantShowResults');
$attempt_text = '-';
}
}
@ -1125,6 +1245,12 @@ if (!empty($exerciseList)) {
}
if ($is_allowedToEdit) {
$additionalActions = ExerciseLib::getAdditionalTeacherActions($row['id']);
if (!empty($additionalActions)) {
$actions .= $additionalActions.PHP_EOL;
}
$item .= Display::tag('td', $actions, ['class' => 'td_actions']);
} else {
if ($isDrhOfCourse) {
@ -1150,37 +1276,29 @@ if (!empty($exerciseList)) {
$hotpotatoes_exist = false;
if ($is_allowedToEdit) {
$sql = "SELECT d.path as path, d.comment as comment, ip.visibility as visibility
$sql = "SELECT d.iid, d.path as path, d.comment as comment
FROM $TBL_DOCUMENT d
INNER JOIN $TBL_ITEM_PROPERTY ip
ON (d.id = ip.ref AND d.c_id = ip.c_id)
WHERE
d.c_id = $courseId AND
ip.c_id = $courseId AND
ip.tool = '".TOOL_DOCUMENT."' AND
(d.path LIKE '%htm%') AND
d.path LIKE '".Database :: escape_string($uploadPath.'/%/%')."'
LIMIT ".$from.",".$limit; // only .htm or .html files listed
} else {
$sql = "SELECT d.path as path, d.comment as comment, ip.visibility as visibility
$sql = "SELECT d.iid, d.path as path, d.comment as comment
FROM $TBL_DOCUMENT d
INNER JOIN $TBL_ITEM_PROPERTY ip
ON (d.id = ip.ref AND d.c_id = ip.c_id)
WHERE
d.c_id = $courseId AND
ip.c_id = $courseId AND
ip.tool = '".TOOL_DOCUMENT."' AND
(d.path LIKE '%htm%') AND
d.path LIKE '".Database :: escape_string($uploadPath.'/%/%')."' AND
ip.visibility='1'
d.path LIKE '".Database :: escape_string($uploadPath.'/%/%')."'
LIMIT ".$from.",".$limit;
}
$result = Database::query($sql);
$attribute = [];
while ($row = Database :: fetch_array($result, 'ASSOC')) {
$attribute['id'][] = $row['iid'];
$attribute['path'][] = $row['path'];
$attribute['visibility'][] = $row['visibility'];
$attribute['comment'][] = $row['comment'];
}
@ -1189,8 +1307,6 @@ if (isset($attribute['path']) && is_array($attribute['path'])) {
$hotpotatoes_exist = true;
foreach ($attribute['path'] as $key => $path) {
$item = '';
$vis = $attribute['visibility'][$key];
$active = !empty($vis);
$title = GetQuizName($path, $documentPath);
if ($title == '') {
$title = basename($path);
@ -1198,6 +1314,26 @@ if (isset($attribute['path']) && is_array($attribute['path'])) {
// prof only
if ($is_allowedToEdit) {
$visibility = api_get_item_visibility(
['real_id' => $courseId],
TOOL_DOCUMENT,
$attribute['id'][$key],
0
);
if (!empty($sessionId)) {
if (0 == $visibility) {
continue;
}
$visibility = api_get_item_visibility(
['real_id' => $courseId],
TOOL_DOCUMENT,
$attribute['id'][$key],
$sessionId
);
}
$item = Display::tag(
'td',
implode(PHP_EOL, [
@ -1208,10 +1344,11 @@ if (isset($attribute['path']) && is_array($attribute['path'])) {
'file' => $path,
'uid' => $userId,
]),
['class' => !$active ? 'text-muted' : null]
['class' => $visibility == 0 ? 'text-muted' : null]
),
])
);
$item .= Display::tag('td', '-');
$actions = Display::url(
@ -1228,7 +1365,7 @@ if (isset($attribute['path']) && is_array($attribute['path'])) {
Display::return_icon('test_results.png', get_lang('Results'), '', ICON_SIZE_SMALL).'</a>';
// if active
if ($active) {
if ($visibility != 0) {
$nbrActiveTests = $nbrActiveTests + 1;
$actions .= ' <a href="'.$exercisePath.'?'.api_get_cidreq().'&hpchoice=disable&page='.$page.'&file='.$path.'">'.
Display::return_icon('visible.png', get_lang('Deactivate'), '', ICON_SIZE_SMALL).'</a>';
@ -1241,8 +1378,18 @@ if (isset($attribute['path']) && is_array($attribute['path'])) {
$item .= Display::tag('td', $actions);
$tableRows[] = Display::tag('tr', $item);
} else {
$visibility = api_get_item_visibility(
['real_id' => $courseId],
TOOL_DOCUMENT,
$attribute['id'][$key],
$sessionId
);
if (0 == $visibility) {
continue;
}
// Student only
if ($active) {
$attempt = ExerciseLib::getLatestHotPotatoResult(
$path,
$userId,
@ -1292,7 +1439,6 @@ if (isset($attribute['path']) && is_array($attribute['path'])) {
}
}
}
}
if (empty($exerciseList) && $hotpotatoes_exist == false) {
if ($is_allowedToEdit && $origin != 'learnpath') {

@ -134,7 +134,7 @@ if (isset($_GET['exerciseId'])) {
'post',
api_get_self().'?'.api_get_cidreq().'&exerciseId='.intval($_GET['exerciseId'])
);
$objExercise->read($_GET['exerciseId']);
$objExercise->read($_GET['exerciseId'], false);
$form->addElement('hidden', 'edit', 'true');
} else {
$form = new FormValidator(
@ -172,12 +172,12 @@ if ($form->validate()) {
}
$nameTools = get_lang('ExerciseManagement');
$interbreadcrumb[] = [
"url" => 'exercise.php?'.api_get_cidreq(),
'url' => 'exercise.php?'.api_get_cidreq(),
'name' => get_lang('Exercises'),
];
$interbreadcrumb[] = [
"url" => 'admin.php?exerciseId='.$objExercise->id.'&'.api_get_cidreq(),
"name" => $objExercise->selectTitle(true),
'url' => 'admin.php?exerciseId='.$objExercise->id.'&'.api_get_cidreq(),
'name' => $objExercise->selectTitle(true),
];
Display::display_header($nameTools, get_lang('Exercise'));
@ -190,12 +190,14 @@ if ($form->validate()) {
} else {
if (!empty($_GET['lp_id']) || !empty($_POST['lp_id'])) {
if (!empty($_POST['lp_id'])) {
$lp_id = intval($_POST['lp_id']);
$lp_id = $_POST['lp_id'];
//TODO:this remains to be implemented after press the first post
} else {
$lp_id = intval($_GET['lp_id']);
$lp_id = $_GET['lp_id'];
}
echo "<a href=\"../lp/lp_controller.php?".api_get_cidreq()."&gradebook=&action=add_item&type=step&lp_id=".$lp_id."#resource_tab-2\">".Display::return_icon('back.png', get_lang("BackTo").' '.get_lang("LearningPaths"), '', ICON_SIZE_MEDIUM)."</a>";
$lp_id = (int) $lp_id;
echo "<a href=\"../lp/lp_controller.php?".api_get_cidreq()."&gradebook=&action=add_item&type=step&lp_id=".$lp_id."#resource_tab-2\">".
Display::return_icon('back.png', get_lang("BackTo").' '.get_lang("LearningPaths"), '', ICON_SIZE_MEDIUM)."</a>";
} else {
echo '<a href="exercise.php?'.api_get_cidreq().'">'.
Display::return_icon('back.png', get_lang('BackToExercisesList'), '', ICON_SIZE_MEDIUM).

@ -31,6 +31,12 @@ if (api_is_student_boss() && !empty($filter_user)) {
api_protect_course_script(true, false, true);
}
$limitTeacherAccess = api_get_configuration_value('limit_exercise_teacher_access');
if ($limitTeacherAccess && !api_is_platform_admin()) {
api_not_allowed(true);
}
// including additional libraries
require_once 'hotpotatoes.lib.php';

@ -48,10 +48,10 @@ if (empty($objExercise)) {
$objExercise = new Exercise();
$exercise_stat_info = $objExercise->get_stat_track_exercise_info_by_exe_id($exe_id);
if (!empty($exercise_stat_info) && isset($exercise_stat_info['exe_exo_id'])) {
header("Location: overview.php?exerciseId=".$exercise_stat_info['exe_exo_id'].'&'.api_get_cidreq());
header('Location: overview.php?exerciseId='.$exercise_stat_info['exe_exo_id'].'&'.api_get_cidreq());
exit;
}
api_not_allowed();
api_not_allowed(true);
}
if (api_is_in_gradebook()) {
@ -64,13 +64,16 @@ if (api_is_in_gradebook()) {
$nameTools = get_lang('Exercises');
$interbreadcrumb[] = [
"url" => "exercise.php?".api_get_cidreq(),
"name" => get_lang('Exercises'),
'url' => 'exercise.php?'.api_get_cidreq(),
'name' => get_lang('Exercises'),
];
$htmlHeadXtra[] = '<script src="'.api_get_path(WEB_LIBRARY_JS_PATH).'hotspot/js/hotspot.js"></script>';
$htmlHeadXtra[] = '<link rel="stylesheet" href="'.api_get_path(WEB_LIBRARY_JS_PATH).'hotspot/css/hotspot.css">';
$htmlHeadXtra[] = '<script src="'.api_get_path(WEB_LIBRARY_JS_PATH).'annotation/js/annotation.js"></script>';
if (api_get_configuration_value('quiz_prevent_copy_paste')) {
$htmlHeadXtra[] = '<script src="'.api_get_path(WEB_LIBRARY_JS_PATH).'jquery.nocopypaste.js"></script>';
}
if ($origin != 'learnpath') {
// So we are not in learnpath tool
@ -218,7 +221,6 @@ if ($origin != 'learnpath') {
Session::erase('duration_time_previous');
Session::erase('duration_time');
}
Session::write('attempt_remaining', $remainingMessage);
// Record the results in the learning path, using the SCORM interface (API)

@ -88,22 +88,28 @@ $action = isset($_REQUEST['action']) ? $_REQUEST['action'] : null;
$courseInfo = api_get_course_info();
$sessionId = api_get_session_id();
$is_allowedToEdit = api_is_allowed_to_edit(null, true) ||
$is_allowedToEdit =
api_is_allowed_to_edit(null, true) ||
api_is_course_tutor() ||
api_is_session_admin() ||
api_is_drh() ||
api_is_student_boss();
if (!empty($sessionId) && !$is_allowedToEdit) {
if (api_is_course_session_coach(
$currentUserId,
api_get_course_int_id(),
$sessionId
)) {
if (!api_coach_can_edit_view_results(api_get_course_int_id(), $sessionId)
) {
if (!api_coach_can_edit_view_results(api_get_course_int_id(), $sessionId)) {
api_not_allowed($printHeaders);
}
}
} else {
if (!$is_allowedToEdit) {
api_not_allowed($printHeaders);
}
}
$allowCoachFeedbackExercises = api_get_setting('allow_coach_feedback_exercises') === 'true';
@ -122,6 +128,7 @@ if (empty($objExercise)) {
$objExercise->read($exercise_id);
}
$feedback_type = $objExercise->feedback_type;
// Only users can see their own results
if (!$is_allowedToEdit) {
if ($student_id != $currentUserId) {
@ -230,10 +237,11 @@ $showTotalScoreAndUserChoicesInLastAttempt = true;
if (!empty($track_exercise_info)) {
// if the results_disabled of the Quiz is 1 when block the script
$result_disabled = $track_exercise_info['results_disabled'];
if ($result_disabled == RESULT_DISABLE_NO_SCORE_AND_EXPECTED_ANSWERS) {
switch ($result_disabled) {
case RESULT_DISABLE_NO_SCORE_AND_EXPECTED_ANSWERS:
$show_results = false;
} elseif ($result_disabled == RESULT_DISABLE_SHOW_SCORE_ONLY) {
break;
case RESULT_DISABLE_SHOW_SCORE_ONLY:
$show_results = false;
$show_only_total_score = true;
if ($origin != 'learnpath') {
@ -245,7 +253,9 @@ if (!empty($track_exercise_info)) {
);
}
}
} elseif ($result_disabled == RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT) {
break;
case RESULT_DISABLE_DONT_SHOW_SCORE_ONLY_IF_USER_FINISHES_ATTEMPTS_SHOW_ALWAYS_FEEDBACK:
case RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT:
$attempts = Event::getExerciseResultsByUser(
$currentUserId,
$objExercise->id,
@ -267,6 +277,7 @@ if (!empty($track_exercise_info)) {
// Last attempt not reach don't show score/feedback
$showTotalScoreAndUserChoicesInLastAttempt = false;
}
break;
}
} else {
echo Display::return_message(get_lang('CantViewResults'), 'warning');
@ -317,7 +328,7 @@ $sql = "SELECT attempts.question_id, answer
questions.id = quizz_rel_questions.question_id AND
questions.c_id = ".api_get_course_int_id()."
WHERE
attempts.exe_id = ".intval($id)." $user_restriction
attempts.exe_id = ".$id." $user_restriction
GROUP BY quizz_rel_questions.question_order, attempts.question_id";
$result = Database::query($sql);
$question_list_from_database = [];
@ -369,6 +380,10 @@ if (!empty($maxEditors) && count($questionList) > $maxEditors) {
}
$objExercise->export = $action === 'export';
$arrid = [];
$arrmarks = [];
$strids = '';
$marksid = '';
$countPendingQuestions = 0;
foreach ($questionList as $questionId) {
@ -388,7 +403,6 @@ foreach ($questionList as $questionId) {
// Start buffer
ob_start();
if ($answerType == MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE) {
$choice = [];
}
@ -721,10 +735,9 @@ foreach ($questionList as $questionId) {
if (in_array($answerType, [FREE_ANSWER, ORAL_EXPRESSION, ANNOTATION])) {
$url_name = get_lang('EditCommentsAndMarks');
} else {
$url_name = get_lang('AddComments');
if ($action == 'edit') {
$url_name = get_lang('EditIndividualComment');
} else {
$url_name = get_lang('AddComments');
}
}
echo '<p>';
@ -809,7 +822,7 @@ foreach ($questionList as $questionId) {
$formMark->addSelect('marks', get_lang('AssignMarks'), $options);
$formMark->display();*/
echo '<form name="marksform_'.$questionId.'" method="post" action="">';
echo get_lang("AssignMarks");
echo get_lang('AssignMarks');
echo "&nbsp;<select name='marks' id='select_marks_".$questionId."' class='selectpicker exercise_mark_select'>";
$model = ExerciseLib::getCourseScoreModel();
if (empty($model)) {
@ -897,13 +910,18 @@ foreach ($questionList as $questionId) {
$score = [];
if ($show_results) {
$scorePassed = $my_total_score >= $my_total_weight;
if (function_exists('bccomp')) {
$compareResult = bccomp($my_total_score, $my_total_weight, 3);
$scorePassed = $compareResult === 1 || $compareResult === 0;
}
$score['result'] = ExerciseLib::show_score(
$my_total_score,
$my_total_weight,
false,
false
);
$score['pass'] = $my_total_score >= $my_total_weight ? true : false;
$score['pass'] = $scorePassed;
$score['type'] = $answerType;
$score['score'] = $my_total_score;
$score['weight'] = $my_total_weight;
@ -989,6 +1007,16 @@ if (!empty($category_list) && ($show_results || $show_only_total_score || $showT
);
}
if (RESULT_DISABLE_RANKING == $track_exercise_info['results_disabled']) {
echo Display::page_header(get_lang('Ranking'), null, 'h4');
echo ExerciseLib::displayResultsInRanking(
$objExercise->iId,
$student_id,
$courseInfo['real_id'],
$sessionId
);
}
echo $totalScoreText;
echo $exercise_content;
@ -997,7 +1025,7 @@ if ($show_results) {
echo $totalScoreText;
}
if ($action == 'export') {
if ($action === 'export') {
$content = ob_get_clean();
// needed in order to mpdf to work
ob_clean();
@ -1023,8 +1051,8 @@ if ($action == 'export') {
if ($isFeedbackAllowed) {
if (is_array($arrid) && is_array($arrmarks)) {
$strids = implode(",", $arrid);
$marksid = implode(",", $arrmarks);
$strids = implode(',', $arrid);
$marksid = implode(',', $arrmarks);
}
}

@ -31,7 +31,7 @@ use ChamiloSession as Session;
*/
require_once __DIR__.'/../inc/global.inc.php';
$current_course_tool = TOOL_QUIZ;
$this_section = 'exercise';
$this_section = SECTION_COURSES;
$debug = false;
// Notice for unauthorized people.
@ -39,6 +39,7 @@ api_protect_course_script(true);
$origin = api_get_origin();
$is_allowedToEdit = api_is_allowed_to_edit(null, true);
$courseId = api_get_course_int_id();
$sessionId = api_get_session_id();
$glossaryExtraTools = api_get_setting('show_glossary_in_extra_tools');
$showGlossary = in_array($glossaryExtraTools, ['true', 'exercise', 'exercise_and_lp']);
@ -63,6 +64,9 @@ $htmlHeadXtra[] = api_get_js('epiclock/renderers/minute/epiclock.minute.js');
$htmlHeadXtra[] = '<link rel="stylesheet" href="'.api_get_path(WEB_LIBRARY_JS_PATH).'hotspot/css/hotspot.css">';
$htmlHeadXtra[] = '<script src="'.api_get_path(WEB_LIBRARY_JS_PATH).'hotspot/js/hotspot.js"></script>';
$htmlHeadXtra[] = '<script src="'.api_get_path(WEB_LIBRARY_JS_PATH).'annotation/js/annotation.js"></script>';
if (api_get_configuration_value('quiz_prevent_copy_paste')) {
$htmlHeadXtra[] = '<script src="'.api_get_path(WEB_LIBRARY_JS_PATH).'jquery.nocopypaste.js"></script>';
}
if (api_get_setting('enable_record_audio') === 'true') {
$htmlHeadXtra[] = '<script src="'.api_get_path(WEB_LIBRARY_JS_PATH).'rtc/RecordRTC.js"></script>';
@ -93,6 +97,15 @@ $current_question = isset($_REQUEST['num']) ? intval($_REQUEST['num']) : null;
$currentAnswer = isset($_REQUEST['num_answer']) ? intval($_REQUEST['num_answer']) : null;
$endExercise = isset($_REQUEST['end_exercise']) && $_REQUEST['end_exercise'] == 1 ? true : false;
$logInfo = [
'tool' => TOOL_QUIZ,
'tool_id' => $exerciseId,
'tool_id_detail' => 0,
'action' => ((int) $_REQUEST['learnpath_id'] > 0) ? 'learnpath_id' : '',
'action_details' => ((int) $_REQUEST['learnpath_id'] > 0) ? (int) $_REQUEST['learnpath_id'] : '',
];
Event::registerLog($logInfo);
// Error message
$error = '';
@ -204,6 +217,12 @@ if ($time_control) {
$show_clock = true;
$user_id = api_get_user_id();
if ($objExercise->selectAttempts() > 0) {
$messageReachedMax = Display::return_message(
sprintf(get_lang('ReachedMaxAttempts'), $exercise_title, $objExercise->selectAttempts()),
'warning',
false
);
$attempt_html = '';
$attempt_count = Event::get_attempt_count(
$user_id,
@ -226,6 +245,35 @@ if ($objExercise->selectAttempts() > 0) {
);
if (!empty($exercise_stat_info)) {
$isQuestionsLimitReached = ExerciseLib::isQuestionsLimitPerDayReached(
$user_id,
$objExercise->selectNbrQuestions(),
$courseId,
$sessionId
);
if ($isQuestionsLimitReached) {
$maxQuestionsAnswered = (int) api_get_course_setting('quiz_question_limit_per_day');
Display::addFlash(
Display::return_message(
sprintf(get_lang('QuizQuestionsLimitPerDayXReached'), $maxQuestionsAnswered),
'warning',
false
)
);
if ($origin == 'learnpath') {
Display::display_reduced_header();
Display::display_reduced_footer();
} else {
Display::display_header(get_lang('Exercises'));
Display::display_footer();
}
exit;
}
$max_exe_id = max(array_keys($exercise_stat_info));
$last_attempt_info = $exercise_stat_info[$max_exe_id];
$attempt_html .= Display::div(
@ -233,15 +281,7 @@ if ($objExercise->selectAttempts() > 0) {
['id' => '']
);
$attempt_html .= Display::return_message(
sprintf(
get_lang('ReachedMaxAttempts'),
$exercise_title,
$objExercise->selectAttempts()
),
'warning',
false
);
$attempt_html .= $messageReachedMax;
if (!empty($last_attempt_info['question_list'])) {
foreach ($last_attempt_info['question_list'] as $questions) {
@ -270,37 +310,13 @@ if ($objExercise->selectAttempts() > 0) {
['id' => 'question_score']
);
} else {
$attempt_html .= Display::return_message(
sprintf(
get_lang('ReachedMaxAttempts'),
$exercise_title,
$objExercise->selectAttempts()
),
'warning',
false
);
$attempt_html .= $messageReachedMax;
}
} else {
$attempt_html .= Display::return_message(
sprintf(
get_lang('ReachedMaxAttempts'),
$exercise_title,
$objExercise->selectAttempts()
),
'warning',
false
);
$attempt_html .= $messageReachedMax;
}
} else {
$attempt_html .= Display::return_message(
sprintf(
get_lang('ReachedMaxAttempts'),
$exercise_title,
$objExercise->selectAttempts()
),
'warning',
false
);
$attempt_html .= $messageReachedMax;
}
if ($origin == 'learnpath') {
@ -331,6 +347,11 @@ $questionListUncompressed = $objExercise->getQuestionListWithMediasUncompressed(
Session::write('question_list_uncompressed', $questionListUncompressed);
$clock_expired_time = null;
if (empty($exercise_stat_info)) {
$disable = api_get_configuration_value('exercises_disable_new_attempts');
if ($disable) {
api_not_allowed(true);
}
if ($debug) {
error_log('5 $exercise_stat_info is empty ');
}
@ -716,7 +737,7 @@ if ($formSent && isset($_POST)) {
exit;
} else {
if ($debug) {
error_log('10. Redirecting to exercise_show.php');
error_log('10. Redirecting to exercise_result.php');
}
header("Location: exercise_result.php?".api_get_cidreq()."&exe_id=$exe_id&learnpath_id=$learnpath_id&learnpath_item_id=$learnpath_item_id&learnpath_item_view_id=$learnpath_item_view_id");
exit;
@ -1202,7 +1223,12 @@ if (!empty($error)) {
window.location = url;
}
function save_now(question_id, url_extra) {
function redirectExerciseToResult()
{
window.location = "'.$script_php.'?'.$params.'";
}
function save_now(question_id, url_extra, validate) {
//1. Normal choice inputs
var my_choice = $(\'*[name*="choice[\'+question_id+\']"]\').serialize();
@ -1311,7 +1337,6 @@ if (!empty($error)) {
data: "'.$params.'&type=all&"+my_choice+"&"+hotspot+"&"+free_answers+"&"+remind_list,
success: function(return_value) {
if (return_value == "ok") {
//$("#save_all_response").html(\''.Display::return_icon('accept.png').'\');
if (validate == "validate") {
window.location = "'.$script_php.'?'.$params.'";
} else {

@ -13,7 +13,7 @@ api_protect_course_script(false);
require_once api_get_path(LIBRARY_PATH).'geometry.lib.php';
Display::display_reduced_header();
//Display::display_reduced_header();
echo '<div id="delineation-container">';
@ -80,7 +80,7 @@ if (isset($_GET['choice'])) {
if (empty($choice_value)) {
echo "<script>
// this works for only radio buttons
var f = self.parent.window.document.frm_exercise;
var f = window.document.frm_exercise;
var choice_js='';
var hotspot = new Array();
var hotspotcoord = new Array();
@ -92,7 +92,7 @@ if (empty($choice_value)) {
}
if (f.elements[i].type=='hidden' ) {
name = f.elements[i].name;
var name = f.elements[i].name;
if (name.substr(0,7)=='hotspot')
hotspot.push(f.elements[i].value);
@ -304,6 +304,11 @@ if (!empty($choice_value)) {
$missing_color = true; //echo 'c';
}
$try_hotspot = null;
$lp_hotspot = null;
$url_hotspot = null;
$select_question_hotspot = null;
// if pass
//if ($final_overlap>=$threadhold1 && $final_missing<=$threadhold2 && $final_excess<=$threadhold3) {
if ($final_overlap >= $threadhold1 && $final_missing <= $threadhold3 && $final_excess <= $threadhold2) {
@ -313,6 +318,8 @@ if (!empty($choice_value)) {
$next = 1; //Go to the oars. If $next = 0 we will show this message: "One (or more) area at risk has been hit" instead of the table resume with the results
$wrong_results = true;
$result_comment = get_lang('Unacceptable');
}
$special_comment = $comment = $answerDestination = $objAnswerTmp->selectComment(1);
$answerDestination = $objAnswerTmp->selectDestination(1);
$destination_items = explode('@@', $answerDestination);
@ -320,7 +327,6 @@ if (!empty($choice_value)) {
$lp_hotspot = $destination_items[2];
$select_question_hotspot = $destination_items[3];
$url_hotspot = $destination_items[4];
}
} elseif ($answerId > 1) {
if ($objAnswerTmp->selectHotspotType($answerId) == 'noerror') {
if ($dbg_local > 0) {
@ -464,7 +470,7 @@ Session::write('newquestionList', $newquestionList);
$links = '';
if (isset($choice_value) && $choice_value == -1) {
if ($answerType != HOT_SPOT_DELINEATION) {
$links .= '<a href="#" onclick="self.parent.tb_remove();">'.get_lang('ChooseAnAnswer').'</a><br />';
$links .= '<a href="#" onclick="tb_remove();">'.get_lang('ChooseAnAnswer').'</a><br />';
}
}
@ -561,13 +567,15 @@ if ($destinationid == -1) {
echo '<script>
function SendEx(num) {
if (num == -1) {
self.parent.window.location.href = "exercise_result.php?take_session=1&exerciseId='.$exerciseId.'&num="+num+"&exerciseType='.$exerciseType.'&origin='.$origin.'&learnpath_item_id='.$learnpath_item_id.'&learnpath_id='.$learnpath_id.'";
self.parent.tb_remove();
window.location.href = "exercise_result.php?take_session=1&exerciseId='.$exerciseId.'&num="+num+"&exerciseType='.$exerciseType.'&origin='.$origin.'&learnpath_item_id='.$learnpath_item_id.'&learnpath_id='.$learnpath_id.'";
//tb_remove();
} else {
num -= 1;
self.parent.window.location.href = "exercise_submit.php?tryagain=1&exerciseId='.$exerciseId.'&num="+num+"&exerciseType='.$exerciseType.'&origin='.$origin.'&learnpath_item_id='.$learnpath_item_id.'&learnpath_id='.$learnpath_id.'";
self.parent.tb_remove();
window.location.href = "exercise_submit.php?tryagain=1&exerciseId='.$exerciseId.'&num="+num+"&exerciseType='.$exerciseType.'&origin='.$origin.'&learnpath_item_id='.$learnpath_item_id.'&learnpath_id='.$learnpath_id.'";
//tb_remove();
}
return false;
}
</script>';
@ -606,8 +614,8 @@ if ($links != '') {
} else {
$questionNum++;
echo '<script>
self.parent.window.location.href = "exercise_submit.php?exerciseId='.$exerciseId.'&num='.$questionNum.'&exerciseType='.$exerciseType.'&'.api_get_cidreq().'";
//self.parent.tb_remove();
window.location.href = "exercise_submit.php?exerciseId='.$exerciseId.'&num='.$questionNum.'&exerciseType='.$exerciseType.'&'.api_get_cidreq().'";
//tb_remove();
</script>';
}

File diff suppressed because it is too large Load Diff

@ -991,10 +991,19 @@ class FillBlanks extends Question
// lets rebuild the sentence with [correct answer][student answer][answer is correct]
$result = '';
for ($i = 0; $i < count($listWithStudentAnswer['common_words']) - 1; $i++) {
$answerValue = null;
if (isset($listWithStudentAnswer['student_answer'][$i])) {
$answerValue = $listWithStudentAnswer['student_answer'][$i];
}
$scoreValue = null;
if (isset($listWithStudentAnswer['student_score'][$i])) {
$scoreValue = $listWithStudentAnswer['student_score'][$i];
}
$result .= $listWithStudentAnswer['common_words'][$i];
$result .= $listWithStudentAnswer['words_with_bracket'][$i];
$result .= $separatorStart.$listWithStudentAnswer['student_answer'][$i].$separatorEnd;
$result .= $separatorStart.$listWithStudentAnswer['student_score'][$i].$separatorEnd;
$result .= $separatorStart.$answerValue.$separatorEnd;
$result .= $separatorStart.$scoreValue.$separatorEnd;
}
$result .= $listWithStudentAnswer['common_words'][$i];
$result .= '::';
@ -1186,7 +1195,12 @@ class FillBlanks extends Question
$result = '';
$listStudentAnswerInfo = self::getAnswerInfo($answer, true);
if ($resultsDisabled == RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT) {
if (in_array($resultsDisabled, [
RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT,
RESULT_DISABLE_DONT_SHOW_SCORE_ONLY_IF_USER_FINISHES_ATTEMPTS_SHOW_ALWAYS_FEEDBACK,
]
)
) {
$resultsDisabled = true;
if ($showTotalScoreAndUserChoices) {
$resultsDisabled = false;
@ -1217,6 +1231,12 @@ class FillBlanks extends Question
// rebuild the sentence with student answer inserted
for ($i = 0; $i < count($listStudentAnswerInfo['common_words']); $i++) {
if ($resultsDisabled == RESULT_DISABLE_SHOW_ONLY_IN_CORRECT_ANSWER) {
if (isset($listStudentAnswerInfo['student_score'][$i]) &&
$listStudentAnswerInfo['student_score'][$i] != 1) {
continue;
}
}
$result .= isset($listStudentAnswerInfo['common_words'][$i]) ? $listStudentAnswerInfo['common_words'][$i] : '';
$result .= isset($listStudentAnswerInfo['student_answer'][$i]) ? $listStudentAnswerInfo['student_answer'][$i] : '';
}
@ -1248,15 +1268,19 @@ class FillBlanks extends Question
$showTotalScoreAndUserChoices = false
) {
$hideExpectedAnswer = false;
if ($feedbackType == 0 && $resultsDisabled == RESULT_DISABLE_SHOW_SCORE_ONLY) {
switch ($resultsDisabled) {
case RESULT_DISABLE_SHOW_SCORE_ONLY:
if ($feedbackType == 0) {
$hideExpectedAnswer = true;
}
if ($resultsDisabled == RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT) {
break;
case RESULT_DISABLE_DONT_SHOW_SCORE_ONLY_IF_USER_FINISHES_ATTEMPTS_SHOW_ALWAYS_FEEDBACK:
case RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT:
$hideExpectedAnswer = true;
if ($showTotalScoreAndUserChoices) {
$hideExpectedAnswer = false;
}
break;
}
$style = 'feedback-green';

@ -61,7 +61,7 @@ class FreeAnswer extends Question
$header = parent::return_header($exercise, $counter, $score);
$header .= '<table class="'.$this->question_table_class.'" >
<tr>
<th>'.get_lang("Answer").'</th>
<th>'.get_lang('Answer').'</th>
</tr>';
return $header;

@ -234,7 +234,7 @@ function GetSrcName($imageTag)
// Select src tag from img tag.
$match = [];
preg_match("|(src=\".*\" )|U", $imageTag, $match); //src
list(, $srctag) = each($match);
$srctag = reset($match);
$src = substr($srctag, 5, (strlen($srctag) - 7));
if (stristr($src, 'http') === false) {
// valid or invalid image name
@ -261,9 +261,9 @@ function GetImgParams($fname, $fpath, &$imgparams, &$imgcount)
$matches = [];
preg_match_all('(<img .*>)', $contents, $matches);
$imgcount = 0;
while (list(, $match) = each($matches)) {
foreach ($matches as $match) {
// Each match consists of a key and a value.
while (list(, $imageTag) = each($match)) {
foreach ($match as $imageTag) {
$imgname = GetImgName($imageTag);
if ($imgname != '' && !in_array($imgname, $imgparams)) {
array_push($imgparams, $imgname); // name (+ type) of the images in the html test
@ -284,7 +284,7 @@ function GenerateHiddenList($imgparams)
{
$list = '';
if (is_array($imgparams)) {
while (list(, $string) = each($imgparams)) {
foreach ($imgparams as $string) {
$list .= "<input type=\"hidden\" name=\"imgparams[]\" value=\"$string\" />\n";
}
}
@ -345,8 +345,8 @@ function ReplaceImgTag($content)
$newcontent = $content;
$matches = [];
preg_match_all('(<img .*>)', $content, $matches);
while (list(, $match) = each($matches)) {
while (list(, $imageTag) = each($match)) {
foreach ($matches as $match) {
foreach ($match as $imageTag) {
$imgname = GetSrcName($imageTag);
if ($imgname != '') {
$prehref = $imgname;

@ -246,7 +246,7 @@ if ((api_is_allowed_to_edit(null, true)) && (($finish == 0) || ($finish == 2)))
if ($finish == 2) {
// If we are in the img upload process.
$dialogBox .= get_lang('ImgNote_st').$imgcount.get_lang('ImgNote_en').'<br />';
while (list($key, $string) = each($imgparams)) {
foreach ($imgparams as $key => $string) {
$dialogBox .= $string.'; ';
}
}

@ -130,7 +130,7 @@ class HotSpotDelineation extends HotSpot
*/
public function createForm(&$form, $exercise)
{
parent::createForm($form);
parent::createForm($form, $exercise);
}
/**

@ -11,7 +11,7 @@ use ChamiloSession as Session;
*
* @author Toon Keppens
*/
$modifyAnswers = intval($_GET['hotspotadmin']);
$modifyAnswers = (int) $_GET['hotspotadmin'];
if (!is_object($objQuestion)) {
$objQuestion = Question::read($modifyAnswers);
@ -30,7 +30,7 @@ if ($modifyIn) {
echo '$modifyIn was set'."<br />\n";
}
// if the user has chosen to modify the question only in the current exercise
if ($modifyIn == 'thisExercise') {
if ($modifyIn === 'thisExercise') {
// duplicates the question
$questionId = $objQuestion->duplicate();
@ -56,13 +56,13 @@ if ($modifyIn) {
$objAnswer = new Answer($questionId);
}
$color = unserialize($color);
$reponse = unserialize($reponse);
$comment = unserialize($comment);
$weighting = unserialize($weighting);
$hotspot_coordinates = unserialize($hotspot_coordinates);
$hotspot_type = unserialize($hotspot_type);
$destination = unserialize($destination);
$color = UnserializeApi::unserialize('not_allowed_classes', $color);
$reponse = UnserializeApi::unserialize('not_allowed_classes', $reponse);
$comment = UnserializeApi::unserialize('not_allowed_classes', $comment);
$weighting = UnserializeApi::unserialize('not_allowed_classes', $weighting);
$hotspot_coordinates = UnserializeApi::unserialize('not_allowed_classes', $hotspot_coordinates);
$hotspot_type = UnserializeApi::unserialize('not_allowed_classes', $hotspot_type);
$destination = UnserializeApi::unserialize('not_allowed_classes', $destination);
unset($buttonBack);
}
@ -71,14 +71,13 @@ $hotspot_admin_url = api_get_path(WEB_CODE_PATH).'exercise/admin.php?'.api_get_c
// the answer form has been submitted
$submitAnswers = isset($_POST['submitAnswers']) ? true : false;
$buttonBack = isset($_POST['buttonBack']) ? true : false;
$nbrAnswers = isset($_POST['nbrAnswers']) ? intval($_POST['nbrAnswers']) : 0;
$nbrAnswers = isset($_POST['nbrAnswers']) ? (int) $_POST['nbrAnswers'] : 0;
if ($submitAnswers || $buttonBack) {
if ($answerType == HOT_SPOT) {
if ($debug > 0) {
echo '$submitAnswers or $buttonBack was set'."<br />\n";
}
$questionWeighting = $nbrGoodAnswers = 0;
for ($i = 1; $i <= $nbrAnswers; $i++) {
if ($debug > 0) {
@ -324,7 +323,7 @@ if ($submitAnswers || $buttonBack) {
// sets the total weighting of the question
$objQuestion->updateWeighting($questionWeighting);
$objQuestion->save($exerciseId);
$objQuestion->save($objExercise);
$editQuestion = $questionId;
unset($modifyAnswers);
@ -334,7 +333,7 @@ if ($submitAnswers || $buttonBack) {
}
}
if ($modifyAnswers) {
if (isset($modifyAnswers)) {
if ($debug > 0) {
echo str_repeat('&nbsp;', 0).'$modifyAnswers is set'."<br />\n";
}

@ -27,12 +27,13 @@ if ($debug) {
error_log("Call to hotspot_answers.as.php");
}
$trackExerciseInfo = $objExercise->get_stat_track_exercise_info_by_exe_id($exeId);
// Check if student has access to the hotspot answers
if (!api_is_allowed_to_edit(null, true)) {
if (empty($exeId)) {
api_not_allowed();
}
$trackExerciseInfo = $objExercise->get_stat_track_exercise_info_by_exe_id($exeId);
if (empty($trackExerciseInfo)) {
api_not_allowed();
@ -92,7 +93,13 @@ $data['courseCode'] = $_course['path'];
$data['hotspots'] = [];
$showTotalScoreAndUserChoicesInLastAttempt = true;
if ($objExercise->selectResultsDisabled() == RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT) {
if (in_array(
$objExercise->selectResultsDisabled(), [
RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT,
RESULT_DISABLE_DONT_SHOW_SCORE_ONLY_IF_USER_FINISHES_ATTEMPTS_SHOW_ALWAYS_FEEDBACK,
]
)
) {
$showOnlyScore = true;
$showResults = true;
$lpId = isset($trackExerciseInfo['orig_lp_id']) ? $trackExerciseInfo['orig_lp_id'] : 0;
@ -119,11 +126,19 @@ if ($objExercise->selectResultsDisabled() == RESULT_DISABLE_SHOW_SCORE_ATTEMPT_S
}
$hideExpectedAnswer = false;
if ($objExercise->selectFeedbackType() == 0 && $objExercise->selectResultsDisabled() == 2) {
if ($objExercise->selectFeedbackType() == 0 &&
$objExercise->selectResultsDisabled() == RESULT_DISABLE_SHOW_SCORE_ONLY
) {
$hideExpectedAnswer = true;
}
if ($objExercise->selectResultsDisabled() == RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT) {
if (in_array(
$objExercise->selectResultsDisabled(), [
RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT,
RESULT_DISABLE_DONT_SHOW_SCORE_ONLY_IF_USER_FINISHES_ATTEMPTS_SHOW_ALWAYS_FEEDBACK,
]
)
) {
$hideExpectedAnswer = $showTotalScoreAndUserChoicesInLastAttempt ? false : true;
}
@ -150,8 +165,36 @@ if (!$hideExpectedAnswer) {
/** @var CQuizAnswer $hotSpotAnswer */
foreach ($result as $hotSpotAnswer) {
$hotSpotAnswerId = $hotSpotAnswer->getIid();
// Show only correct hotspots
if ($objExercise->selectResultsDisabled() == RESULT_DISABLE_SHOW_ONLY_IN_CORRECT_ANSWER) {
$TBL_TRACK_HOTSPOT = Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTSPOT);
// Check auto id
$sql = "SELECT hotspot_correct
FROM $TBL_TRACK_HOTSPOT
WHERE
hotspot_exe_id = $exeId AND
hotspot_question_id= $questionId AND
hotspot_answer_id = ".$hotSpotAnswerId."
ORDER BY hotspot_id ASC";
$result = Database::query($sql);
$studentChoice = false;
if (Database::num_rows($result)) {
$studentChoice = Database::result(
$result,
0,
'hotspot_correct'
);
}
if (!$studentChoice) {
continue;
}
}
$hotSpot = [];
$hotSpot['id'] = $hotSpotAnswer->getIid();
$hotSpot['id'] = $hotSpotAnswerId;
$hotSpot['answer'] = $hotSpotAnswer->getAnswer();
switch ($hotSpotAnswer->getHotspotType()) {

@ -291,6 +291,7 @@ class Matching extends Question
$header .= '<th>'.get_lang('ExpectedChoice').'</th>';
$header .= '<th>'.get_lang('Status').'</th>';
} else {
$header .= '<th>'.get_lang('YourChoice').'</th>';
$header .= '<th>'.get_lang('CorrespondsTo').'</th>';
}
$header .= '</tr>';

@ -29,6 +29,7 @@ $exercise_id = isset($_REQUEST['exerciseId']) ? intval($_REQUEST['exerciseId'])
$objExercise = new Exercise();
$result = $objExercise->read($exercise_id);
if (!$result) {
api_not_allowed(true);
}
@ -38,11 +39,20 @@ $learnpath_item_id = isset($_REQUEST['learnpath_item_id']) ? intval($_REQUEST['l
$learnpathItemViewId = isset($_REQUEST['learnpath_item_view_id']) ? intval($_REQUEST['learnpath_item_view_id']) : null;
$origin = api_get_origin();
$logInfo = [
'tool' => TOOL_QUIZ,
'tool_id' => $exercise_id,
'tool_id_detail' => 0,
'action' => isset($_REQUEST['learnpath_id']) ? 'learnpath_id' : '',
'action_details' => isset($_REQUEST['learnpath_id']) ? (int) $_REQUEST['learnpath_id'] : '',
];
Event::registerLog($logInfo);
$interbreadcrumb[] = [
"url" => "exercise.php?".api_get_cidreq(),
"name" => get_lang('Exercises'),
'url' => 'exercise.php?'.api_get_cidreq(),
'name' => get_lang('Exercises'),
];
$interbreadcrumb[] = ["url" => "#", "name" => $objExercise->selectTitle(true)];
$interbreadcrumb[] = ['url' => '#', 'name' => $objExercise->selectTitle(true)];
$time_control = false;
$clock_expired_time = ExerciseLib::get_session_time_control_key($objExercise->id, $learnpath_id, $learnpath_item_id);
@ -169,7 +179,13 @@ if ($current_browser == 'Internet Explorer') {
}
$blockShowAnswers = false;
if ($objExercise->results_disabled == RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT) {
if (in_array(
$objExercise->results_disabled,
[
RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT,
RESULT_DISABLE_DONT_SHOW_SCORE_ONLY_IF_USER_FINISHES_ATTEMPTS_SHOW_ALWAYS_FEEDBACK,
])
) {
if (count($attempts) < $objExercise->attempts) {
$blockShowAnswers = true;
}
@ -178,10 +194,7 @@ if ($objExercise->results_disabled == RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANS
if (!empty($attempts)) {
$i = $counter;
foreach ($attempts as $attempt_result) {
$score = ExerciseLib::show_score(
$attempt_result['exe_result'],
$attempt_result['exe_weighting']
);
$score = ExerciseLib::show_score($attempt_result['exe_result'], $attempt_result['exe_weighting']);
$attempt_url = api_get_path(WEB_CODE_PATH).'exercise/result.php?';
$attempt_url .= api_get_cidreq().'&show_headers=1&';
$attempt_url .= http_build_query([
@ -211,7 +224,7 @@ if (!empty($attempts)) {
),
'userIp' => $attempt_result['user_ip'],
];
$attempt_link .= "&nbsp;&nbsp;&nbsp;".$teacher_revised;
$attempt_link .= '&nbsp;&nbsp;&nbsp;'.$teacher_revised;
if (in_array(
$objExercise->results_disabled,
@ -220,6 +233,9 @@ if (!empty($attempts)) {
RESULT_DISABLE_SHOW_SCORE_ONLY,
RESULT_DISABLE_SHOW_FINAL_SCORE_ONLY_WITH_CATEGORIES,
RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT,
RESULT_DISABLE_DONT_SHOW_SCORE_ONLY_IF_USER_FINISHES_ATTEMPTS_SHOW_ALWAYS_FEEDBACK,
RESULT_DISABLE_RANKING,
RESULT_DISABLE_SHOW_ONLY_IN_CORRECT_ANSWER,
]
)) {
$row['result'] = $score;
@ -231,16 +247,27 @@ if (!empty($attempts)) {
RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS,
RESULT_DISABLE_SHOW_FINAL_SCORE_ONLY_WITH_CATEGORIES,
RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT,
RESULT_DISABLE_DONT_SHOW_SCORE_ONLY_IF_USER_FINISHES_ATTEMPTS_SHOW_ALWAYS_FEEDBACK,
RESULT_DISABLE_RANKING,
RESULT_DISABLE_SHOW_ONLY_IN_CORRECT_ANSWER,
]
) || (
$objExercise->results_disabled == RESULT_DISABLE_SHOW_SCORE_ONLY &&
$objExercise->feedback_type == EXERCISE_FEEDBACK_TYPE_END
)
) {
if ($blockShowAnswers) {
if ($blockShowAnswers &&
$objExercise->results_disabled != RESULT_DISABLE_DONT_SHOW_SCORE_ONLY_IF_USER_FINISHES_ATTEMPTS_SHOW_ALWAYS_FEEDBACK
) {
$attempt_link = '';
}
if ($blockShowAnswers == true &&
$objExercise->results_disabled == RESULT_DISABLE_DONT_SHOW_SCORE_ONLY_IF_USER_FINISHES_ATTEMPTS_SHOW_ALWAYS_FEEDBACK
) {
if (isset($row['result'])) {
unset($row['result']);
}
}
$row['attempt_link'] = $attempt_link;
}
$my_attempt_array[] = $row;
@ -252,6 +279,19 @@ if (!empty($attempts)) {
// Hiding score and answer
switch ($objExercise->results_disabled) {
case RESULT_DISABLE_DONT_SHOW_SCORE_ONLY_IF_USER_FINISHES_ATTEMPTS_SHOW_ALWAYS_FEEDBACK:
if ($blockShowAnswers) {
$header_names = [get_lang('Attempt'), get_lang('StartDate'), get_lang('IP'), get_lang('Details')];
} else {
$header_names = [
get_lang('Attempt'),
get_lang('StartDate'),
get_lang('IP'),
get_lang('Score'),
get_lang('Details'),
];
}
break;
case RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT:
if ($blockShowAnswers) {
$header_names = [get_lang('Attempt'), get_lang('StartDate'), get_lang('IP'), get_lang('Score')];
@ -267,6 +307,7 @@ if (!empty($attempts)) {
break;
case RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS:
case RESULT_DISABLE_SHOW_FINAL_SCORE_ONLY_WITH_CATEGORIES:
case RESULT_DISABLE_RANKING:
$header_names = [
get_lang('Attempt'),
get_lang('StartDate'),

@ -18,6 +18,7 @@ use Chamilo\CourseBundle\Entity\CQuizAnswer;
abstract class Question
{
public $id;
public $iid;
public $question;
public $description;
public $weighting;
@ -38,6 +39,7 @@ abstract class Question
public $questionTypeWithFeedback;
public $extra;
public $export = false;
public $code;
public static $questionTypes = [
UNIQUE_ANSWER => ['unique_answer.class.php', 'UniqueAnswer'],
MULTIPLE_ANSWER => ['multiple_answer.class.php', 'MultipleAnswer'],
@ -76,6 +78,7 @@ abstract class Question
public function __construct()
{
$this->id = 0;
$this->iid = 0;
$this->question = '';
$this->description = '';
$this->weighting = 0;
@ -154,6 +157,7 @@ abstract class Question
$objQuestion = self::getInstance($object->type);
if (!empty($objQuestion)) {
$objQuestion->id = (int) $id;
$objQuestion->iid = (int) $object->iid;
$objQuestion->question = $object->question;
$objQuestion->description = $object->description;
$objQuestion->weighting = $object->ponderation;
@ -165,6 +169,7 @@ abstract class Question
$objQuestion->course = $course_info;
$objQuestion->feedback = isset($object->feedback) ? $object->feedback : '';
$objQuestion->category = TestCategory::getCategoryForQuestion($id, $course_id);
$objQuestion->code = isset($object->code) ? $object->code : '';
$tblQuiz = Database::get_course_table(TABLE_QUIZ_TEST);
$sql = "SELECT DISTINCT q.exercice_id
@ -229,8 +234,12 @@ abstract class Question
public function getTitleToDisplay($itemNumber)
{
$showQuestionTitleHtml = api_get_configuration_value('save_titles_as_html');
$title = '';
if (api_get_configuration_value('show_question_id')) {
$title .= '<h4>#'.$this->course['code'].'-'.$this->iid.'</h4>';
}
$title = $showQuestionTitleHtml ? '' : '<strong>';
$title .= $showQuestionTitleHtml ? '' : '<strong>';
$title .= $itemNumber.'. '.$this->selectTitle();
$title .= $showQuestionTitleHtml ? '' : '</strong>';
@ -403,7 +412,7 @@ abstract class Question
*/
public function selectNbrExercises()
{
return sizeof($this->exerciseList);
return count($this->exerciseList);
}
/**
@ -423,7 +432,7 @@ abstract class Question
*/
public function updateParentId($id)
{
$this->parent_id = intval($id);
$this->parent_id = (int) $id;
}
/**
@ -948,6 +957,12 @@ abstract class Question
$params,
['c_id = ? AND id = ?' => [$c_id, $id]]
);
Event::addEvent(
LOG_QUESTION_UPDATED,
LOG_QUESTION_ID,
$this->iid
);
$this->saveCategory($categoryId);
if (!empty($exerciseId)) {
@ -1005,6 +1020,12 @@ abstract class Question
$sql = "UPDATE $TBL_QUESTIONS SET id = iid WHERE iid = {$this->id}";
Database::query($sql);
Event::addEvent(
LOG_QUESTION_CREATED,
LOG_QUESTION_ID,
$this->id
);
api_item_property_update(
$this->course,
TOOL_QUIZ,
@ -1124,7 +1145,10 @@ abstract class Question
$se_doc = $di->get_document((int) $se_ref['search_did']);
if ($se_doc !== false) {
if (($se_doc_data = $di->get_document_data($se_doc)) !== false) {
$se_doc_data = unserialize($se_doc_data);
$se_doc_data = UnserializeApi::unserialize(
'not_allowed_classes',
$se_doc_data
);
if (isset($se_doc_data[SE_DATA]['type']) &&
$se_doc_data[SE_DATA]['type'] == SE_DOCTYPE_EXERCISE_QUESTION
) {
@ -1240,9 +1264,9 @@ abstract class Question
// checks if the exercise ID is not in the list
if (!in_array($exerciseId, $this->exerciseList)) {
$this->exerciseList[] = $exerciseId;
$new_exercise = new Exercise();
$new_exercise->read($exerciseId);
$count = $new_exercise->selectNbrQuestions();
$newExercise = new Exercise();
$newExercise->read($exerciseId, false);
$count = $newExercise->getQuestionCount();
$count++;
$sql = "INSERT INTO $exerciseRelQuestionTable (c_id, question_id, exercice_id, question_order)
VALUES ({$this->course['real_id']}, ".intval($id).", ".intval($exerciseId).", '$count')";
@ -1747,7 +1771,6 @@ abstract class Question
//Save normal question if NOT media
if ($this->type != MEDIA_QUESTION) {
$this->save($exercise);
// modify the exercise
$exercise->addToList($this->id);
$exercise->update_question_positions();
@ -1774,7 +1797,7 @@ abstract class Question
*
* @param Exercise $objExercise
*/
public static function display_type_menu($objExercise)
public static function displayTypeMenu($objExercise)
{
$feedback_type = $objExercise->feedback_type;
$exerciseId = $objExercise->id;
@ -1957,23 +1980,25 @@ abstract class Question
if (!empty($counter)) {
$counterLabel = (int) $counter;
}
$score_label = get_lang('Wrong');
$scoreLabel = get_lang('Wrong');
$class = 'error';
if ($score['pass'] == true) {
$score_label = get_lang('Correct');
if (isset($score['pass']) && $score['pass'] == true) {
$scoreLabel = get_lang('Correct');
$class = 'success';
}
if (in_array($this->type, [FREE_ANSWER, ORAL_EXPRESSION, ANNOTATION])) {
$score['revised'] = isset($score['revised']) ? $score['revised'] : false;
if ($score['revised'] == true) {
$score_label = get_lang('Revised');
$scoreLabel = get_lang('Revised');
$class = '';
} else {
$score_label = get_lang('NotRevised');
$scoreLabel = get_lang('NotRevised');
$class = 'warning';
if (isset($score['weight'])) {
$weight = float_format($score['weight'], 1);
$score['result'] = " ? / ".$weight;
$score['result'] = ' ? / '.$weight;
}
$model = ExerciseLib::getCourseScoreModel();
if (!empty($model)) {
$score['result'] = ' ? ';
@ -1996,13 +2021,19 @@ abstract class Question
$header .= $this->show_media_content();
}
$scoreCurrent = [
'used' => $score['score'],
'missing' => $score['weight'],
'used' => isset($score['score']) ? $score['score'] : '',
'missing' => isset($score['weight']) ? $score['weight'] : '',
];
$header .= Display::page_subheader2($counterLabel.'. '.$this->question);
// dont display score for certainty degree questions
if ($this->type != MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY) {
$header .= $exercise->getQuestionRibbon($class, $score_label, $score['result'], $scoreCurrent);
if (isset($score['result'])) {
if ($exercise->results_disabled == RESULT_DISABLE_SHOW_ONLY_IN_CORRECT_ANSWER) {
$score['result'] = null;
}
$header .= $exercise->getQuestionRibbon($class, $scoreLabel, $score['result'], $scoreCurrent);
}
}
if ($this->type != READING_COMPREHENSION) {
@ -2042,6 +2073,7 @@ abstract class Question
}
/**
* @deprecated
* Create a question from a set of parameters.
*
* @param int Quiz ID
@ -2324,6 +2356,28 @@ abstract class Question
return '<br />'.Display::return_message($this->feedback, 'normal', false);
}
/**
* Check if this question exists in another exercise.
*
* @throws \Doctrine\ORM\Query\QueryException
*
* @return mixed
*/
public function existsInAnotherExercises()
{
$em = Database::getManager();
$count = $em
->createQuery('
SELECT COUNT(qq.iid) FROM ChamiloCourseBundle:CQuizRelQuestion qq
WHERE qq.questionId = :id
')
->setParameters(['id' => (int) $this->id])
->getSingleScalarResult();
return $count > 1;
}
/**
* Resizes a picture || Warning!: can only be called after uploadPicture,
* or if picture is already available in object.

@ -13,7 +13,7 @@
*/
if (isset($_GET['editQuestion'])) {
$objQuestion = Question::read($_GET['editQuestion']);
$action = api_get_self()."?".api_get_cidreq()."&myid=1&modifyQuestion=".$modifyQuestion."&editQuestion=".$objQuestion->id;
$action = api_get_self()."?".api_get_cidreq()."&myid=1&modifyQuestion=".$modifyQuestion."&editQuestion=".$objQuestion->id.'&page='.$page;
} else {
$objQuestion = Question::getInstance($_REQUEST['answerType']);
$action = api_get_self()."?".api_get_cidreq()."&modifyQuestion=".$modifyQuestion."&newQuestion=".$newQuestion;
@ -35,8 +35,13 @@ if (is_object($objQuestion)) {
$typesInformation = Question::get_question_type_list();
$form_title_extra = isset($typesInformation[$type][1]) ? get_lang($typesInformation[$type][1]) : null;
$code = '';
if (isset($objQuestion->code) && !empty($objQuestion->code)) {
$code = ' ('.$objQuestion->code.')';
}
// form title
$form->addHeader($text.': '.$form_title_extra);
$form->addHeader($text.': '.$form_title_extra.$code);
// question form elements
$objQuestion->createForm($form, $objExercise);
@ -60,13 +65,18 @@ if (is_object($objQuestion)) {
$objQuestion->type != HOT_SPOT_DELINEATION
) {
if (isset($_GET['editQuestion'])) {
echo '<script type="text/javascript">window.location.href="admin.php?exerciseId='.$exerciseId.'&'.api_get_cidreq().'&message=ItemUpdated"</script>';
echo '<script type="text/javascript">window.location.href="admin.php?exerciseId='.$exerciseId.'&'.api_get_cidreq().'&page='.$page.'&message=ItemUpdated"</script>';
} else {
// New question
echo '<script type="text/javascript">window.location.href="admin.php?exerciseId='.$exerciseId.'&'.api_get_cidreq().'&message=ItemAdded"</script>';
$page = 1;
$length = api_get_configuration_value('question_pagination_length');
if (!empty($length)) {
$page = round($objExercise->getQuestionCount() / $length);
}
echo '<script type="text/javascript">window.location.href="admin.php?exerciseId='.$exerciseId.'&'.api_get_cidreq().'&page='.$page.'&message=ItemAdded"</script>';
}
} else {
echo '<script type="text/javascript">window.location.href="admin.php?exerciseId='.$exerciseId.'&hotspotadmin='.$objQuestion->id.'&'.api_get_cidreq().'"</script>';
echo '<script type="text/javascript">window.location.href="admin.php?exerciseId='.$exerciseId.'&page='.$page.'&hotspotadmin='.$objQuestion->id.'&'.api_get_cidreq().'"</script>';
}
} else {
if (isset($questionName)) {
@ -76,7 +86,7 @@ if (is_object($objQuestion)) {
echo '<img src="../document/download.php?doc_url=%2Fimages%2F'.$pictureName.'" border="0">';
}
if (!empty($msgErr)) {
echo Display::return_message($msgErr, 'normal');
echo Display::return_message($msgErr);
}
// display the form
$form->display();

@ -14,9 +14,14 @@ use ChamiloSession as Session;
* This script allows to manage the question list
* It is included from the script admin.php
*/
$limitTeacherAccess = api_get_configuration_value('limit_exercise_teacher_access');
// deletes a question from the exercise (not from the data base)
if ($deleteQuestion) {
if ($limitTeacherAccess && !api_is_platform_admin()) {
exit;
}
// if the question exists
if ($objQuestionTmp = Question::read($deleteQuestion)) {
$objQuestionTmp->delete($exerciseId);
@ -29,13 +34,13 @@ if ($deleteQuestion) {
// destruction of the Question object
unset($objQuestionTmp);
}
$ajax_url = api_get_path(WEB_AJAX_PATH)."exercise.ajax.php?".api_get_cidreq()."&exercise_id=".intval($exerciseId);
$ajax_url = api_get_path(WEB_AJAX_PATH).'exercise.ajax.php?'.api_get_cidreq().'&exercise_id='.intval($exerciseId);
?>
<div id="dialog-confirm"
title="<?php echo get_lang("ConfirmYourChoice"); ?>"
title="<?php echo get_lang('ConfirmYourChoice'); ?>"
style="display:none;">
<p>
<?php echo get_lang("AreYouSureToDelete"); ?>
<?php echo get_lang('AreYouSureToDelete'); ?>
</p>
</div>
@ -144,9 +149,10 @@ $ajax_url = api_get_path(WEB_AJAX_PATH)."exercise.ajax.php?".api_get_cidreq()."&
<?php
//we filter the type of questions we can add
Question::display_type_menu($objExercise);
Question::displayTypeMenu($objExercise);
// Re sets the question list
$objExercise->setQuestionList();
//$objExercise->setQuestionList();
echo '<div id="message"></div>';
$token = Security::get_token();
@ -156,10 +162,50 @@ Session::erase('less_answer');
// If we are in a test
$inATest = isset($exerciseId) && $exerciseId > 0;
if (!$inATest) {
echo "<div class='alert alert-warning'>"
.get_lang("ChoiceQuestionType")
."</div>";
echo "<div class='alert alert-warning'>".get_lang('ChoiceQuestionType')."</div>";
} else {
if ($nbrQuestions) {
// In the building exercise mode show question list ordered as is.
$objExercise->setCategoriesGrouping(false);
// In building mode show all questions not render by teacher order.
$objExercise->questionSelectionType = EX_Q_SELECTION_ORDERED;
$alloQuestionOrdering = true;
$showPagination = api_get_configuration_value('show_question_pagination');
if (!empty($showPagination) && $nbrQuestions > $showPagination) {
// $page is declare in admin.php
//$page = isset($_GET['page']) && !empty($_GET['page']) ? (int) $_GET['page'] : 1;
$length = api_get_configuration_value('question_pagination_length');
$url = api_get_self().'?'.api_get_cidreq();
// Use pagination for exercise with more than 200 questions.
$alloQuestionOrdering = false;
$start = ($page - 1) * $length;
$questionList = $objExercise->getQuestionForTeacher($start, $length);
$paginator = new Knp\Component\Pager\Paginator();
$pagination = $paginator->paginate([]);
$pagination->setTotalItemCount($nbrQuestions);
$pagination->setItemNumberPerPage($length);
$pagination->setCurrentPageNumber($page);
$pagination->renderer = function ($data) use ($url) {
$render = '<ul class="pagination">';
for ($i = 1; $i <= $data['pageCount']; $i++) {
$pageContent = '<li><a href="'.$url.'&page='.$i.'">'.$i.'</a></li>';
if ($data['current'] == $i) {
$pageContent = '<li class="active"><a href="#" >'.$i.'</a></li>';
}
$render .= $pageContent;
}
$render .= '</ul>';
return $render;
};
echo $pagination;
} else {
// Classic order
$questionList = $objExercise->selectQuestionList(true, true);
}
echo '
<div class="row hidden-xs">
<div class="col-sm-5"><strong>'.get_lang('Questions').'</strong></div>
@ -172,26 +218,7 @@ if (!$inATest) {
<div id="question_list">
';
if ($nbrQuestions) {
// Always getting list from DB
//$questionList = $objExercise->selectQuestionList(true);
// In the building exercise mode show question list ordered as is.
$objExercise->setCategoriesGrouping(false);
// Show exercises as in category settings
//$questionList = $objExercise->getQuestionListWithMediasUncompressed();
// In building mode show all questions not render by teacher order.
$objExercise->questionSelectionType = EX_Q_SELECTION_ORDERED;
// Get question list
$questionList = $objExercise->selectQuestionList(true, true);
$category_list = TestCategory::getListOfCategoriesNameForTest(
$objExercise->id,
false
);
$category_list = TestCategory::getListOfCategoriesNameForTest($objExercise->id, false);
if (is_array($questionList)) {
foreach ($questionList as $id) {
@ -209,10 +236,10 @@ if (!$inATest) {
[],
ICON_SIZE_TINY
),
api_get_self().'?'.api_get_cidreq().'&clone_question='.$id,
api_get_self().'?'.api_get_cidreq().'&clone_question='.$id.'&page='.$page,
['class' => 'btn btn-default btn-sm']
);
$edit_link = ($objQuestionTmp->type == CALCULATED_ANSWER && $objQuestionTmp->isAnswered())
$edit_link = $objQuestionTmp->type == CALCULATED_ANSWER && $objQuestionTmp->isAnswered()
? Display::span(
Display::return_icon(
'edit_na.png',
@ -234,11 +261,11 @@ if (!$inATest) {
'type' => $objQuestionTmp->selectType(),
'myid' => 1,
'editQuestion' => $id,
'page' => $page,
]),
['class' => 'btn btn-default btn-sm']
);
$delete_link = null;
if ($objExercise->edit_exercise_in_lp == true) {
$delete_link = Display::url(
Display::return_icon(
@ -251,6 +278,7 @@ if (!$inATest) {
.http_build_query([
'exerciseId' => $exerciseId,
'deleteQuestion' => $id,
'page' => $page,
]),
[
'id' => "delete_$id",
@ -259,6 +287,10 @@ if (!$inATest) {
);
}
if ($limitTeacherAccess && !api_is_platform_admin()) {
$delete_link = '';
}
$btnActions = implode(
PHP_EOL,
[$edit_link, $clone_link, $delete_link]
@ -266,7 +298,10 @@ if (!$inATest) {
$title = Security::remove_XSS($objQuestionTmp->selectTitle());
$title = strip_tags($title);
$move = Display::returnFontAwesomeIcon("arrows moved", 1, true);
$move = '&nbsp;';
if ($alloQuestionOrdering) {
$move = Display::returnFontAwesomeIcon('arrows moved', 1, true);
}
// Question name
$questionName =
@ -296,8 +331,7 @@ if (!$inATest) {
// Question score
$questionScore = $objQuestionTmp->selectWeighting();
echo '
<div id="question_id_list_'.$id.'">
echo '<div id="question_id_list_'.$id.'">
<div class="header_operations" data-exercise="'.$objExercise->selectId().'"
data-question="'.$id.'">
<div class="row">
@ -332,9 +366,7 @@ if (!$inATest) {
unset($objQuestionTmp);
}
}
}
if (!$nbrQuestions) {
} else {
echo Display::return_message(get_lang('NoQuestion'), 'warning');
}
echo '</div>'; //question list div

@ -2,6 +2,7 @@
/* For licensing terms, see /license.txt */
use ChamiloSession as Session;
use Knp\Component\Pager\Paginator;
/**
* Question Pool
@ -27,7 +28,6 @@ $exerciseId = isset($_REQUEST['exerciseId']) ? intval($_REQUEST['exerciseId']) :
$courseCategoryId = isset($_REQUEST['courseCategoryId']) ? intval($_REQUEST['courseCategoryId']) : null;
$exerciseLevel = isset($_REQUEST['exerciseLevel']) ? intval($_REQUEST['exerciseLevel']) : -1;
$answerType = isset($_REQUEST['answerType']) ? intval($_REQUEST['answerType']) : null;
$page = isset($_REQUEST['page']) ? intval($_REQUEST['page']) : 0;
$question_copy = isset($_REQUEST['question_copy']) ? intval($_REQUEST['question_copy']) : 0;
$session_id = isset($_REQUEST['session_id']) ? intval($_REQUEST['session_id']) : null;
$selected_course = isset($_GET['selected_course']) ? intval($_GET['selected_course']) : null;
@ -35,6 +35,9 @@ $selected_course = isset($_GET['selected_course']) ? intval($_GET['selected_cour
$course_id_changed = isset($_GET['course_id_changed']) ? intval($_GET['course_id_changed']) : null;
// save the id of the previous exercise selected by user to reset menu if we detect that user change course hub 13-10-2011
$exercise_id_changed = isset($_GET['exercise_id_changed']) ? intval($_GET['exercise_id_changed']) : null;
$questionId = isset($_GET['question_id']) && !empty($_GET['question_id']) ? (int) $_GET['question_id'] : '';
$description = isset($_GET['description']) ? Database::escape_string($_GET['description']) : '';
$page = isset($_GET['page']) ? (int) $_GET['page'] : 1;
// by default when we go to the page for the first time, we select the current course
if (!isset($_GET['selected_course']) && !isset($_GET['exerciseId'])) {
@ -45,16 +48,16 @@ $_course = api_get_course_info();
if (empty($objExercise) && !empty($fromExercise)) {
$objExercise = new Exercise();
$objExercise->read($fromExercise);
$objExercise->read($fromExercise, false);
}
$nameTools = get_lang('QuestionPool');
$interbreadcrumb[] = ["url" => "exercise.php?".api_get_cidreq(), "name" => get_lang('Exercises')];
$interbreadcrumb[] = ['url' => 'exercise.php?'.api_get_cidreq(), 'name' => get_lang('Exercises')];
if (!empty($objExercise)) {
$interbreadcrumb[] = [
"url" => "admin.php?exerciseId=".$objExercise->id."&".api_get_cidreq(),
"name" => $objExercise->selectTitle(true),
'url' => 'admin.php?exerciseId='.$objExercise->id.'&'.api_get_cidreq(),
'name' => $objExercise->selectTitle(true),
];
}
@ -71,9 +74,7 @@ if ($is_allowedToEdit) {
$old_question_obj = Question::read($old_question_id, $origin_course_id);
$courseId = $current_course['real_id'];
if ($old_question_obj) {
$old_question_obj->updateTitle(
$old_question_obj->selectTitle().' - '.get_lang('Copy')
);
$old_question_obj->updateTitle($old_question_obj->selectTitle().' - '.get_lang('Copy'));
//Duplicating the source question, in the current course
$new_id = $old_question_obj->duplicate($current_course);
//Reading new question
@ -97,6 +98,10 @@ if ($is_allowedToEdit) {
// Deletes a question from the database and all exercises
if ($delete) {
$limitTeacherAccess = api_get_configuration_value('limit_exercise_teacher_access');
if ($limitTeacherAccess && !api_is_platform_admin()) {
api_not_allowed(true);
}
// Construction of the Question object
$objQuestionTmp = Question::read($delete);
// if the question exists
@ -125,6 +130,9 @@ if ($is_allowedToEdit) {
// Adds the question ID represented by $recup into the list of questions for the current exercise
$objExercise->addToList($recup);
Session::write('objExercise', $objExercise);
Display::addFlash(
Display::return_message(get_lang('ItemAdded'), 'success')
);
} elseif (isset($_POST['recup']) && is_array($_POST['recup']) && $fromExercise) {
$list_recup = $_POST['recup'];
foreach ($list_recup as $course_id => $question_data) {
@ -204,11 +212,22 @@ Display::display_header($nameTools, 'Exercise');
// Menu
echo '<div class="actions">';
if (isset($type)) {
$url = api_get_self().'?type=1';
} else {
$url = api_get_self();
}
$url = api_get_self().'?'.api_get_cidreq().'&'.http_build_query(
[
'fromExercise' => $fromExercise,
'session_id' => $session_id,
'selected_course' => $selected_course,
'courseCategoryId' => $courseCategoryId,
'exerciseId' => $exerciseId,
'exerciseLevel' => $exerciseLevel,
'answerType' => $answerType,
'question_id' => $questionId,
'description' => Security::remove_XSS($description),
'course_id_changed' => $course_id_changed,
'exercise_id_changed' => $exercise_id_changed,
]
);
if (isset($fromExercise) && $fromExercise > 0) {
echo '<a href="admin.php?'.api_get_cidreq().'&exerciseId='.$fromExercise.'">'.
Display::return_icon('back.png', get_lang('GoBackToQuestionList'), '', ICON_SIZE_MEDIUM).'</a>';
@ -216,35 +235,36 @@ if (isset($fromExercise) && $fromExercise > 0) {
} else {
echo '<a href="exercise.php?'.api_get_cidreq().'">'.
Display::return_icon('back.png', get_lang('BackToExercisesList'), '', ICON_SIZE_MEDIUM).'</a>';
echo "<a href='admin.php?exerciseId=0'>".Display::return_icon('add_question.gif', get_lang('NewQu'), '', ICON_SIZE_MEDIUM)."</a>";
echo "<a href='admin.php?exerciseId=0'>".
Display::return_icon('add_question.gif', get_lang('NewQu'), '', ICON_SIZE_MEDIUM)."</a>";
$titleAdd = get_lang('ManageAllQuestions');
}
echo '</div>';
if ($displayMessage != "") {
if ($displayMessage != '') {
echo Display::return_message($displayMessage, 'confirm');
$displayMessage = "";
$displayMessage = '';
}
// Form
echo '<form class="form-horizontal" name="question_pool" method="GET" action="'.$url.'">';
// Title
echo '<legend>'.$nameTools.' - '.$titleAdd.'</legend>';
if (isset($type)) {
echo '<input type="hidden" name="type" value="1">';
}
echo '<input type="hidden" name="fromExercise" value="'.$fromExercise.'">';
// Session list, if sessions are used.
$sessionList = SessionManager::get_sessions_by_user(api_get_user_id(), api_is_platform_admin());
$tabAttrParam = ['onchange' => 'submit_form(this)'];
$labelFormRow = get_lang('Session');
$session_select_list = [];
foreach ($sessionList as $item) {
$session_select_list[$item['session_id']] = $item['session_name'];
}
$select_session_html = Display::select('session_id', $session_select_list, $session_id, $tabAttrParam);
echo Display::form_row($labelFormRow, $select_session_html);
$select_session_html = Display::select(
'session_id',
$session_select_list,
$session_id,
['onchange' => 'submit_form(this)']
);
echo Display::form_row(get_lang('Session'), $select_session_html);
// Course list, get course list of session, or for course where user is admin
if (!empty($session_id) && $session_id != '-1' && !empty($sessionList)) {
@ -256,9 +276,11 @@ if (!empty($session_id) && $session_id != '-1' && !empty($sessionList)) {
}
$course_list = $sessionInfo['courses'];
} else {
$course_list = CourseManager::get_course_list_of_user_as_course_admin(
api_get_user_id()
);
if (api_is_platform_admin()) {
$course_list = CourseManager::get_courses_list(0, 0, 'title');
} else {
$course_list = CourseManager::get_course_list_of_user_as_course_admin(api_get_user_id());
}
// Admin fix, add the current course in the question pool.
if (api_is_platform_admin()) {
@ -306,17 +328,8 @@ if ($course_id_changed) {
}
$course_id = $course_info['real_id'];
// Redefining table calls
$TBL_EXERCISE_QUESTION = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
$TBL_EXERCISES = Database::get_course_table(TABLE_QUIZ_TEST);
$TBL_QUESTIONS = Database::get_course_table(TABLE_QUIZ_QUESTION);
$TBL_REPONSES = Database::get_course_table(TABLE_QUIZ_ANSWER);
$TBL_CATEGORY = Database::get_course_table(TABLE_QUIZ_QUESTION_CATEGORY);
$TBL_COURSE_REL_CATEGORY = Database::get_course_table(TABLE_QUIZ_QUESTION_REL_CATEGORY);
// Get course categories for the selected course
// get category list for the course $selected_course
// Get category list for the course $selected_course
$categoryList = TestCategory::getCategoriesIdAndName($selected_course);
$selectCourseCategory = Display::select(
'courseCategoryId',
@ -334,6 +347,7 @@ $exercise_list = ExerciseLib::get_all_exercises_for_course_id(
$selected_course,
false
);
// Exercise List
$my_exercise_list = [];
$my_exercise_list['0'] = get_lang('AllExercises');
@ -351,6 +365,7 @@ if (is_array($exercise_list)) {
if ($exercise_id_changed == 1) {
reset_menu_lvl_type();
}
$select_exercise_html = Display::select(
'exerciseId',
$my_exercise_list,
@ -371,6 +386,7 @@ $levels = [
4 => 4,
5 => 5,
];
$select_difficulty_html = Display::select(
'exerciseLevel',
$levels,
@ -386,8 +402,6 @@ $question_list = Question::get_question_type_list();
$new_question_list = [];
$new_question_list['-1'] = get_lang('All');
if (!empty($_course)) {
$objExercise = new Exercise();
$objExercise->read($fromExercise);
foreach ($question_list as $key => $item) {
if ($objExercise->feedback_type == EXERCISE_FEEDBACK_TYPE_DIRECT) {
if (!in_array($key, [HOT_SPOT_DELINEATION, UNIQUE_ANSWER])) {
@ -402,6 +416,7 @@ if (!empty($_course)) {
}
}
}
// Answer type list
$select_answer_html = Display::select(
'answerType',
@ -412,17 +427,50 @@ $select_answer_html = Display::select(
);
echo Display::form_row(get_lang('AnswerType'), $select_answer_html);
$button = '<button class="save" type="submit" name="name" value="'.get_lang('Filter').'">'.get_lang('Filter').'</button>';
echo Display::form_row(get_lang('Id'), Display::input('text', 'question_id', $questionId));
echo Display::form_row(
get_lang('Description'),
Display::input('text', 'description', Security::remove_XSS($description))
);
$button = '<button class="btn btn-primary save" type="submit" name="name" value="'.get_lang('Filter').'">'.
get_lang('Filter').'</button>';
echo Display::form_row('', $button);
echo "<input type='hidden' id='course_id_changed' name='course_id_changed' value='0' />";
echo "<input type='hidden' id='exercise_id_changed' name='exercise_id_changed' value='0' />";
?>
</form>
<div class="clear"></div>
<form method="post" action="<?php echo $url.'?'.api_get_cidreq().'&fromExercise='.$fromExercise; ?>" >
<?php
echo '<input type="hidden" name="course_id" value="'.$selected_course.'">';
$mainQuestionList = [];
function getQuestions(
$getCount,
$start,
$length,
$exerciseId,
$courseCategoryId,
$selected_course,
$session_id,
$exerciseLevel,
$answerType,
$questionId,
$description
) {
$start = (int) $start;
$length = (int) $length;
$exerciseId = (int) $exerciseId;
$courseCategoryId = (int) $courseCategoryId;
$selected_course = (int) $selected_course;
$session_id = (int) $session_id;
$exerciseLevel = (int) $exerciseLevel;
$answerType = (int) $answerType;
$questionId = (int) $questionId;
$description = Database::escape_string($description);
$TBL_EXERCISE_QUESTION = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
$TBL_EXERCISES = Database::get_course_table(TABLE_QUIZ_TEST);
$TBL_QUESTIONS = Database::get_course_table(TABLE_QUIZ_QUESTION);
$TBL_COURSE_REL_CATEGORY = Database::get_course_table(TABLE_QUIZ_QUESTION_REL_CATEGORY);
// if we have selected an exercise in the list-box 'Filter'
if ($exerciseId > 0) {
@ -430,7 +478,10 @@ if ($exerciseId > 0) {
$from = '';
if (isset($courseCategoryId) && $courseCategoryId > 0) {
$from = ", $TBL_COURSE_REL_CATEGORY crc ";
$where .= " AND crc.c_id=$selected_course AND crc.question_id=qu.id AND crc.category_id=$courseCategoryId";
$where .= " AND
crc.c_id = $selected_course AND
crc.question_id = qu.id AND
crc.category_id = $courseCategoryId";
}
if (isset($exerciseLevel) && $exerciseLevel != -1) {
$where .= ' AND level='.$exerciseLevel;
@ -438,33 +489,43 @@ if ($exerciseId > 0) {
if (isset($answerType) && $answerType > 0) {
$where .= ' AND type='.$answerType;
}
$sql = "SELECT DISTINCT
if (!empty($questionId)) {
$where .= ' AND qu.iid='.$questionId;
}
if (!empty($description)) {
$where .= " AND qu.description LIKE '%$description%'";
}
$select = 'DISTINCT
id,
question,
type,
level
level,
qt.exercice_id exerciseId';
if ($getCount) {
$select = 'count(qu.iid) as count';
}
$sql = "SELECT $select
FROM
$TBL_EXERCISE_QUESTION qt,
$TBL_QUESTIONS qu
$from
WHERE
qt.question_id = qu.id
AND qt.exercice_id=$exerciseId
AND qt.c_id=$selected_course
AND qu.c_id=$selected_course
qt.question_id = qu.id AND
qt.exercice_id = $exerciseId AND
qt.c_id = $selected_course AND
qu.c_id = $selected_course
$where
ORDER BY question_order";
$result = Database::query($sql);
while ($row = Database::fetch_array($result, 'ASSOC')) {
$mainQuestionList[] = $row;
}
} elseif ($exerciseId == -1) {
// If we have selected the option 'Orphan questions' in the list-box 'Filter'
$level_where = '';
$from = '';
if (isset($courseCategoryId) && $courseCategoryId > 0) {
$from = " INNER JOIN $TBL_COURSE_REL_CATEGORY crc ON crc.question_id=q.id AND crc.c_id= q.c_id ";
$from = " INNER JOIN $TBL_COURSE_REL_CATEGORY crc
ON crc.question_id = q.id AND crc.c_id = q.c_id ";
$level_where .= " AND
crc.c_id = $selected_course AND
crc.category_id = $courseCategoryId";
@ -477,9 +538,23 @@ if ($exerciseId > 0) {
$answer_where = ' AND type='.$answerType;
}
if (!empty($questionId)) {
$answer_where .= ' AND q.iid='.$questionId;
}
if (!empty($description)) {
$answer_where .= " AND q.description LIKE '%$description%'";
}
$select = ' q.*, r.exercice_id exerciseId ';
if ($getCount) {
$select = 'count(q.iid) as count';
}
// @todo fix this query with the new id field
$sql = " (
SELECT q.* FROM $TBL_QUESTIONS q
SELECT $select
FROM $TBL_QUESTIONS q
INNER JOIN $TBL_EXERCISE_QUESTION r
ON (q.c_id = r.c_id AND q.id = r.question_id)
INNER JOIN $TBL_EXERCISES ex
@ -488,40 +563,44 @@ if ($exerciseId > 0) {
WHERE
ex.c_id = '$selected_course' AND
ex.active = '-1'
$level_where $answer_where
$level_where
$answer_where
)
UNION
(
SELECT q.* FROM $TBL_QUESTIONS q
SELECT $select
FROM $TBL_QUESTIONS q
LEFT OUTER JOIN $TBL_EXERCISE_QUESTION r
ON (q.c_id = r.c_id AND q.id = r.question_id)
$from
WHERE
q.c_id = '$selected_course' AND
r.question_id is null
$level_where $answer_where
$level_where
$answer_where
)
UNION
(
SELECT q.* FROM $TBL_QUESTIONS q
SELECT $select
FROM $TBL_QUESTIONS q
INNER JOIN $TBL_EXERCISE_QUESTION r
ON (q.c_id = r.c_id AND q.id = r.question_id)
$from
WHERE
r.c_id = '$selected_course' AND
(r.exercice_id = '-1' OR r.exercice_id = '0')
$level_where $answer_where
)";
$result = Database::query($sql);
while ($row = Database::fetch_array($result, 'ASSOC')) {
$mainQuestionList[] = $row;
$level_where
$answer_where
)
";
if ($getCount) {
$sql = "SELECT SUM(count) count FROM ($sql) as total";
}
} else {
// All tests for selected course
// If we have not selected any option in the list-box 'Filter'
$filter = '';
$from = '';
if (isset($courseCategoryId) && $courseCategoryId > 0) {
$from = ", $TBL_COURSE_REL_CATEGORY crc ";
$filter .= " AND
@ -536,89 +615,27 @@ if ($exerciseId > 0) {
$filter .= ' AND qu.type='.$answerType.' ';
}
if (!empty($session_id) && $session_id != '-1') {
$mainQuestionList = [];
if (!empty($course_list)) {
foreach ($course_list as $course_item) {
$courseItemId = $course_item['real_id'];
if (!empty($selected_course) && $selected_course != '-1') {
if ($selected_course != $courseItemId) {
continue;
}
}
$exerciseList = ExerciseLib::get_all_exercises($course_item, $session_id);
if (!empty($exerciseList)) {
foreach ($exerciseList as $exercise) {
$my_exercise = new Exercise($courseItemId);
$my_exercise->read($exercise['id']);
if (!empty($my_exercise)) {
if (!empty($my_exercise->questionList)) {
foreach ($my_exercise->questionList as $question_id) {
$question_obj = Question::read(
$question_id,
$courseItemId
);
if ($exerciseLevel != '-1') {
if ($exerciseLevel != $question_obj->level) {
continue;
}
}
if ($answerType > 0) {
if ($answerType != $question_obj->type) {
continue;
}
}
$categoryIdFromQuestion = TestCategory::getCategoryForQuestion(
$question_obj->id,
$selected_course
);
if ($courseCategoryId > 0 &&
$categoryIdFromQuestion != $courseCategoryId
) {
continue;
if (!empty($questionId)) {
$filter .= ' AND qu.iid='.$questionId;
}
if (!empty($objExercise) &&
$objExercise->feedback_type != EXERCISE_FEEDBACK_TYPE_DIRECT
) {
if ($question_obj->type == HOT_SPOT_DELINEATION) {
continue;
}
if (!empty($description)) {
$filter .= " AND qu.description LIKE '%$description%'";
}
$question_row = [
'id' => $question_obj->id,
'question' => $question_obj->question,
'type' => $question_obj->type,
'level' => $question_obj->level,
'exercise_id' => $exercise['id'],
'exercise_name' => $exercise['title'],
'course_id' => $courseItemId,
];
$mainQuestionList[] = $question_row;
}
}
}
}
}
}
}
} else {
if ($session_id == -1 || empty($session_id)) {
$session_id = 0;
}
$sessionCondition = api_get_session_condition($session_id, true, 'q.session_id');
$select = 'qu.id, question, qu.type, level, q.session_id, qt.exercice_id exerciseId ';
if ($getCount) {
$select = 'count(qu.iid) as count';
}
// All tests for the course selected, not in session
$sql = "SELECT DISTINCT qu.id, question, qu.type, level, q.session_id
$sql = "SELECT DISTINCT
$select
FROM
$TBL_QUESTIONS as qu,
$TBL_EXERCISE_QUESTION as qt,
@ -630,18 +647,87 @@ if ($exerciseId > 0) {
q.c_id = $selected_course AND
qu.id = qt.question_id
$sessionCondition AND
q.id = qt.exercice_id $filter
q.id = qt.exercice_id
$filter
ORDER BY session_id ASC";
}
if ($getCount) {
$result = Database::query($sql);
$row = Database::fetch_array($result, 'ASSOC');
return (int) $row['count'];
}
$sql .= " LIMIT $start, $length";
$result = Database::query($sql);
$mainQuestionList = [];
while ($row = Database::fetch_array($result, 'ASSOC')) {
$mainQuestionList[] = $row;
}
return $mainQuestionList;
}
// forces the value to 0
$exerciseId = 0;
$nbrQuestions = getQuestions(
true,
null,
null,
$exerciseId,
$courseCategoryId,
$selected_course,
$session_id,
$exerciseLevel,
$answerType,
$questionId,
$description
);
$length = api_get_configuration_value('question_pagination_length');
if (empty($length)) {
$length = 20;
}
$start = ($page - 1) * $length;
$paginator = new Paginator();
$pagination = $paginator->paginate([]);
$pagination->setTotalItemCount($nbrQuestions);
$pagination->setItemNumberPerPage($length);
$pagination->setCurrentPageNumber($page);
$pagination->renderer = function ($data) use ($url) {
$render = '';
if ($data['pageCount'] > 1) {
$render = '<ul class="pagination">';
for ($i = 1; $i <= $data['pageCount']; $i++) {
$pageContent = '<li><a href="'.$url.'&page='.$i.'">'.$i.'</a></li>';
if ($data['current'] == $i) {
$pageContent = '<li class="active"><a href="#" >'.$i.'</a></li>';
}
$render .= $pageContent;
}
$render .= '</ul>';
}
$nbrQuestions = count($mainQuestionList);
return $render;
};
$mainQuestionList = getQuestions(
false,
$start,
$length,
$exerciseId,
$courseCategoryId,
$selected_course,
$session_id,
$exerciseLevel,
$answerType,
$questionId,
$description
);
// build the line of the array to display questions
// Actions are different if you launch the question_pool page
@ -662,108 +748,60 @@ $nbrQuestions = count($mainQuestionList);
*/
if ($fromExercise <= 0) {
// NOT IN A TEST - IN THE COURSE
if ($selected_course == api_get_course_int_id()) {
$actionLabel = get_lang('Modify');
$actionIcon1 = "edit";
$actionIcon2 = "delete";
// We are in the course, question title can be a link to the question edit page
$questionTagA = 1;
} else { // NOT IN A TEST - NOT IN THE COURSE
// NOT IN A TEST - NOT IN THE COURSE
$actionLabel = get_lang('Reuse');
$actionIcon1 = get_lang('MustBeInATest');
$actionIcon2 = "";
$actionIcon2 = '';
// We are not in this course, to messy if we link to the question in another course
$questionTagA = 0;
}
} else {
// IN A TEST - IN THE COURSE
if ($selected_course == api_get_course_int_id()) {
$actionLabel = get_lang('Reuse');
$actionIcon1 = "add";
$actionIcon2 = "";
// NOT IN A TEST - IN THE COURSE
$actionLabel = get_lang('Modify');
$actionIcon1 = 'edit';
$actionIcon2 = 'delete';
// We are in the course, question title can be a link to the question edit page
$questionTagA = 1;
}
} else {
// IN A TEST - NOT IN THE COURSE
$actionLabel = get_lang('Reuse');
$actionIcon1 = "clone";
$actionIcon2 = "";
$actionIcon1 = 'clone';
$actionIcon2 = '';
$questionTagA = 0;
if ($selected_course == api_get_course_int_id()) {
// IN A TEST - IN THE COURSE
$actionLabel = get_lang('Reuse');
$actionIcon1 = 'add';
$actionIcon2 = '';
$questionTagA = 1;
}
}
// Display table
$header = [
[
get_lang('QuestionUpperCaseFirstLetter'),
false,
["style" => "text-align:center"],
'',
],
[
get_lang('Type'),
false,
["style" => "text-align:center"],
["style" => "text-align:center"],
'',
],
[
get_lang('QuestionCategory'),
false,
["style" => "text-align:center"],
["style" => "text-align:center"],
'',
],
[
get_lang('Difficulty'),
false,
["style" => "text-align:center"],
["style" => "text-align:center"],
'',
],
[
$actionLabel,
false,
["style" => "text-align:center"],
["style" => "text-align:center"],
'',
],
];
$data = [];
if (is_array($mainQuestionList)) {
foreach ($mainQuestionList as $question) {
/*if ($hideDoubles) {
if (in_array($question['question'], $questionAdded)) {
continue;
}
}
$questionAdded[$question['question']] = $question;*/
$row = [];
// This function checks if the question can be read
$question_type = get_question_type_for_question(
$selected_course,
$question['id']
);
$question_type = get_question_type_for_question($selected_course, $question['id']);
if (empty($question_type)) {
continue;
}
$sessionId = isset($question['session_id']) ? $question['session_id'] : null;
$exerciseName = isset($question['exercise_name']) ? '<br />('.$question['exercise_id'].') ' : null;
$row[] = get_a_tag_for_question(
$row[] = getLinkForQuestion(
$questionTagA,
$fromExercise,
$question['id'],
$question['type'],
$question['question'],
$sessionId
$sessionId,
$question['exerciseId']
).$exerciseName;
$row[] = $question_type;
$row[] = get_question_categorie_for_question($selected_course, $question['id']);
$row[] = TestCategory::getCategoryNameForQuestion($question['id'], $selected_course);
$row[] = $question['level'];
$row[] = get_action_icon_for_question(
$actionIcon1,
@ -776,8 +814,9 @@ if (is_array($mainQuestionList)) {
$exerciseLevel,
$answerType,
$session_id,
$exerciseId
)."&nbsp;".
$question['exerciseId'],
$objExercise
).'&nbsp;'.
get_action_icon_for_question(
$actionIcon2,
$fromExercise,
@ -789,12 +828,53 @@ if (is_array($mainQuestionList)) {
$exerciseLevel,
$answerType,
$session_id,
$exerciseId
$question['exerciseId'],
$objExercise
);
$data[] = $row;
}
}
// Display table
$header = [
[
get_lang('QuestionUpperCaseFirstLetter'),
false,
['style' => 'text-align:center'],
'',
],
[
get_lang('Type'),
false,
['style' => 'text-align:center'],
['style' => 'text-align:center'],
'',
],
[
get_lang('QuestionCategory'),
false,
['style' => 'text-align:center'],
['style' => 'text-align:center'],
'',
],
[
get_lang('Difficulty'),
false,
['style' => 'text-align:center'],
['style' => 'text-align:center'],
'',
],
[
$actionLabel,
false,
['style' => 'text-align:center'],
['style' => 'text-align:center'],
'',
],
];
echo $pagination;
Display::display_sortable_table(
$header,
$data,
@ -802,10 +882,6 @@ Display::display_sortable_table(
['per_page_default' => 999, 'per_page' => 999, 'page_nr' => 1]
);
if (!$nbrQuestions) {
echo get_lang('NoQuestion');
}
Display::display_footer();
/**
@ -840,35 +916,44 @@ function reset_menu_exo_lvl_type()
*
* @param int $in_addA
* @param int $in_fromex
* @param int $in_questionid
* @param int $in_questiontype
* @param string $in_questionname
* @param int $questionId
* @param int $questiontype
* @param string $questionName
* @param int $sessionId
* @param int $exerciseId
*
* @return string
*
* @author hubert.borderiou
*/
function get_a_tag_for_question(
function getLinkForQuestion(
$in_addA,
$in_fromex,
$in_questionid,
$in_questiontype,
$in_questionname,
$sessionId
$fromExercise,
$questionId,
$questionType,
$questionName,
$sessionId,
$exerciseId
) {
$res = $in_questionname;
$sessionIcon = null;
$result = $questionName;
if ($in_addA) {
$sessionIcon = '';
if (!empty($sessionId) && $sessionId != -1) {
$sessionIcon = ' '.Display::return_icon('star.png', get_lang('Session'));
}
$res = "<a href='admin.php?".api_get_cidreq()."&editQuestion=$in_questionid&type=$in_questiontype&fromExercise=$in_fromex'>".
$res.$sessionIcon.
"</a>";
$exerciseId = (int) $exerciseId;
$questionId = (int) $questionId;
$questionType = (int) $questionType;
$fromExercise = (int) $fromExercise;
$result = Display::url(
$questionName.$sessionIcon,
"admin.php?".api_get_cidreq().
"&exerciseId=$exerciseId&editQuestion=$questionId&type=$questionType&fromExercise=$fromExercise"
);
}
return $res;
return $result;
}
/**
@ -896,40 +981,45 @@ function get_action_icon_for_question(
$in_exerciseLevel,
$in_answerType,
$in_session_id,
$in_exercise_id
$in_exercise_id,
Exercise $myObjEx
) {
$res = "";
$limitTeacherAccess = api_get_configuration_value('limit_exercise_teacher_access');
$getParams = "&selected_course=$in_selected_course&courseCategoryId=$in_courseCategoryId&exerciseId=$in_exercise_id&exerciseLevel=$in_exerciseLevel&answerType=$in_answerType&session_id=$in_session_id";
$res = '';
switch ($in_action) {
case 'delete':
$res = "<a href='".api_get_self()."?".api_get_cidreq().$getParams."&delete=$in_questionid' onclick='return confirm_your_choice()'>";
$res .= Display::return_icon("delete.png", get_lang('Delete'));
if ($limitTeacherAccess && !api_is_platform_admin()) {
break;
}
$res = "<a href='".api_get_self()."?".
api_get_cidreq().$getParams."&delete=$in_questionid' onclick='return confirm_your_choice()'>";
$res .= Display::return_icon('delete.png', get_lang('Delete'));
$res .= "</a>";
break;
case 'edit':
$res = get_a_tag_for_question(
$res = getLinkForQuestion(
1,
$from_exercise,
$in_questionid,
$in_questiontype,
Display::return_icon("edit.png", get_lang('Modify')),
$in_session_id
Display::return_icon('edit.png', get_lang('Modify')),
$in_session_id,
$in_exercise_id
);
break;
case 'add':
// add if question is not already in test
$myObjEx = new Exercise();
$myObjEx->read($from_exercise);
$res = "-";
if (!$myObjEx->isInList($in_questionid)) {
$res = "<a href='".api_get_self()."?".api_get_cidreq().$getParams."&recup=$in_questionid&fromExercise=$from_exercise'>";
$res .= Display::return_icon("view_more_stats.gif", get_lang('InsertALinkToThisQuestionInTheExercise'));
$res = '-';
if (!$myObjEx->hasQuestion($in_questionid)) {
$res = "<a href='".api_get_self()."?".
api_get_cidreq().$getParams."&recup=$in_questionid&fromExercise=$from_exercise'>";
$res .= Display::return_icon('view_more_stats.gif', get_lang('InsertALinkToThisQuestionInTheExercise'));
$res .= "</a>";
}
unset($myObjEx);
break;
case 'clone':
$url = api_get_self()."?".api_get_cidreq().$getParams."&question_copy=$in_questionid&course_id=$in_selected_course&fromExercise=$from_exercise";
$url = api_get_self().'?'.api_get_cidreq().$getParams.
"&question_copy=$in_questionid&course_id=$in_selected_course&fromExercise=$from_exercise";
$res = Display::url(
Display::return_icon('cd.png', get_lang('ReUseACopyInCurrentTest')),
$url
@ -955,20 +1045,7 @@ function get_question_type_for_question($in_selectedcourse, $in_questionid)
if (!empty($myObjQuestion)) {
list($typeImg, $typeExpl) = $myObjQuestion->get_type_icon_html();
$questionType = Display::tag('div', Display::return_icon($typeImg, $typeExpl, [], 32), []);
unset($myObjQuestion);
}
return $questionType;
}
/**
* Return the name of the category for the question in a course.
*
* @author hubert.borderiou 13-10-2011
*/
function get_question_categorie_for_question($in_courseid, $in_questionid)
{
$cat = TestCategory::getCategoryNameForQuestion($in_questionid, $in_courseid);
return $cat;
}

@ -1,69 +1,106 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CoreBundle\Entity\TrackEExercises;
require_once __DIR__.'/../inc/global.inc.php';
$isAllowedToEdit = api_is_allowed_to_edit(true, true);
if (!$isAllowedToEdit) {
api_not_allowed(true);
exit;
}
if (!isset($_REQUEST['user'], $_REQUEST['exercise'], $_REQUEST['id'])) {
api_not_allowed(true);
exit;
}
$courseId = api_get_course_int_id();
$sessionId = api_get_session_id();
$em = Database::getManager();
$trackedExercise = $em
->getRepository('ChamiloCoreBundle:TrackEExercises')
->find(intval($_REQUEST['id']));
/** @var TrackEExercises $trackedExercise */
$trackedExercise = $em->getRepository('ChamiloCoreBundle:TrackEExercises')->find($_REQUEST['id']);
if ($trackedExercise->getExeUserId() != intval($_REQUEST['user']) ||
$trackedExercise->getExeExoId() != intval($_REQUEST['exercise'])
) {
api_not_allowed(true);
if (empty($trackedExercise)) {
exit;
}
$attempts = $em->getRepository('ChamiloCoreBundle:TrackEAttempt')
->findBy([
'exeId' => $trackedExercise->getExeId(),
'userId' => $trackedExercise->getExeUserId(),
]);
$studentId = $trackedExercise->getExeUserId();
$exerciseId = $trackedExercise->getExeExoId();
$exeId = $trackedExercise->getExeId();
$newResult = 0;
/** @var \Chamilo\CoreBundle\Entity\TrackEAttempt $attempt */
foreach ($attempts as $attempt) {
$questionId = $attempt->getQuestionId();
if ($studentId != intval($_REQUEST['user']) ||
$exerciseId != intval($_REQUEST['exercise'])
) {
exit;
}
$question = $em->find('ChamiloCourseBundle:CQuizQuestion', $questionId);
$questionList = $trackedExercise->getDataTracking();
if (!$question) {
continue;
if (empty($questionList)) {
exit;
}
$answers = $em->getRepository('ChamiloCourseBundle:CQuizAnswer')->findBy([
'questionId' => $questionId,
'correct' => 1,
]);
$newMarks = 0;
foreach ($answers as $answer) {
if ($answer->getId() != $attempt->getAnswer()) {
continue;
$questionList = explode(',', $questionList);
$exercise = new Exercise($courseId);
$exercise->read($exerciseId);
$totalScore = 0;
$totalWeight = 0;
foreach ($questionList as $questionId) {
$question = Question::read($questionId, $courseId);
$totalWeight += $question->selectWeighting();
// We're inside *one* question. Go through each possible answer for this question
if ($question->type === MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY) {
$result = $exercise->manage_answer(
$exeId,
$questionId,
[],
'exercise_result',
[],
false,
true,
false,
$exercise->selectPropagateNeg(),
[],
[],
true
);
} else {
$result = $exercise->manage_answer(
$exeId,
$questionId,
[],
'exercise_result',
[],
false,
true,
false,
$exercise->selectPropagateNeg(),
[],
[],
true
);
}
$newMarks += $answer->getPonderation();
// Adding the new score.
$totalScore += $result['score'];
}
$newResult += $newMarks;
$attempt->setMarks($newMarks);
$em->merge($attempt);
$remindList = $trackedExercise->getQuestionsToCheck();
if (!empty($remindList)) {
$remindList = explode(',', $remindList);
}
$trackedExercise->setExeResult($newResult);
$table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
$sql = "UPDATE $table SET
exe_result = '$totalScore',
exe_weighting = '$totalWeight'
WHERE exe_id = $exeId";
Database::query($sql);
$em->merge($trackedExercise);
$em->flush();
echo $totalScore.'/'.$totalWeight;

@ -10,10 +10,9 @@ use ChamiloSession as Session;
*/
require_once __DIR__.'/../inc/global.inc.php';
$id = isset($_REQUEST['id']) ? intval($_GET['id']) : null; //exe id
$show_headers = isset($_REQUEST['show_headers']) ? intval($_REQUEST['show_headers']) : null; //exe id
$id = isset($_REQUEST['id']) ? (int) $_GET['id'] : null; //exe id
$show_headers = isset($_REQUEST['show_headers']) ? (int) $_REQUEST['show_headers'] : null;
$origin = api_get_origin();
$this_section = 'results';
if ($origin == 'learnpath') {
$show_headers = false;
@ -40,11 +39,14 @@ $student_id = $track_exercise_info['exe_user_id'];
$current_user_id = api_get_user_id();
$objExercise = new Exercise();
if (!empty($exercise_id)) {
$objExercise->read($exercise_id);
}
if (empty($objExercise)) {
api_not_allowed($show_headers);
}
// Only users can see their own results
if (!$is_allowedToEdit) {
if ($student_id != $current_user_id) {
@ -58,10 +60,10 @@ $htmlHeadXtra[] = '<script src="'.api_get_path(WEB_LIBRARY_JS_PATH).'annotation/
if ($show_headers) {
$interbreadcrumb[] = [
"url" => "exercise.php?".api_get_cidreq(),
"name" => get_lang('Exercises'),
'url' => 'exercise.php?'.api_get_cidreq(),
'name' => get_lang('Exercises'),
];
$interbreadcrumb[] = ["url" => "#", "name" => get_lang('Result')];
$interbreadcrumb[] = ['url' => '#', 'name' => get_lang('Result')];
$this_section = SECTION_COURSES;
Display::display_header();
} else {

@ -132,15 +132,15 @@ function edit_category_form($action)
get_lang('CategoryDescription'),
false,
false,
['ToolbarSet' => 'test_category', 'Height' => '200']
['ToolbarSet' => 'TestQuestionDescription', 'Height' => '200']
);
$form->addButtonSave(get_lang('ModifyCategory'), 'SubmitNote');
// setting the defaults
$defaults = [];
$defaults["category_id"] = $objcat->id;
$defaults["category_name"] = $objcat->name;
$defaults["category_description"] = $objcat->description;
$defaults['category_id'] = $objcat->id;
$defaults['category_name'] = $objcat->name;
$defaults['category_description'] = $objcat->description;
$form->setDefaults($defaults);
// setting the rules
@ -213,7 +213,7 @@ function add_category_form($action)
get_lang('CategoryDescription'),
false,
false,
['ToolbarSet' => 'test_category', 'Height' => '200']
['ToolbarSet' => 'TestQuestionDescription', 'Height' => '200']
);
$form->addButtonCreate(get_lang('AddTestCategory'), 'SubmitNote');
// setting the rules

@ -334,7 +334,7 @@ class UniqueAnswer extends Question
//$list_destination = $form -> getSubmitValue('destination'.$i);
//$destination_str = $form -> getSubmitValue('destination'.$i);
$try = $scenario['try'.$i];
$try = !empty($scenario['try'.$i]);
$lp = $scenario['lp'.$i];
$destination = $scenario['destination'.$i];
$url = trim($scenario['url'.$i]);

@ -129,18 +129,23 @@ function lp_upload_quiz_main()
*/
function lp_upload_quiz_action_handling()
{
$_course = api_get_course_info();
$courseId = $_course['real_id'];
if (!isset($_POST['submit_upload_quiz'])) {
return;
}
$_course = api_get_course_info();
if (empty($_course)) {
return false;
}
$courseId = $_course['real_id'];
// Get the extension of the document.
$path_info = pathinfo($_FILES['user_upload_quiz']['name']);
// Check if the document is an Excel document
if ($path_info['extension'] != 'xls') {
if (!in_array($path_info['extension'], ['xls', 'xlsx'])) {
return;
}
@ -543,7 +548,8 @@ function lp_upload_quiz_action_handling()
$lpObject = Session::read('lpobject');
if (!empty($lpObject)) {
$oLP = unserialize($lpObject);
/** @var learnpath $oLP */
$oLP = UnserializeApi::unserialize('lp', $lpObject);
if (is_object($oLP)) {
if ((empty($oLP->cc)) || $oLP->cc != api_get_course_id()) {
$oLP = null;

@ -15,7 +15,6 @@ api_protect_course_script(true);
/* Libraries & config files */
require_once api_get_path(SYS_CODE_PATH).'forum/forumfunction.inc.php';
require_once api_get_path(SYS_CODE_PATH).'forum/forumconfig.inc.php';
/* MAIN CODE */
$group_id = api_get_group_id();
$user_id = api_get_user_id();

@ -2,6 +2,7 @@
/* For licensing terms, see /license.txt */
// not used??
exit;
require_once '../inc/global.inc.php';
@ -28,6 +29,11 @@ $d_id = (int) $d_id;
$d_number = (int) $d_number;
$sql4 = "UPDATE set_module SET cal_day_num = $d_number WHERE id = $d_id ";
Database::query($sql4);
print_r(unserialize(Security::remove_XSS($_POST['aaa'])));
print_r(
UnserializeApi::unserialize(
'not_allowed_classes',
Security::remove_XSS($_POST['aaa'])
)
);
Display::display_footer();

@ -165,7 +165,7 @@ if (api_is_allowed_to_edit(null, true)) {
).get_lang('ViewUser').'</a>';
}
}
echo '<a href="../mySpace/myStudents.php?'.api_get_cidreq().'&origin=user_course&student='.$userIdViewed.'&details=true&course='.$_course['id'].'">'.Display::return_icon('stats.png', get_lang('UserStatistics'), '', ICON_SIZE_MEDIUM).get_lang('UserStatistics').'</a>';
echo '<a href="../mySpace/myStudents.php?'.api_get_cidreq().'&origin=user_course&student='.$userIdViewed.'&details=true&course='.$_course['id'].'">'.Display::return_icon('statistics.png', get_lang('UserStatistics'), '', ICON_SIZE_MEDIUM).get_lang('UserStatistics').'</a>';
echo '</div>';
} else {
if ($tool_info['visibility'] == 1) {

Loading…
Cancel
Save