Allow exercise categories requires DB change and configuration BT#15636

configuration value: 'allow_exercise_categories'
pull/2990/head
Julio 6 years ago
parent 55c3bed3ca
commit fb3483efbb
  1. 146
      main/exercise/category.php
  2. 308
      main/exercise/exercise.class.php
  3. 1391
      main/exercise/exercise.php
  4. 22
      main/inc/ajax/model.ajax.php
  5. 270
      main/inc/lib/ExerciseCategoryManager.php
  6. 21
      main/inc/lib/display.lib.php
  7. 9
      main/inc/lib/formvalidator/FormValidator.class.php
  8. 181
      main/inc/lib/pear/PEAR.php
  9. 12
      main/inc/lib/pear/Pager/Pager.php
  10. 55
      main/inc/lib/sortable_table.class.php
  11. 21
      main/inc/lib/table_sort.class.php
  12. 5
      main/install/configuration.dist.php
  13. 88
      main/lp/learnpath.class.php
  14. 3
      main/lp/lp_add_item.php
  15. 219
      src/Chamilo/CourseBundle/Entity/CExerciseCategory.php
  16. 7
      src/Chamilo/CourseBundle/Entity/CQuiz.php
  17. 2
      src/Chamilo/CourseBundle/Entity/CQuizCategory.php

@ -0,0 +1,146 @@
<?php
/* For licensing terms, see /license.txt */
require_once __DIR__.'/../inc/global.inc.php';
if (api_get_configuration_value('allow_exercise_categories') === false) {
api_not_allowed();
}
api_protect_course_script();
if (!api_is_allowed_to_edit()) {
api_not_allowed(true);
}
$interbreadcrumb[] = [
'url' => api_get_path(WEB_CODE_PATH).'exercise/exercise.php?'.api_get_cidreq(),
'name' => get_lang('Exercises')
];
$courseId = api_get_course_int_id();
$url = api_get_path(WEB_AJAX_PATH).'model.ajax.php?a=get_exercise_categories&c_id='.$courseId.'&'.api_get_cidreq();
$action = isset($_GET['action']) ? Security::remove_XSS($_GET['action']) : '';
$obj = new ExerciseCategoryManager();
$check = Security::check_token('request');
$token = Security::get_token();
//Add the JS needed to use the jqgrid
$htmlHeadXtra[] = api_get_jqgrid_js();
//The order is important you need to check the the $column variable in the model.ajax.php file
$columns = [
get_lang('Name'),
get_lang('Actions'),
];
// Column config
$column_model = [
[
'name' => 'name',
'index' => 'name',
'width' => '140',
'align' => 'left',
],
[
'name' => 'actions',
'index' => 'actions',
'width' => '40',
'align' => 'left',
'formatter' => 'action_formatter',
'sortable' => 'false',
],
];
// Autowidth
$extra_params['autowidth'] = 'true';
// height auto
$extra_params['height'] = 'auto';
$action_links = $obj->getJqgridActionLinks($token);
$htmlHeadXtra[] = '<script>
$(function() {
// grid definition see the $obj->display() function
'.Display::grid_js(
'categories',
$url,
$columns,
$column_model,
$extra_params,
[],
$action_links,
true
).'
});
</script>';
$url = api_get_self().'?'.api_get_cidreq();
switch ($action) {
case 'add':
$interbreadcrumb[] = ['url' => $url, 'name' => get_lang('Categories')];
$interbreadcrumb[] = ['url' => '#', 'name' => get_lang('Add')];
$form = $obj->return_form($url.'&action=add', 'add');
// The validation or display
if ($form->validate()) {
$values = $form->exportValues();
unset($values['id']);
$res = $obj->save($values);
if ($res) {
Display::addFlash(Display::return_message(get_lang('ItemAdded'), 'confirmation'));
}
header('Location: '.$url);
exit;
} else {
$content = '<div class="actions">';
$content .= '<a href="'.$url.'">'.
Display::return_icon('back.png', get_lang('Back'), '', ICON_SIZE_MEDIUM).'</a>';
$content .= '</div>';
$form->addElement('hidden', 'sec_token');
$form->setConstants(['sec_token' => $token]);
$content .= $form->returnForm();
}
break;
case 'edit':
$interbreadcrumb[] = ['url' => $url, 'name' => get_lang('Categories')];
$interbreadcrumb[] = ['url' => '#', 'name' => get_lang('Edit')];
$form = $obj->return_form($url.'&action=edit&id='.intval($_GET['id']), 'edit');
// The validation or display
if ($form->validate()) {
$values = $form->exportValues();
$res = $obj->update($values);
if ($res) {
Display::addFlash(Display::return_message(get_lang('ItemUpdated'), 'confirmation'));
}
header('Location: '.$url);
exit;
} else {
$content = '<div class="actions">';
$content .= '<a href="'.$url.'">'.
Display::return_icon('back.png', get_lang('Back'), '', ICON_SIZE_MEDIUM).'</a>';
$content .= '</div>';
$form->addElement('hidden', 'sec_token');
$form->setConstants(['sec_token' => $token]);
$content .= $form->returnForm();
}
break;
case 'delete':
$res = $obj->delete($_GET['id']);
if ($res) {
Display::addFlash(Display::return_message(get_lang('ItemDeleted'), 'confirmation'));
}
header('Location: '.$url);
exit;
break;
default:
$content = $obj->display();
break;
}
Display::display_header();
echo $content;

@ -1652,6 +1652,11 @@ class Exercise
'hide_question_title' => $this->getHideQuestionTitle(),
];
$allow = api_get_configuration_value('allow_exercise_categories');
if ($allow === true) {
$params['exercise_category_id'] = $this->getExerciseCategoryId();
}
$allow = api_get_configuration_value('allow_quiz_show_previous_button_setting');
if ($allow === true) {
$params['show_previous_button'] = $this->showPreviousButton();
@ -1813,6 +1818,21 @@ class Exercise
*/
public function delete()
{
$limitTeacherAccess = api_get_configuration_value('limit_exercise_teacher_access');
if ($limitTeacherAccess && !api_is_platform_admin()) {
return false;
}
$locked = api_resource_is_locked_by_gradebook(
$this->id,
LINK_EXERCISE
);
if ($locked) {
return false;
}
$table = Database::get_course_table(TABLE_QUIZ_TEST);
$sql = "UPDATE $table SET active='-1'
WHERE c_id = ".$this->course_id." AND id = ".intval($this->id);
@ -1835,11 +1855,21 @@ class Exercise
Skill::deleteSkillsFromItem($this->iId, ITEM_TYPE_EXERCISE);
if (api_get_setting('search_enabled') == 'true' &&
if (api_get_setting('search_enabled') === 'true' &&
extension_loaded('xapian')
) {
$this->search_engine_delete();
}
$linkInfo = GradebookUtils::isResourceInCourseGradebook(
$this->course['code'],
LINK_EXERCISE,
$this->id,
$this->sessionId
);
if ($linkInfo !== false) {
GradebookUtils::remove_resource_from_course_gradebook($linkInfo['id']);
}
}
/**
@ -4335,7 +4365,7 @@ class Exercise
echo '<tr>';
if (!in_array($this->results_disabled, [
RESULT_DISABLE_SHOW_ONLY_IN_CORRECT_ANSWER,
RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS_AND_RANKING,
//RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS_AND_RANKING,
])
) {
echo '<td>'.$s_answer_label.'</td>';
@ -4382,7 +4412,7 @@ class Exercise
if ($this->showExpectedChoice()) {
if (!in_array($this->results_disabled, [
RESULT_DISABLE_SHOW_ONLY_IN_CORRECT_ANSWER,
RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS_AND_RANKING,
//RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS_AND_RANKING,
])
) {
echo '<td>'.$user_answer.'</td>';
@ -4628,6 +4658,7 @@ class Exercise
if ($debug) {
error_log('Showing questions $from '.$from);
}
if ($from === 'exercise_result') {
//display answers (if not matching type, or if the answer is correct)
if (!in_array($answerType, [MATCHING, DRAGGABLE, MATCHING_DRAGGABLE]) ||
@ -8656,15 +8687,16 @@ class Exercise
}
/**
* @param int $categoryId
* @param int $page
* @param int $from
* @param int $limit
* @param int $categoryId
* @param int $page
* @param int $from
* @param int $limit
* @param string $keyword
*
* @return string
* @throws \Doctrine\ORM\Query\QueryException
*/
public static function exerciseGrid($categoryId, $page, $from, $limit)
public static function exerciseGrid($categoryId, $page, $from, $limit, $keyword = '')
{
$TBL_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
$TBL_ITEM_PROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
@ -8672,7 +8704,6 @@ class Exercise
$TBL_EXERCISES = Database::get_course_table(TABLE_QUIZ_TEST);
$TBL_TRACK_EXERCISES = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
$categoryId = (int) $categoryId;
$page = (int) $page;
$from = (int) $from;
$limit = (int) $limit;
@ -8701,7 +8732,6 @@ class Exercise
$courseInfo
);
$documentPath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document';
$limitTeacherAccess = api_get_configuration_value('limit_exercise_teacher_access');
$learnpath_id = isset($_REQUEST['learnpath_id']) ? (int) $_REQUEST['learnpath_id'] : null;
@ -8712,10 +8742,17 @@ class Exercise
$content = '';
$categoryCondition = '';
if (!empty($categoryId)) {
$categoryId = (int) $categoryId;
if (api_get_configuration_value('allow_exercise_categories')) {
$categoryCondition = " AND exercise_category_id = $categoryId ";
}
$keywordCondition = '';
if (!empty($keyword)) {
$keyword = Database::escape_string($keyword);
$keywordCondition = " AND title LIKE '%$keyword%' ";
}
// Only for administrators
if ($is_allowedToEdit) {
$total_sql = "SELECT count(iid) as count
@ -8725,21 +8762,34 @@ class Exercise
active<>'-1'
$condition_session
$categoryCondition
$keywordCondition
";
$sql = "SELECT * FROM $TBL_EXERCISES
WHERE c_id = $courseId AND active<>'-1' $condition_session $categoryCondition
WHERE
c_id = $courseId AND
active <> '-1'
$condition_session
$categoryCondition
$keywordCondition
ORDER BY title
LIMIT ".$from.",".$limit;
LIMIT $from , $limit";
} else {
// Only for students
$total_sql = "SELECT count(iid) as count
FROM $TBL_EXERCISES
WHERE c_id = $courseId AND active = '1' $condition_session $categoryCondition";
WHERE
c_id = $courseId AND
active = '1'
$condition_session
$categoryCondition
$keywordCondition
";
$sql = "SELECT * FROM $TBL_EXERCISES
WHERE c_id = $courseId AND
active='1' $condition_session
$categoryCondition
ORDER BY title LIMIT ".$from.",".$limit;
$keywordCondition
ORDER BY title LIMIT $from , $limit";
}
$result = Database::query($sql);
$result_total = Database::query($total_sql);
@ -8773,27 +8823,6 @@ class Exercise
}
$total = $total_exercises + $hp_count;
if ($total > $limit) {
$content .= '<div style="float:right;height:20px;">';
// Show pages navigation link for previous page
if ($page) {
$content .= "<a href=\"".api_get_self()."?".api_get_cidreq()."&page=".($page - 1)."\">".
Display::return_icon('action_prev.png', get_lang('PreviousPage')).'</a>';
} elseif ($total_exercises + $hp_count > $limit) {
$content .= Display::return_icon('action_prev_na.png', get_lang('PreviousPage'));
}
// Show pages navigation link for previous page
if ($total_exercises > $from + $limit || $hp_count > $from + $limit) {
$content .= ' '."<a href=\"".api_get_self()."?".api_get_cidreq()."&page=".($page + 1)."\">".
Display::return_icon('action_next.png', get_lang('NextPage')).'</a>';
} elseif ($page) {
$content .= ' '.Display::return_icon('action_next_na.png', get_lang('NextPage'));
}
$content .= '</div>';
}
$exerciseList = [];
$list_ordered = null;
while ($row = Database::fetch_array($result, 'ASSOC')) {
@ -8860,7 +8889,10 @@ class Exercise
$mylpid = empty($learnpath_id) ? '' : '&learnpath_id='.$learnpath_id;
$mylpitemid = empty($learnpath_item_id) ? '' : '&learnpath_item_id='.$learnpath_item_id;
foreach ($exerciseList as $row) {
$currentRow = [];
$my_exercise_id = $row['id'];
$attempt_text = '';
$actions = '';
$exercise = new Exercise();
$exercise->read($my_exercise_id, false);
@ -8978,14 +9010,13 @@ class Exercise
$sessionId
);
$move = Display::return_icon(
/*$move = Display::return_icon(
'all_directions.png',
get_lang('Move'),
['class' => 'moved', 'style' => 'margin-bottom:-0.5em;']
);
);*/
$move = null;
$class_tip = '';
if (!empty($count_exercise_not_validated)) {
$results_text = $count_exercise_not_validated == 1 ? get_lang('ResultNotRevised') : get_lang('ResultsNotRevised');
$title .= '<span class="exercise_tooltip" style="display: none;">'.$count_exercise_not_validated.' '.$results_text.' </span>';
@ -9001,11 +9032,11 @@ class Exercise
$url .= Display::div($embeddableIcon, ['class' => 'pull-right']);
}
$item = Display::tag('td', $url.' '.$session_img.$lp_blocked);
$currentRow['title'] = $url.' '.$session_img.$lp_blocked;
// Count number exercise - teacher
$sql = "SELECT count(*) count FROM $TBL_EXERCISE_QUESTION
WHERE c_id = $courseId AND exercice_id = $my_exercise_id";
WHERE c_id = $courseId AND exercice_id = $my_exercise_id";
$sqlresult = Database::query($sql);
$rowi = (int) Database::result($sqlresult, 0, 0);
@ -9152,7 +9183,7 @@ class Exercise
'',
ICON_SIZE_SMALL
),
'exercise.php?choice=exportqti2&exerciseId='.$row['id'].'&'.api_get_cidreq()
'exercise.php?action=exportqti2&exerciseId='.$row['id'].'&'.api_get_cidreq()
);
if ($limitTeacherAccess && !api_is_platform_admin()) {
@ -9205,7 +9236,6 @@ class Exercise
}
$actions .= $visibility;
$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(
@ -9281,7 +9311,8 @@ class Exercise
} else {
$number_of_questions = $rowi;
}
$item .= Display::tag('td', $number_of_questions);
$currentRow['count_questions'] = $number_of_questions;
} else {
// Student only.
$visibility = api_get_item_visibility(
@ -9299,7 +9330,7 @@ class Exercise
$cut_title.'</a>';
// Link of the exercise.
$item = Display::tag('td', $url.' '.$session_img);
$currentRow['title'] = $url.' '.$session_img;
// This query might be improved later on by ordering by the new "tms" field rather than by exe_id
// Don't remove this marker: note-query-exe-results
@ -9320,6 +9351,7 @@ class Exercise
// Hide the results.
$my_result_disabled = $row['results_disabled'];
$attempt_text = '-';
// Time limits are on
if ($time_limits) {
// Exam is ready to be taken
@ -9413,28 +9445,12 @@ class Exercise
} else {
$attempt_text = get_lang('NotAttempted');
}
} else {
$attempt_text = '-';
}
}
$class_tip = '';
if (empty($num)) {
$num = '';
} else {
$class_tip = 'link_tooltip';
//@todo use sprintf and show the results validated by the teacher
if ($num == 1) {
$num = $num.' '.get_lang('Result');
} else {
$num = $num.' '.get_lang('Results');
}
$num = '<span class="tooltip" style="display: none;">'.$num.'</span>';
}
$item .= Display::tag('td', $attempt_text);
}
$currentRow['attempt'] = $attempt_text;
if ($is_allowedToEdit) {
$additionalActions = ExerciseLib::getAdditionalTeacherActions($row['id']);
@ -9442,30 +9458,32 @@ class Exercise
$actions .= $additionalActions.PHP_EOL;
}
$item .= Display::tag('td', $actions, ['class' => 'td_actions']);
$currentRow = [
$row['iid'],
$currentRow['title'],
$currentRow['count_questions'],
$actions,
];
} else {
if ($isDrhOfCourse) {
$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>';
$item .= Display::tag('td', $actions, ['class' => 'td_actions']);
}
$currentRow = [
$row['iid'],
$currentRow['title'],
$currentRow['attempt'],
$actions,
];
}
$tableRows[] = Display::tag(
'tr',
$item,
[
'id' => 'exercise_list_'.$my_exercise_id,
]
);
$tableRows[] = $currentRow;
}
}
}
// end exercise list
// Hotpotatoes results
$hotpotatoes_exist = false;
if ($is_allowedToEdit) {
$sql = "SELECT d.iid, d.path as path, d.comment as comment
FROM $TBL_DOCUMENT d
@ -9473,7 +9491,7 @@ class Exercise
d.c_id = $courseId AND
(d.path LIKE '%htm%') AND
d.path LIKE '".Database :: escape_string($uploadPath.'/%/%')."'
LIMIT ".$from.",".$limit; // only .htm or .html files listed
LIMIT $from , $limit"; // only .htm or .html files listed
} else {
$sql = "SELECT d.iid, d.path as path, d.comment as comment
FROM $TBL_DOCUMENT d
@ -9481,22 +9499,21 @@ class Exercise
d.c_id = $courseId AND
(d.path LIKE '%htm%') AND
d.path LIKE '".Database :: escape_string($uploadPath.'/%/%')."'
LIMIT ".$from.",".$limit;
LIMIT $from , $limit";
}
$result = Database::query($sql);
$attribute = [];
$attributes = [];
while ($row = Database :: fetch_array($result, 'ASSOC')) {
$attribute['id'][] = $row['iid'];
$attribute['path'][] = $row['path'];
$attribute['comment'][] = $row['comment'];
$attributes[$row['iid']] = $row;
}
$nbrActiveTests = 0;
if (isset($attribute['path']) && is_array($attribute['path'])) {
$hotpotatoes_exist = true;
foreach ($attribute['path'] as $key => $path) {
$item = '';
if (!empty($attributes)) {
foreach ($attributes as $item) {
$id = $item['iid'];
$path = $item['path'];
$title = GetQuizName($path, $documentPath);
if ($title == '') {
$title = basename($path);
@ -9507,7 +9524,7 @@ class Exercise
$visibility = api_get_item_visibility(
['real_id' => $courseId],
TOOL_DOCUMENT,
$attribute['id'][$key],
$id,
0
);
@ -9519,15 +9536,14 @@ class Exercise
$visibility = api_get_item_visibility(
['real_id' => $courseId],
TOOL_DOCUMENT,
$attribute['id'][$key],
$id,
$sessionId
);
}
$item = Display::tag(
'td',
$title =
implode(PHP_EOL, [
Display::return_icon('hotpotatoes_s.png', "HotPotatoes"),
Display::return_icon('hotpotatoes_s.png', 'HotPotatoes'),
Display::url(
$title,
'showinframes.php?'.api_get_cidreq().'&'.http_build_query([
@ -9536,10 +9552,7 @@ class Exercise
]),
['class' => $visibility == 0 ? 'text-muted' : null]
),
])
);
$item .= Display::tag('td', '-');
]);
$actions = Display::url(
Display::return_icon(
@ -9552,7 +9565,8 @@ class Exercise
);
$actions .= '<a href="hotpotatoes_exercise_report.php?'.api_get_cidreq().'&path='.$path.'">'.
Display::return_icon('test_results.png', get_lang('Results'), '', ICON_SIZE_SMALL).'</a>';
Display::return_icon('test_results.png', get_lang('Results'), '', ICON_SIZE_SMALL).
'</a>';
// if active
if ($visibility != 0) {
@ -9563,15 +9577,20 @@ class Exercise
$actions .= ' <a href="'.$exercisePath.'?'.api_get_cidreq().'&hpchoice=enable&page='.$page.'&file='.$path.'">'.
Display::return_icon('invisible.png', get_lang('Activate'), '', ICON_SIZE_SMALL).'</a>';
}
$actions .= '<a href="'.$exercisePath.'?'.api_get_cidreq().'&hpchoice=delete&file='.$path.'" onclick="javascript:if(!confirm(\''.addslashes(api_htmlentities(get_lang('AreYouSureToDeleteJS'), ENT_QUOTES, $charset).' '.$title."?").'\')) return false;">'.
$actions .= '<a href="'.$exercisePath.'?'.api_get_cidreq().'&hpchoice=delete&file='.$path.'" onclick="javascript:if(!confirm(\''.addslashes(api_htmlentities(get_lang('AreYouSureToDeleteJS'), ENT_QUOTES, $charset)).'\')) return false;">'.
Display::return_icon('delete.png', get_lang('Delete'), '', ICON_SIZE_SMALL).'</a>';
$item .= Display::tag('td', $actions);
$tableRows[] = Display::tag('tr', $item);
$currentRow = [
'',
$title,
'',
$actions,
];
} else {
$visibility = api_get_item_visibility(
['real_id' => $courseId],
TOOL_DOCUMENT,
$attribute['id'][$key],
$id,
$sessionId
);
@ -9588,18 +9607,18 @@ class Exercise
);
$nbrActiveTests = $nbrActiveTests + 1;
$item .= Display::tag(
'td',
Display::url(
$title,
'showinframes.php?'.api_get_cidreq().'&'.http_build_query([
$title = Display::url(
$title,
'showinframes.php?'.api_get_cidreq().'&'.http_build_query(
[
'file' => $path,
'cid' => api_get_course_id(),
'uid' => $userId,
])
]
)
);
$actions = '';
if (!empty($attempt)) {
$actions = '<a href="hotpotatoes_exercise_report.php?'.api_get_cidreq().'&path='.$path.'&filter_by_user='.$userId.'">'.Display::return_icon('test_results.png', get_lang('Results'), '', ICON_SIZE_SMALL).'</a>';
$attemptText = get_lang('LatestAttempt').' : ';
@ -9613,24 +9632,24 @@ class Exercise
$attemptText = get_lang('NotAttempted').' ';
}
$item .= Display::tag('td', $attemptText);
if ($isDrhOfCourse) {
$actions = '<a href="hotpotatoes_exercise_report.php?'.api_get_cidreq().'&path='.$path.'">'.
Display::return_icon('test_results.png', get_lang('Results'), '', ICON_SIZE_SMALL).'</a>';
$item .= Display::tag(
'td',
$actions,
['class' => 'td_actions']
);
}
$tableRows[] = Display::tag('tr', $item);
$currentRow = [
'',
$title,
$attemptText,
$actions,
];
}
$tableRows[] = $currentRow;
}
}
if (empty($tableRows)) {
if (empty($tableRows) && empty($categoryId)) {
if ($is_allowedToEdit && $origin != 'learnpath') {
$content .= '<div id="no-data-view">';
$content .= '<h3>'.get_lang('Quiz').'</h3>';
@ -9645,42 +9664,49 @@ class Exercise
$content .= '</div>';
}
} else {
if ($is_allowedToEdit) {
$headers = [
get_lang('ExerciseName'),
get_lang('QuantityQuestions'),
get_lang('Actions'),
];
} else {
$headers = [
get_lang('ExerciseName'),
get_lang('Status'),
];
if ($isDrhOfCourse) {
$headers[] = get_lang('Actions');
}
}
foreach ($tableRows as $roz) {
echo $roz;
if (empty($tableRows)) {
return '';
}
var_dump($tableRows);
$content .= '<div class="table-responsive">';
$table = new SortableTableFromArrayConfig(
$tableRows,
1,
0,
20,
'exercises'
'exercises_cat'.$categoryId,
[],
[]
);
$table->setTotalNumberOfItems($total);
$table->set_additional_parameters([
'cidReq' => api_get_course_id(),
'id_session' => api_get_session_id(),
'category_id' => $categoryId,
]);
$formActions = [];
$formActions['visible'] = get_lang('Activate');
$formActions['invisible'] = get_lang('Deactivate');
$formActions['delete'] = get_lang('Delete');
$table->set_form_actions($formActions);
$i = 0;
foreach ($headers as $header) {
$table->set_header($i++, $header);
$table->set_header($i++, '', false, 'width="18px"');
$table->set_header($i++, get_lang('ExerciseName'), false);
if ($is_allowedToEdit) {
$table->set_header($i++, get_lang('QuantityQuestions'), false);
$table->set_header($i++, get_lang('Actions'), false);
} else {
$table->set_header($i++, get_lang('Status'), false);
if ($isDrhOfCourse) {
$table->set_header($i++, get_lang('Actions'), false);
}
}
$table->set_header($i++, 'aa');
//$content .= '<div class="table-responsive">';
$content .= $table->return_table();
$content .= '</div>';
//$content .= '</div>';
}
return $content;

File diff suppressed because it is too large Load Diff

@ -64,6 +64,7 @@ if (!in_array(
'get_learning_path_calendars',
'get_usergroups_users',
'get_calendar_users',
'get_exercise_categories',
]
) && !isset($_REQUEST['from_course_session'])) {
api_protect_admin_script(true);
@ -262,6 +263,11 @@ if (!$sidx) {
//@todo rework this
switch ($action) {
case 'get_exercise_categories':
$manager = new ExerciseCategoryManager();
$courseId = isset($_REQUEST['c_id']) ? $_REQUEST['c_id'] : 0;
$count = $manager->getCourseCount($courseId);
break;
case 'get_calendar_users':
$calendarPlugin = LearningCalendarPlugin::create();
$id = isset($_REQUEST['id']) ? $_REQUEST['id'] : 0;
@ -840,6 +846,21 @@ $is_allowedToEdit = api_is_allowed_to_edit(null, true) || api_is_allowed_to_edit
$columns = [];
switch ($action) {
case 'get_exercise_categories':
api_protect_course_script();
if (!api_is_allowed_to_edit()) {
api_not_allowed(true);
}
$columns = ['name', 'actions'];
$manager = new ExerciseCategoryManager();
$result = $manager->get_all([
'where' => ['c_id = ? ' => $courseId],
'order' => "$sidx $sord",
'LIMIT' => "$start , $limit",
]);
break;
case 'get_calendar_users':
$columns = ['firstname', 'lastname', 'exam'];
$result = $calendarPlugin->getUsersPerCalendar($id);
@ -2277,6 +2298,7 @@ $allowed_actions = [
'get_learning_path_calendars',
'get_usergroups_users',
'get_calendar_users',
'get_exercise_categories',
];
//5. Creating an obj to return a json

@ -0,0 +1,270 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CourseBundle\Entity\CExerciseCategory;
/**
* Class ExtraFieldValue
* Declaration for the ExtraFieldValue class, managing the values in extra
* fields for any data type.
*
* @package chamilo.library
*/
class ExerciseCategoryManager extends Model
{
public $type = '';
public $columns = [
'id',
'name',
'c_id',
'description',
'created_at',
'updated_at',
];
/**
* Formats the necessary elements for the given datatype.
*
* @param string $type The type of data to which this extra field
* applies (user, course, session, ...)
*
* @assert (-1) === false
*/
public function __construct()
{
parent::__construct();
$this->is_course_model = true;
$this->table = Database::get_course_table('exercise_category');
}
/**
* Gets the number of values stored in the table (all fields together)
* for this type of resource.
*
* @param int $courseId
*
* @return int Number of rows in the table
*/
public function getCourseCount($courseId)
{
$em = Database::getManager();
$query = $em->getRepository('ChamiloCourseBundle:CExerciseCategory')->createQueryBuilder('e');
$query->select('count(e.id)');
$query->where('e.cId = :cId');
$query->setParameter('cId', $courseId);
return $query->getQuery()->getSingleScalarResult();
}
/**
* @param int $courseId
*
* @return array
*/
public function getCategories($courseId)
{
$em = Database::getManager();
$query = $em->getRepository('ChamiloCourseBundle:CExerciseCategory')->createQueryBuilder('e');
$query->where('e.cId = :cId');
$query->setParameter('cId', $courseId);
$query->orderBy('e.position');
return $query->getQuery()->getResult();
}
/**
* @param int $courseId
*
* @return array
*/
public function getCategoriesForSelect($courseId)
{
$categories = $this->getCategories($courseId);
$options = [];
if (!empty($categories)) {
/** @var CExerciseCategory $category */
foreach ($categories as $category) {
$options[$category->getId()] = $category->getName();
}
}
return $options;
}
/**
* @param int $id
*
*/
public function delete($id)
{
$em = Database::getManager();
$repo = Database::getManager()->getRepository('ChamiloCourseBundle:CExerciseCategory');
$category = $repo->find($id);
if ($category) {
$em->remove($category);
$em->flush();
$courseId = api_get_course_int_id();
$table = Database::get_course_table(TABLE_QUIZ_TEST);
$id = (int) $id;
$sql = "UPDATE $table SET exercise_category_id = 0
WHERE c_id = $courseId AND exercise_category_id = $id";
Database::query($sql);
}
}
/**
* Save values in the *_field_values table.
*
* @param array $params Structured array with the values to save
* @param bool $showQuery Whether to show the insert query (passed to the parent save() method)
*
*/
public function save($params, $showQuery = false)
{
$courseId = api_get_course_int_id();
$em = Database::getManager();
$category = new CExerciseCategory();
$category
->setName($params['name'])
->setCId(api_get_course_int_id())
->setDescription($params['name'])
;
/*
// Update position
$query = $em->getRepository('ChamiloCourseBundle:CExerciseCategory')->createQueryBuilder('e');
$query
->where('e.cId = :cId')
->setParameter('cId', $courseId)
->setMaxResults(1)
->orderBy('e.position', 'DESC');
$last = $query->getQuery()->getOneOrNullResult();
$position = 0;
if (!empty($last)) {
$position = $last->getPosition() + 1;
}
$category->setPosition($position);
*/
$em->persist($category);
$em->flush();
return $category;
}
/**
* @param $token
*
* @return string
*/
public function getJqgridActionLinks($token)
{
//With this function we can add actions to the jgrid (edit, delete, etc)
$editIcon = Display::return_icon('edit.png', get_lang('Edit'), '', ICON_SIZE_SMALL);
$deleteIcon = Display::return_icon('delete.png', get_lang('Delete'), '', ICON_SIZE_SMALL);
$confirmMessage = addslashes(
api_htmlentities(get_lang('ConfirmYourChoice'), ENT_QUOTES)
);
$courseParams = api_get_cidreq();
$editButton = <<<JAVASCRIPT
<a href="?action=edit&{$courseParams}&id=' + options.rowId + '" class="btn btn-link btn-xs">\
$editIcon\
</a>
JAVASCRIPT;
$deleteButton = <<<JAVASCRIPT
<a \
onclick="if (!confirm(\'$confirmMessage\')) {return false;}" \
href="?sec_token=$token&{$courseParams}&id=' + options.rowId + '&action=delete" \
class="btn btn-link btn-xs">\
$deleteIcon\
</a>
JAVASCRIPT;
return "function action_formatter(cellvalue, options, rowObject) {
return '$editButton $deleteButton';
}";
}
/**
* @param string $url
* @param string $action
*
* @return FormValidator
*/
public function return_form($url, $action)
{
$form = new FormValidator('category', 'post', $url);
$id = isset($_GET['id']) ? (int) $_GET['id'] : null;
$form->addElement('hidden', 'id', $id);
// Setting the form elements
$header = get_lang('Add');
$defaults = [];
if ($action === 'edit') {
$header = get_lang('Modify');
// Setting the defaults
$defaults = $this->get($id, false);
}
$form->addElement('header', $header);
$form->addText(
'name',
get_lang('Name')
);
$form->addHtmlEditor('description', get_lang('Description'));
if ($action === 'edit') {
$form->addButtonUpdate(get_lang('Modify'));
} else {
$form->addButtonCreate(get_lang('Add'));
}
/*if (!empty($defaults['created_at'])) {
$defaults['created_at'] = api_convert_and_format_date($defaults['created_at']);
}
if (!empty($defaults['updated_at'])) {
$defaults['updated_at'] = api_convert_and_format_date($defaults['updated_at']);
}*/
$form->setDefaults($defaults);
// Setting the rules
$form->addRule('name', get_lang('ThisFieldIsRequired'), 'required');
return $form;
}
/**
* @return string
*/
public function display()
{
// action links
$content = '<div class="actions">';
$content .= '<a href="'.api_get_path(WEB_CODE_PATH).'exercise/exercise.php?'.api_get_cidreq().'">';
$content .= Display::return_icon(
'back.png',
get_lang('BackTo').' '.get_lang('PlatformAdmin'),
'',
ICON_SIZE_MEDIUM
);
$content .= '</a>';
$content .= '<a href="'.api_get_self().'?action=add&'.api_get_cidreq().'">';
$content .= Display::return_icon(
'add.png',
get_lang('Add'),
'',
ICON_SIZE_MEDIUM
);
$content .= '</a>';
$content .= '</div>';
$content .= Display::grid_html('categories');
return $content;
}
}

@ -1167,6 +1167,7 @@ class Display
* @param string $id id of the container of the tab in the example "tabs"
* @param array $attributes for the ul
* @param array $ul_attributes
* @param int $selected
*
* @return string
*/
@ -1175,7 +1176,8 @@ class Display
$items,
$id = 'tabs',
$attributes = [],
$ul_attributes = []
$ul_attributes = [],
$selected = ''
) {
if (empty($headers) || count($headers) == 0) {
return '';
@ -1188,6 +1190,14 @@ class Display
if ($i == 1) {
$active = ' active';
}
if (!empty($selected)) {
$active = '';
if ($selected == $i) {
$active = ' active';
}
}
$item = self::tag(
'a',
$item,
@ -1203,6 +1213,7 @@ class Display
$lis .= self::tag('li', $item, $ul_attributes);
$i++;
}
$ul = self::tag(
'ul',
$lis,
@ -1220,6 +1231,14 @@ class Display
if ($i == 1) {
$active = ' active';
}
if (!empty($selected)) {
$active = '';
if ($selected == $i) {
$active = ' active';
}
}
$divs .= self::tag(
'div',
$content,

@ -200,6 +200,15 @@ EOT;
return $element;
}
/**
* Add hidden course params
*/
public function addCourseHiddenParams()
{
$this->addHidden('cidReq', api_get_course_id());
$this->addHidden('id_session', api_get_session_id());
}
/**
* The "date_range_picker" element creates 2 hidden fields
* "elementName" + "_start" and "elementName" + "_end"

@ -177,29 +177,6 @@ class PEAR
}
}
// }}}
// {{{ destructor
/**
* Destructor (the emulated type of...). Does nothing right now,
* but is included for forward compatibility, so subclass
* destructors should always call it.
*
* See the note in the class desciption about output from
* destructors.
*
* @access public
* @return void
*/
function _PEAR() {
if ($this->_debug) {
printf("PEAR destructor called, class=%s\n", strtolower(get_class($this)));
}
}
// }}}
// {{{ getStaticProperty()
/**
* If you have a class that's mostly/entirely static, and you need static
* properties, you can use this method to simulate them. Eg. in your method(s)
@ -385,23 +362,6 @@ class PEAR
return sizeof($this->_expected_errors);
}
// }}}
// {{{ popExpect()
/**
* This method pops one element off the expected error codes
* stack.
*
* @return array the list of error codes that were popped
*/
function popExpect()
{
return array_pop($this->_expected_errors);
}
// }}}
// {{{ _checkDelExpect()
/**
* This method checks unsets an error code if available
*
@ -428,49 +388,6 @@ class PEAR
return $deleted;
}
// }}}
// {{{ delExpect()
/**
* This method deletes all occurences of the specified element from
* the expected error codes stack.
*
* @param mixed $error_code error code that should be deleted
* @return mixed list of error codes that were deleted or error
* @access public
* @since PHP 4.3.0
*/
function delExpect($error_code)
{
$deleted = false;
if ((is_array($error_code) && (0 != count($error_code)))) {
// $error_code is a non-empty array here;
// we walk through it trying to unset all
// values
foreach($error_code as $key => $error) {
if ($this->_checkDelExpect($error)) {
$deleted = true;
} else {
$deleted = false;
}
}
return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME
} elseif (!empty($error_code)) {
// $error_code comes alone, trying to unset it
if ($this->_checkDelExpect($error_code)) {
return true;
} else {
return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME
}
}
// $error_code is empty
return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME
}
// }}}
// {{{ raiseError()
/**
* This method is a wrapper that returns an instance of the
* configured error class with this object's default error
@ -586,80 +503,6 @@ class PEAR
return $a;
}
// }}}
function staticPushErrorHandling($mode, $options = null)
{
$stack = &$GLOBALS['_PEAR_error_handler_stack'];
$def_mode = &$GLOBALS['_PEAR_default_error_mode'];
$def_options = &$GLOBALS['_PEAR_default_error_options'];
$stack[] = array($def_mode, $def_options);
switch ($mode) {
case PEAR_ERROR_EXCEPTION:
case PEAR_ERROR_RETURN:
case PEAR_ERROR_PRINT:
case PEAR_ERROR_TRIGGER:
case PEAR_ERROR_DIE:
case null:
$def_mode = $mode;
$def_options = $options;
break;
case PEAR_ERROR_CALLBACK:
$def_mode = $mode;
// class/object method callback
if (is_callable($options)) {
$def_options = $options;
} else {
trigger_error("invalid error callback", E_USER_WARNING);
}
break;
default:
trigger_error("invalid error mode", E_USER_WARNING);
break;
}
$stack[] = array($mode, $options);
return true;
}
function staticPopErrorHandling()
{
$stack = &$GLOBALS['_PEAR_error_handler_stack'];
$setmode = &$GLOBALS['_PEAR_default_error_mode'];
$setoptions = &$GLOBALS['_PEAR_default_error_options'];
array_pop($stack);
list($mode, $options) = $stack[sizeof($stack) - 1];
array_pop($stack);
switch ($mode) {
case PEAR_ERROR_EXCEPTION:
case PEAR_ERROR_RETURN:
case PEAR_ERROR_PRINT:
case PEAR_ERROR_TRIGGER:
case PEAR_ERROR_DIE:
case null:
$setmode = $mode;
$setoptions = $options;
break;
case PEAR_ERROR_CALLBACK:
$setmode = $mode;
// class/object method callback
if (is_callable($options)) {
$setoptions = $options;
} else {
trigger_error("invalid error callback", E_USER_WARNING);
}
break;
default:
trigger_error("invalid error mode", E_USER_WARNING);
break;
}
return true;
}
// {{{ pushErrorHandling()
/**
* Push a new error handler on top of the error handler options stack. With this
* you can easily override the actual error handler for some code and restore
@ -693,30 +536,6 @@ class PEAR
return true;
}
// }}}
// {{{ popErrorHandling()
/**
* Pop the last error handler used
*
* @return bool Always true
*
* @see PEAR::pushErrorHandling
*/
function popErrorHandling()
{
$stack = &$GLOBALS['_PEAR_error_handler_stack'];
array_pop($stack);
list($mode, $options) = $stack[sizeof($stack) - 1];
array_pop($stack);
if (isset($this) && is_a($this, 'PEAR')) {
$this->setErrorHandling($mode, $options);
} else {
PEAR::setErrorHandling($mode, $options);
}
return true;
}
// }}}
// {{{ loadExtension()

@ -1,5 +1,4 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* Contains the Pager class
@ -51,8 +50,6 @@
*/
class Pager
{
// {{{ Pager()
/**
* Constructor
*
@ -140,12 +137,8 @@ class Pager
*/
public function __construct($options = array())
{
}
// }}}
// {{{ factory()
/**
* Return a pager based on $mode and $options
*
@ -177,7 +170,4 @@ class Pager
$null = null;
return $null;
}
// }}}
}
?>
}

@ -129,7 +129,7 @@ class SortableTable extends HTML_Table
$parameters = []
) {
if (empty($table_id)) {
$table_id = $table_name.uniqid();
$table_id = $table_name.uniqid('table', true);
}
if (isset($parameters) && empty($parameters)) {
$parameters = ['class' => 'table table-bordered data_table', 'id' => $table_id];
@ -161,9 +161,9 @@ class SortableTable extends HTML_Table
if (!in_array($my_session_direction, ['ASC', 'DESC'])) {
$this->direction = 'ASC';
} else {
if ($my_session_direction == 'ASC') {
if ($my_session_direction === 'ASC') {
$this->direction = 'ASC';
} elseif ($my_session_direction == 'DESC') {
} elseif ($my_session_direction === 'DESC') {
$this->direction = 'DESC';
}
}
@ -186,7 +186,7 @@ class SortableTable extends HTML_Table
Session::erase($this->param_prefix.'per_page');
$this->per_page = Session::read($this->param_prefix.'per_page', $default_items_per_page);
$this->per_page = isset($_GET[$this->param_prefix.'per_page']) ? intval($_GET[$this->param_prefix.'per_page']) : $this->per_page;
$this->per_page = isset($_GET[$this->param_prefix.'per_page']) ? (int) $_GET[$this->param_prefix.'per_page'] : $this->per_page;
Session::write($this->param_prefix.'per_page', $this->per_page);
Session::write($this->param_prefix.'direction', $this->direction);
@ -208,14 +208,15 @@ class SortableTable extends HTML_Table
/**
* Get the Pager object to split the showed data in several pages.
*
* @return Pager_Sliding
*/
public function get_pager()
{
if (is_null($this->pager)) {
$total_number_of_items = $this->get_total_number_of_items();
if ($this->pager === null) {
$params['mode'] = 'Sliding';
$params['perPage'] = $this->per_page;
$params['totalItems'] = $total_number_of_items;
$params['totalItems'] = $this->get_total_number_of_items();
$params['urlVar'] = $this->param_prefix.'page_nr';
$params['currentPage'] = $this->page_nr;
$icon_attributes = ['style' => 'vertical-align: middle;'];
@ -992,6 +993,14 @@ class SortableTable extends HTML_Table
return $this->total_number_of_items;
}
/**
* @param int $value
*/
public function setTotalNumberOfItems($value)
{
$this->total_number_of_items = (int) $value;
}
/**
* Get the data to display. This function calls the function given as
* 2nd argument in the constructor of a SortableTable. Make sure your
@ -1149,20 +1158,20 @@ class SortableTableFromArrayConfig extends SortableTable
/**
* Constructor.
*
* @param array $table_data All the information of the table
* @param int $default_column Default column that will be use in the sorts functions
* @param int $default_items_per_page quantity of pages that we are going to see
* @param int $tablename Name of the table
* @param array $column_show An array with binary values 1: we show the column 2: we don't show it
* @param array $column_order an array of integers that let us decide how the columns are going to be sort
* @param array $data All the information of the table
* @param int $column Default column that will be use in the sorts functions
* @param int $itemsPerPage quantity of pages that we are going to see
* @param string $tableName Name of the table
* @param array $column_show An array with binary values 1: we show the column 2: we don't show it
* @param array $column_order an array of integers that let us decide how the columns are going to be sort
* @param string $direction
* @param bool $doc_filter special modification to fix the document name order
* @param bool $doc_filter special modification to fix the document name order
*/
public function __construct(
$table_data,
$default_column = 1,
$default_items_per_page = 20,
$tablename = 'tablename',
$data,
$column = 1,
$itemsPerPage = 20,
$tableName = 'tablename',
$column_show = [],
$column_order = [],
$direction = 'ASC',
@ -1173,14 +1182,14 @@ class SortableTableFromArrayConfig extends SortableTable
$this->doc_filter = $doc_filter;
parent::__construct(
$tablename,
$tableName,
null,
null,
$default_column,
$default_items_per_page,
$column,
$itemsPerPage,
$direction
);
$this->table_data = $table_data;
$this->table_data = $data;
}
/**
@ -1198,7 +1207,7 @@ class SortableTableFromArrayConfig extends SortableTable
$content = TableSort::sort_table_config(
$this->table_data,
$this->column,
$this->direction == 'ASC' ? SORT_ASC : SORT_DESC,
$this->direction === 'ASC' ? SORT_ASC : SORT_DESC,
$this->column_show,
$this->column_order,
SORT_REGULAR,

@ -36,10 +36,8 @@ class TableSort
if (!is_array($data) || empty($data)) {
return [];
}
if ($column != strval(intval($column))) {
// Probably an attack
return $data;
}
$column = (int) $column;
if (!in_array($direction, [SORT_ASC, SORT_DESC])) {
// Probably an attack
return $data;
@ -78,7 +76,7 @@ class TableSort
case SORT_NUMERIC:
$function = function ($a, $b) use ($column, $compareOperator) {
$result = strip_tags($a[$column]) <= strip_tags($b[$column]);
if ($compareOperator == '>') {
if ($compareOperator === '>') {
$result = strip_tags($a[$column]) > strip_tags($b[$column]);
}
@ -91,7 +89,7 @@ class TableSort
api_strtolower(strip_tags($a[$column], "<img>")),
api_strtolower(strip_tags($b[$column], "<img>"))
) <= 0;
if ($compareOperator == '>') {
if ($compareOperator === '>') {
$result = api_strnatcmp(
api_strtolower(strip_tags($a[$column], "<img>")),
api_strtolower(strip_tags($b[$column], "<img>"))
@ -105,7 +103,7 @@ class TableSort
case SORT_DATE:
$function = function ($a, $b) use ($column, $compareOperator) {
$result = strtotime(strip_tags($a[$column])) <= strtotime(strip_tags($b[$column]));
if ($compareOperator == '>') {
if ($compareOperator === '>') {
$result = strtotime(strip_tags($a[$column])) > strtotime(strip_tags($b[$column]));
}
@ -119,7 +117,7 @@ class TableSort
api_strtolower(strip_tags($a[$column])),
api_strtolower(strip_tags($b[$column]))
) <= 0;
if ($compareOperator == '>') {
if ($compareOperator === '>') {
$result = api_strnatcmp(
api_strtolower(strip_tags($a[$column])),
api_strtolower(strip_tags($b[$column]))
@ -164,10 +162,7 @@ class TableSort
return [];
}
if ($column != strval(intval($column))) {
// Probably an attack
return $data;
}
$column = (int) $column;
if (!in_array($direction, [SORT_ASC, SORT_DESC])) {
// Probably an attack
@ -198,7 +193,7 @@ class TableSort
$new_data = [];
if (!empty($data)) {
foreach ($data as $document) {
if ($document['type'] == 'folder') {
if ($document['type'] === 'folder') {
$docs_to_sort[$document['id']] = api_strtolower($document['name']);
} else {
$folder_to_sort[$document['id']] = api_strtolower($document['name']);

@ -1217,6 +1217,11 @@ $_configuration['required_extra_fields_in_profile'] = [
// Allow general certificate
//$_configuration['allow_general_certificate'] = false;
// Allow exercise categories
// CREATE TABLE c_exercise_category (id BIGINT AUTO_INCREMENT NOT NULL, c_id INT NOT NULL, name VARCHAR(255) NOT NULL, description LONGTEXT DEFAULT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, position INT NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;
// enable @ORM in CExerciseCategory adn CQuiz::exerciseCategoryId
//$_configuration['allow_exercise_categories'] = false;
// KEEP THIS AT THE END
// -------- Custom DB changes
// Add user activation by confirmation email

@ -7702,6 +7702,9 @@ class learnpath
echo Display::return_message(get_lang('ClickOnTheLearnerViewToSeeYourLearningPath'), 'normal');
$dir = $this->display_item_form('dir', get_lang('EnterDataNewChapter'), 'add_item');
$selected = isset($_REQUEST['lp_build_selected']) ? (int) $_REQUEST['lp_build_selected'] : 0;
echo Display::tabs(
$headers,
[
@ -7713,7 +7716,10 @@ class learnpath
$dir,
$finish,
],
'resource_tab'
'resource_tab',
[],
[],
$selected
);
return true;
@ -7779,6 +7785,7 @@ class learnpath
public function display_quiz_form($action = 'add', $id = 0, $extra_info = '')
{
$course_id = api_get_course_int_id();
$id = (int) $id;
$tbl_lp_item = Database::get_course_table(TABLE_LP_ITEM);
$tbl_quiz = Database::get_course_table(TABLE_QUIZ_TEST);
@ -7801,10 +7808,9 @@ class learnpath
$item_title = Security::remove_XSS($item_title);
$item_description = Security::remove_XSS($item_description);
$parent = 0;
if ($id != 0 && is_array($extra_info)) {
$parent = $extra_info['parent_item_id'];
} else {
$parent = 0;
}
$sql = "SELECT * FROM $tbl_lp_item
@ -7842,9 +7848,9 @@ class learnpath
);
$defaults = [];
if ($action == 'add') {
if ($action === 'add') {
$legend = get_lang('CreateTheExercise');
} elseif ($action == 'move') {
} elseif ($action === 'move') {
$legend = get_lang('MoveTheCurrentExercise');
} else {
$legend = get_lang('EditCurrentExecice');
@ -7906,6 +7912,7 @@ class learnpath
}
}
}
if (is_array($arrLP)) {
reset($arrLP);
}
@ -10133,10 +10140,10 @@ class learnpath
{
$_course = api_get_course_info();
$course_code = api_get_course_id();
$return = '<div class="actions">';
$item_id = (int) $item_id;
$return = '<div class="actions">';
$tbl_lp_item = Database::get_course_table(TABLE_LP_ITEM);
$item_id = (int) $item_id;
$sql = "SELECT * FROM $tbl_lp_item
WHERE iid = ".$item_id;
$result = Database::query($sql);
@ -10748,18 +10755,78 @@ class learnpath
$activeCondition = ' active = 1 ';
}
$categoryCondition = '';
$categoryId = isset($_REQUEST['category_id']) ? (int) $_REQUEST['category_id'] : 0;
if (api_get_configuration_value('allow_exercise_categories') && !empty($categoryId)) {
$categoryCondition = " AND exercise_category_id = $categoryId ";
}
$keywordCondition = '';
$keyword = isset($_REQUEST['keyword']) ? $_REQUEST['keyword'] :'';
if (!empty($keyword)) {
$keyword = Database::escape_string($keyword);
$keywordCondition = " AND title LIKE '%$keyword%' ";
}
$sql_quiz = "SELECT * FROM $tbl_quiz
WHERE c_id = $course_id AND $activeCondition $condition_session
WHERE
c_id = $course_id AND
$activeCondition
$condition_session
$categoryCondition
$keywordCondition
ORDER BY title ASC";
$sql_hot = "SELECT * FROM $tbl_doc
WHERE c_id = $course_id AND path LIKE '".$uploadPath."/%/%htm%' $condition_session
WHERE
c_id = $course_id AND
path LIKE '".$uploadPath."/%/%htm%'
$condition_session
ORDER BY id ASC";
$res_quiz = Database::query($sql_quiz);
$res_hot = Database::query($sql_hot);
$return = '<ul class="lp_resource">';
$currentUrl = api_get_self().'?'.api_get_cidreq().'&action=add_item&type=step&lp_id='.$this->lp_id.'#resource_tab-2';
// Create a search-box
$form = new FormValidator('search_simple', 'get', $currentUrl);
$form->addHidden('action', 'add_item');
$form->addHidden('type', 'step');
$form->addHidden('lp_id', $this->lp_id);
$form->addHidden('lp_build_selected', '2');
$form->addCourseHiddenParams();
$form->addText(
'keyword',
get_lang('Search'),
false,
[
'aria-label' => get_lang('Search'),
]
);
if (api_get_configuration_value('allow_exercise_categories')) {
$manager = new ExerciseCategoryManager();
$options = $manager->getCategoriesForSelect(api_get_course_int_id());
if (!empty($options)) {
$form->addSelect(
'category_id',
get_lang('Category'),
$options,
['placeholder' => get_lang('SelectAnOption')]
);
}
}
$form->addButtonSearch(get_lang('Search'));
$return = $form->returnForm();
$return .= '<ul class="lp_resource">';
$return .= '<li class="lp_resource_element">';
$return .= Display::return_icon('new_exercice.png');
$return .= '<a href="'.api_get_path(WEB_CODE_PATH).'exercise/exercise_admin.php?'.api_get_cidreq().'&lp_id='.$this->lp_id.'">'.
@ -10828,7 +10895,6 @@ class learnpath
'class' => $visibility == 0 ? 'moved text-muted' : 'moved',
]
);
$return .= '</li>';
}

@ -121,7 +121,7 @@ switch ($type) {
break;
}
if ($action == 'add_item' && $type == 'document') {
if ($action === 'add_item' && $type === 'document') {
$interbreadcrumb[] = ['url' => '#', 'name' => get_lang('NewDocumentCreated')];
}
@ -216,7 +216,6 @@ if (($type == 'document' || $type == 'step') && !isset($_GET['file'])) {
echo '<div id="frmModel" class="scrollbar-inner lp-add-item">';
echo '</div>';
}
echo '</div>';
echo '<div id="doc_form" class="col-md-8">';

@ -0,0 +1,219 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\CourseBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
/**
* CExerciseCategory.
*
* @ORM\Table(name="c_exercise_category")
* ORM\Entity(repositoryClass="Gedmo\Sortable\Entity\Repository\SortableRepository")
*/
class CExerciseCategory
{
/**
* @var int
*
* @ORM\Column(name="id", type="bigint")
* @ORM\Id
* @ORM\GeneratedValue
*/
protected $id;
/**
* @var int
*
* @Gedmo\SortableGroup
* @ORM\ManyToOne(targetEntity="Chamilo\CourseBundle\Entity\CExerciseCategory", inversedBy="children")
* @ORM\JoinColumn(referencedColumnName="id", onDelete="SET NULL")
*
* @ORM\Column(name="c_id", type="integer")
*/
protected $cId;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=255, nullable=false)
*/
protected $name;
/**
* @var string
*
* @ORM\Column(name="description", type="text", nullable=true)
*/
protected $description;
/**
* @Gedmo\SortablePosition
* @ORM\Column(name="position", type="integer")
*/
protected $position;
/**
* @var \DateTime
*
* @ORM\Column(name="created_at", type="datetime", nullable=false)
*/
protected $createdAt;
/**
* @var \DateTime
*
* @ORM\Column(name="updated_at", type="datetime", nullable=false)
*/
protected $updatedAt;
/**
* Project constructor.
*/
public function __construct()
{
$this->createdAt = new \DateTime();
$this->updatedAt = new \DateTime();
}
/**
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* @param int $id
*
* @return CExerciseCategory
*/
public function setId($id)
{
$this->id = $id;
return $this;
}
/**
* @return int
*/
public function getCId()
{
return $this->cId;
}
/**
* @param int $cId
*
* @return CExerciseCategory
*/
public function setCId($cId)
{
$this->cId = $cId;
return $this;
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @param string $name
*
* @return CExerciseCategory
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* @return string
*/
public function getDescription()
{
return $this->description;
}
/**
* @param string $description
*
* @return CExerciseCategory
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* @return \DateTime
*/
public function getCreatedAt()
{
return $this->createdAt;
}
/**
* @param \DateTime $createdAt
*
* @return CExerciseCategory
*/
public function setCreatedAt($createdAt)
{
$this->createdAt = $createdAt;
return $this;
}
/**
* @return \DateTime
*/
public function getUpdatedAt()
{
return $this->updatedAt;
}
/**
* @param \DateTime $updatedAt
*
* @return CExerciseCategory
*/
public function setUpdatedAt($updatedAt)
{
$this->updatedAt = $updatedAt;
return $this;
}
/**
* @return mixed
*/
public function getPosition()
{
return $this->position;
}
/**
* @param mixed $position
*
* @return CExerciseCategory
*/
public function setPosition($position)
{
$this->position = $position;
return $this;
}
}

@ -209,6 +209,13 @@ class CQuiz
*/
protected $hideQuestionTitle;
/**
* @var int
*
* ORM\Column(name="exercise_category_id", type="integer", nullable=true)
*/
protected $exerciseCategoryId;
/**
* CQuiz constructor.
*/

@ -8,6 +8,8 @@ use Doctrine\ORM\Mapping as ORM;
/**
* CQuizCategory.
*
* Manages quiz question categories inside an exercise.
*
* @ORM\Table(name="c_quiz_rel_category")
* @ORM\Entity
*/

Loading…
Cancel
Save