Update from 1.11.x

pull/4101/head
Julio Montoya 6 years ago
parent cec00aafcd
commit fec82f7490
  1. 1
      main/admin/index.php
  2. 73
      main/admin/system_announcements.php
  3. 1
      main/admin/user_linking_requests.php
  4. 3
      main/auth/courses.php
  5. 12
      main/auth/courses_categories.php
  6. 8
      main/auth/courses_controller.php
  7. 101
      main/auth/external_login/ldap.inc.php
  8. 2
      main/auth/external_login/newUser.ldap.php
  9. 19
      main/auth/ldap/authldap.php
  10. 12
      main/auth/my_progress.php
  11. 5
      main/document/add_link.php
  12. 10
      main/document/document.php
  13. 5
      main/document/showinframes.php
  14. 23
      main/dropbox/dropbox_init.inc.php
  15. 2
      main/exercise/ReadingComprehension.php
  16. 1
      main/exercise/UniqueAnswerImage.php
  17. 11
      main/exercise/exercise.class.php
  18. 12
      main/exercise/exercise.php
  19. 28
      main/exercise/exercise_report.php
  20. 25
      main/exercise/exercise_result.php
  21. 11
      main/exercise/export/exercise_import.inc.php
  22. 66
      main/exercise/export/qti2/qti2_classes.php
  23. 1
      main/exercise/export/scorm/ScormQuestion.php
  24. 14
      main/exercise/overview.php
  25. 12
      main/exercise/question.class.php
  26. 10
      main/exercise/question_pool.php
  27. 9
      main/forum/forumfunction.inc.php
  28. 16
      main/glossary/glossary_ajax_request.php
  29. 12
      main/gradebook/gradebook_display_certificate.php
  30. 5
      main/gradebook/gradebook_display_summary.php
  31. 1
      main/inc/ajax/myspace.ajax.php
  32. 25
      main/inc/lib/MailTemplateManager.php
  33. 10
      main/inc/lib/NotificationEvent.php
  34. 66
      main/inc/lib/api.lib.php
  35. 2
      main/inc/lib/array.lib.php
  36. 38
      main/inc/lib/course.lib.php
  37. 31
      main/inc/lib/course_category.lib.php
  38. 12
      main/inc/lib/course_home.lib.php
  39. 29
      main/inc/lib/events.lib.php
  40. 117
      main/inc/lib/exercise.lib.php
  41. 1
      main/inc/lib/exercise_show_functions.lib.php
  42. 35
      main/inc/lib/glossary.lib.php
  43. 2
      main/inc/lib/hook/HookEvent.php
  44. 2
      main/inc/lib/hook/interfaces/HookAdminBlockObserverInterface.php
  45. 2
      main/inc/lib/hook/interfaces/base/HookEventInterface.php
  46. 170
      main/inc/lib/message.lib.php
  47. 168
      main/inc/lib/sessionmanager.lib.php
  48. 15
      main/inc/lib/skill.lib.php
  49. 11
      main/inc/lib/sortable_table.class.php
  50. 120
      main/inc/lib/system_announcements.lib.php
  51. 15
      main/inc/lib/usergroup.lib.php
  52. 3
      main/inc/lib/usermanager.lib.php
  53. 70
      main/lp/learnpath.class.php
  54. 38
      main/mySpace/access_details.php
  55. 1
      main/session/about.php
  56. 9
      main/session/add_users_to_session.php
  57. 2
      main/session/session_course_user.php
  58. 11
      main/social/home.php
  59. 2
      main/social/profile.php
  60. 2
      main/template/default/auth/session_catalog.tpl
  61. 10
      main/template/default/career/diagram.tpl
  62. 3
      main/tracking/courseLog.php
  63. 22
      main/user/class.php
  64. 19
      main/wiki/index.php
  65. 1
      main/wiki/wiki.inc.php

@ -6,7 +6,6 @@
* Index page of the admin tools.
*/
// Resetting the course id.
$cidReset = true;
// Including some necessary chamilo files.

@ -56,6 +56,34 @@ if (!empty($action)) {
} else {
$tool_name = get_lang('SystemAnnouncements');
}
$url = api_get_path(WEB_AJAX_PATH).'career.ajax.php';
$htmlHeadXtra[] = '<script>
function showCareer() {
$("#promotion").show();
var url = "'.$url.'";
var id = $(\'#career_id\').val();
$.getJSON(
url, {
"career_id" : id,
"a" : "get_promotions"
}
)
.done(function(data) {
$("#promotion_id").empty();
$("#promotion_id").append(
$("<option>", {value: "0", text: "'.addslashes(get_lang('All')).'"})
);
$.each(data, function(index, value) {
$("#promotion_id").append(
$("<option>", {value: value.id, text: value.name})
);
});
$("#promotion_id").selectpicker("refresh");
});
}
</script>';
// Displaying the header.
Display::display_header($tool_name);
@ -130,6 +158,10 @@ switch ($action) {
$values[$key] = $data[$key];
}
}
if ($allowCareers) {
$values['career_id'] = $announcement->career_id;
$values['promotion_id'] = $announcement->promotion_id;
}
$values['lang'] = $announcement->lang;
$values['action'] = 'edit';
@ -178,6 +210,39 @@ if ($action_todo) {
['id' => 'range']
);
if ($allowCareers) {
$career = new Career();
$careerList = $career->get_all();
$list = array_column($careerList, 'name', 'id');
$form->addSelect(
'career_id',
get_lang('Career'),
$list,
['onchange' => 'javascript: showCareer();', 'placeholder' => get_lang('SelectAnOption'), 'id' => 'career_id']
);
$display = 'none;';
$options = [];
if (isset($values['promotion_id'])) {
$promotion = new Promotion();
$promotion = $promotion->get($values['promotion_id']);
if ($promotion) {
$options = [$promotion['id'] => $promotion['name']];
$display = 'block';
}
}
$form->addHtml('<div id="promotion" style="display:'.$display.';">');
$form->addSelect(
'promotion_id',
get_lang('Promotion'),
$options,
['id' => 'promotion_id']
);
$form->addHtml('</div>');
}
$group = [];
foreach ($visibleList as $key => $name) {
$group[] = $form->createElement(
@ -248,7 +313,9 @@ if ($action_todo) {
$values['lang'],
$sendMail,
empty($values['add_to_calendar']) ? false : true,
empty($values['send_email_test']) ? false : true
empty($values['send_email_test']) ? false : true,
isset($values['career_id']) ? $values['career_id'] : 0,
isset($values['promotion_id']) ? $values['promotion_id'] : 0
);
if ($announcement_id !== false) {
@ -279,7 +346,9 @@ if ($action_todo) {
$visibilityResult,
$values['lang'],
$sendMail,
$sendMailTest
$sendMailTest,
isset($values['career_id']) ? $values['career_id'] : 0,
isset($values['promotion_id']) ? $values['promotion_id'] : 0
)) {
if (isset($values['group'])) {
SystemAnnouncementManager::announcement_for_groups(

@ -87,7 +87,6 @@ if (!empty($action) && $hrm && $assignedId) {
/**
* Get the data to fill the tables on screen.
*
* @param User $hrm
* @param int $status
*
* @return array

@ -1,6 +1,7 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CoreBundle\Entity\SequenceResource;
/**
@ -8,8 +9,6 @@ use Chamilo\CoreBundle\Entity\SequenceResource;
* to the controllers depend on the current action.
*
* @author Christian Fasanando <christian1827@gmail.com> - Beeznest
*
* @package chamilo.auth
*/
// Delete the globals['_cid'], we don't need it here.
$cidReset = true; // Flag forcing the 'current course' reset

@ -1,12 +1,11 @@
<?php
/* For licensing terms, see /license.txt */
/**
* View (MVC patter) for courses categories.
*
* @author Christian Fasanando <christian1827@gmail.com> - Beeznest
*
* @package chamilo.auth
*/
if (isset($_REQUEST['action']) && Security::remove_XSS($_REQUEST['action']) !== 'subscribe') {
$stok = Security::get_token();
@ -20,8 +19,8 @@ $action = in_array($action, $actions) ? $action : 'display_courses';
$showCourses = CoursesAndSessionsCatalog::showCourses();
$showSessions = CoursesAndSessionsCatalog::showSessions();
$pageCurrent = isset($pageCurrent) ? $pageCurrent : isset($_GET['pageCurrent']) ? (int) $_GET['pageCurrent'] : 1;
$pageLength = isset($pageLength) ? $pageLength : isset($_GET['pageLength']) ? (int) $_GET['pageLength'] : CoursesAndSessionsCatalog::PAGE_LENGTH;
$pageCurrent = isset($_GET['pageCurrent']) ? (int) $_GET['pageCurrent'] : 1;
$pageLength = isset($_GET['pageLength']) ? (int) $_GET['pageLength'] : CoursesAndSessionsCatalog::PAGE_LENGTH;
$pageTotal = (int) ceil((int) $countCoursesInCategory / $pageLength);
$cataloguePagination = $pageTotal > 1 ? CourseCategory::getCatalogPagination($pageCurrent, $pageLength, $pageTotal) : '';
$searchTerm = isset($_REQUEST['search_term']) ? Security::remove_XSS($_REQUEST['search_term']) : '';
@ -44,13 +43,8 @@ $code = isset($code) ? $code : null;
url: $(this).attr('data-link'),
success: function(data) {
$("#rating_wrapper_"+id).html(data);
if (data == 'added') {
//$('#vote_label2_' + id).html("{'Saved'|get_lang}");
}
if (data == 'updated') {
//$('#vote_label2_' + id).html("{'Saved'|get_lang}");
}
}
});
});
var getSessionId = function (el) {

@ -1,6 +1,7 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CoreBundle\Entity\Repository\SequenceRepository;
use Chamilo\CoreBundle\Entity\SequenceResource;
use Chamilo\CoreBundle\Entity\SessionRelCourse;
@ -512,6 +513,7 @@ class CoursesController
$includeText = false,
$btnBing = false
) {
$sessionId = (int) $sessionId;
if ($btnBing) {
$btnBing = 'btn-lg btn-block';
} else {
@ -522,7 +524,7 @@ class CoursesController
$url .= 'sequence.ajax.php?';
$url .= http_build_query([
'a' => 'get_requirements',
'id' => intval($sessionId),
'id' => $sessionId,
'type' => SequenceResource::SESSION_TYPE,
]);
@ -552,7 +554,7 @@ class CoursesController
$url .= 'auth/courses.php?';
$url .= http_build_query([
'action' => 'subscribe_to_session',
'session_id' => intval($sessionId),
'session_id' => $sessionId,
]);
$result = Display::toolbarButton(
@ -588,7 +590,7 @@ class CoursesController
$hook = HookResubscribe::create();
if (!empty($hook)) {
$hook->setEventData([
'session_id' => intval($sessionId),
'session_id' => $sessionId,
]);
try {
$hook->notifyResubscribe(HOOK_EVENT_TYPE_PRE);

@ -31,7 +31,7 @@ function extldap_purify_string($string)
/**
* Establishes a connection to the LDAP server and sets the protocol version.
*
* @return bool ldap link identifier or false
* @return resource|bool ldap link identifier or false
*
* @author ndiechburg <noel@cblue.be>
* */
@ -219,6 +219,12 @@ function extldap_get_chamilo_user($ldap_user, $cor = null)
$chamilo_user[$chamilo_field] = trim($ldap_field, "!\t\n\r\0");
break;
}
if (!array_key_exists($ldap_field, $ldap_user)) {
$lowerCaseFieldName = strtolower($ldap_field);
if (array_key_exists($lowerCaseFieldName, $ldap_user)) {
$ldap_field = $lowerCaseFieldName;
}
}
if (isset($ldap_user[$ldap_field][0])) {
$chamilo_user[$chamilo_field] = extldap_purify_string($ldap_user[$ldap_field][0]);
} else {
@ -405,3 +411,96 @@ function extldap_add_user_by_array($data, $update_if_exists = true)
return $user_id;
}
/**
* Get one user's single attribute value.
* User is identified by filter.
* $extldap_config['filter'] is also applied in complement, if defined.
*
* @param $filter string LDAP entry filter, such as '(uid=10000)'
* @param $attribute string name of the LDAP attribute to read the value from
*
* @throws Exception if more than one entries matched or on internal error
*
* @return string|bool the single matching user entry's single attribute value or false if not found
*/
function extldapGetUserAttributeValue($filter, $attribute)
{
global $extldap_config;
if (array_key_exists('filter', $extldap_config) && !empty($extldap_config['filter'])) {
$filter = '(&'.$filter.'('.$extldap_config['filter'].'))';
}
$ldap = extldap_connect();
if (false === $ldap) {
throw new Exception(get_lang('LDAPConnectFailed'));
}
if (false === ldap_bind($ldap, $extldap_config['admin_dn'], $extldap_config['admin_password'])) {
throw new Exception(get_lang('LDAPBindFailed'));
}
$searchResult = ldap_search($ldap, $extldap_config['base_dn'], $filter, [$attribute]);
if (false === $searchResult) {
throw new Exception(get_lang('LDAPSearchFailed'));
}
switch (ldap_count_entries($ldap, $searchResult)) {
case 0:
return false;
case 1:
$entry = ldap_first_entry($ldap, $searchResult);
if (false === $entry) {
throw new Exception(get_lang('LDAPFirstEntryFailed'));
}
$values = ldap_get_values($ldap, $entry, $attribute);
if (false == $values) {
throw new Exception(get_lang('LDAPGetValuesFailed'));
}
if ($values['count'] == 1) {
return $values[0];
}
throw new Exception(get_lang('MoreThanOneAttributeValueFound'));
default:
throw new Exception(get_lang('MoreThanOneUserMatched'));
}
}
/**
* Get the username from the CAS-supplied user identifier.
*
* searches in attribute $extldap_user_correspondance['extra']['cas_user'] or 'uid' by default
* reads value from attribute $extldap_user_correspondance['username'] or 'uid' by default
*
* @param $casUser string code returned from the CAS server to identify the user
*
* @throws Exception on error
*
* @return string|bool user login name, false if not found
*/
function extldapCasUserLogin($casUser)
{
global $extldap_user_correspondance;
// which LDAP attribute is the cas user identifier stored in ?
$attributeToFilterOn = 'uid';
if (is_array($extldap_user_correspondance) && array_key_exists('extra', $extldap_user_correspondance)) {
$extra = $extldap_user_correspondance['extra'];
if (is_array($extra) && array_key_exists('cas_user', $extra) && !empty($extra['cas_user'])) {
$attributeToFilterOn = $extra['cas_user'];
}
}
// which LDAP attribute is the username ?
$attributeToRead = 'uid';
if (is_array($extldap_user_correspondance)
&& array_key_exists('username', $extldap_user_correspondance)
&& !empty($extldap_user_correspondance['username'])
) {
$attributeToRead = $extldap_user_correspondance['username'];
}
// return the value
return extldapGetUserAttributeValue("($attributeToFilterOn=$casUser)", $attributeToRead);
}

@ -63,7 +63,7 @@ if ($ldap_user !== false) {
}
Event::eventLogin($chamiloUser->getId());
MessageManager::sendNotificationByRegisteredUser($chamiloUser);
MessageManager::sendNotificationOfNewRegisteredUser($chamiloUser);
}
} else {
$loginFailed = true;

@ -26,25 +26,6 @@
3.2 - updated to allow for specific term search for teachers identification
3.1 - updated code to use database settings, to respect coding conventions
* as much as possible (camel-case removed) and to allow for non-anonymous login
3.0 - updated to use ldap_var.inc.php instead of ldap_var.inc (deprecated)
(November 2003)
2.9 - further changes for new login procedure
- (busy) translating french functions to english
(October 2003)
2.8 - adapted for new Claroline login procedure
- ldap package now becomes a standard, in auth/ldap
2.7 - uses more standard LDAP field names: mail, sn, givenname (or cn)
instead of mail, preferredsn, preferredgivenname
there are still
- code cleanup
- fixed bug: dc = xx, dc = yy was configured for UGent
and put literally in the code, this is now a variable
in configuration.php ($LDAPbasedn)
with thanks to
- Stefan De Wannemacker (Ghent University)
- Universite Jean Monet (J Dubois / Michel Courbon)
- Michel Panckoucke for reporting and fixing a bug
- Patrick Cool: fixing security hole
* @author Roan Embrechts

@ -9,11 +9,15 @@
$cidReset = true;
require_once __DIR__.'/../inc/global.inc.php';
api_block_anonymous_users();
if (api_get_configuration_value('block_my_progress_page')) {
api_not_allowed(true);
}
$this_section = SECTION_TRACKING;
$nameTools = get_lang('MyProgress');
api_block_anonymous_users();
$htmlHeadXtra[] = api_get_js('jquery.timelinr-0.9.54.js');
$htmlHeadXtra[] = "<script>
$(function() {
@ -31,10 +35,6 @@ if ($pluginCalendar) {
$plugin->setJavaScript($htmlHeadXtra);
}
if (api_get_configuration_value('block_my_progress_page')) {
api_not_allowed(true);
}
$user_id = api_get_user_id();
$courseUserList = CourseManager::get_courses_list_by_user_id($user_id);
$dates = $issues = '';

@ -1,6 +1,7 @@
<?php
/* For licensing terms, see /license.txt */
/**
* This script allows to add cloud file links to the document structure.
*
@ -78,7 +79,7 @@ $interbreadcrumb[] = [
// Interbreadcrumb for the current directory root path
if (empty($document_data['parents'])) {
// Hack in order to not add the document to the breadcrumb in case it is a link
if ($document_data['filetype'] != 'link') {
if ($document_data && $document_data['filetype'] != 'link') {
$interbreadcrumb[] = ['url' => '#', 'name' => $document_data['title']];
}
} else {
@ -144,7 +145,7 @@ if ($form->validate()) {
Display::addFlash(Display::return_message(get_lang('ErrorAddCloudLink'), 'warning', false));
}
}
header('Location: document.php?'.api_get_cidreq());
header('Location: document.php?'.api_get_cidreq().'&id='.$documentId);
exit;
}
}

@ -209,7 +209,7 @@ if (!empty($groupId)) {
}
// Actions.
$document_id = isset($_REQUEST['id']) ? (int) $_REQUEST['id'] : null;
$documentIdFromGet = $document_id = isset($_REQUEST['id']) ? (int) $_REQUEST['id'] : null;
$currentUrl = api_get_self().'?'.api_get_cidreq().'&id='.$document_id;
$curdirpath = isset($_GET['curdirpath']) ? Security::remove_XSS($_GET['curdirpath']) : null;
@ -674,10 +674,12 @@ if (isset($document_id) && empty($action)) {
true
);
$parent_id = $document_data['parent_id'];
if (isset($document_data['parent_id'])) {
$parent_id = $document_data['parent_id'];
}
}
if (isset($document_data) && $document_data['path'] == '/certificates') {
if (isset($document_data) && isset($document_data['path']) && $document_data['path'] == '/certificates') {
$is_certificate_mode = true;
}
@ -1769,7 +1771,7 @@ if ($isAllowedToEdit ||
if ($fileLinkEnabled && !$is_certificate_mode) {
$actionsLeft .= Display::url(
Display::return_icon('clouddoc_new.png', get_lang('AddCloudLink'), '', ICON_SIZE_MEDIUM),
api_get_path(WEB_CODE_PATH).'document/add_link.php?'.api_get_cidreq().'&id='.$document_id
api_get_path(WEB_CODE_PATH).'document/add_link.php?'.api_get_cidreq().'&id='.$documentIdFromGet
);
}
}

@ -111,9 +111,12 @@ if (in_array(strtolower($pathinfo['extension']), $playerSupportedFiles)) {
$group_id = api_get_group_id();
$current_group = GroupManager::get_group_properties($group_id);
$current_group_name = $current_group['name'];
if (isset($group_id) && $group_id != '') {
if ($current_group) {
$current_group_name = $current_group['name'];
}
$interbreadcrumb[] = [
'url' => api_get_path(WEB_CODE_PATH).'group/group.php?'.api_get_cidreq(),
'name' => get_lang('Groups'),

@ -83,29 +83,6 @@ Version 1.1
- index.php: add filesize info in sent/received lists
- dropbox_submit.php: resubmit prevention only for GET action, because it gives some annoying behaviour in POST
* situation: white screen in IE6.
Version 1.2
-----------
- adapted entire dropbox tool so it can be used as a default tool in Dokeos 1.5
- index.php: add event registration to log use of tool in stats tables
- index.php: upload form checks for correct user selection and file specification before uploading the script
- dropbox_init1.inc.php: added dropbox_cnf["allowOverwrite"] to allow or disallow overwriting of files
- index.php: author name textbox is automatically filled in
- mailing functionality (René Haentjens)
- allowStudentToStudent and allowJustUpload options (id.)
- help in separate window (id.)
Version 1.3 (Patrick Cool)
--------------------------
- sortable table
- categories
- fixing a security hole
- tabs (which can be disabled: see $dropbox_cnf['sent_received_tabs'])
- same action on multiple documents ([zip]download, move, delete)
- consistency with the docuements tool (open/download file, icons of documents, ...)
- zip download of complete folder
Version 1.4 (Yannick Warnier)
-----------------------------
- removed all self-built database tables names
*/

@ -141,7 +141,7 @@ class ReadingComprehension extends UniqueAnswer
$form->addTextarea('questionDescription', get_lang('Text'), ['rows' => 20]);
// question name
if (api_get_configuration_value('save_titles_as_html')) {
$editorConfig = ['ToolbarSet' => 'Minimal'];
$editorConfig = ['ToolbarSet' => 'TitleAsHtml'];
$form->addHtmlEditor(
'questionName',
get_lang('Question'),

@ -119,7 +119,6 @@ class UniqueAnswerImage extends UniqueAnswer
}
$tempScenario = [];
if ($numberAnswers < 1) {
$numberAnswers = 1;
echo Display::return_message(get_lang('YouHaveToCreateAtLeastOneAnswer'));

@ -1922,7 +1922,7 @@ class Exercise
get_lang('ExerciseName'),
false,
false,
['ToolbarSet' => 'Minimal']
['ToolbarSet' => 'TitleAsHtml']
);
} else {
$form->addElement(
@ -3518,7 +3518,6 @@ class Exercise
error_log(print_r($extra, 1));
}
// Fixes problems with negatives values using intval
$true_score = floatval(trim($extra[0]));
$false_score = floatval(trim($extra[1]));
$doubt_score = floatval(trim($extra[2]));
@ -5560,8 +5559,6 @@ class Exercise
$destinationid = $select_question_hotspot;
$url = $url_hotspot;
} else {
//show if no error
//echo 'no error';
$comment = $answerComment = $objAnswerTmp->selectComment($nbrAnswers);
$answerDestination = $objAnswerTmp->selectDestination($nbrAnswers);
}
@ -6246,7 +6243,7 @@ class Exercise
// 1.1 Admins and teachers can access to the exercise
if ($filterByAdmin) {
if (api_is_platform_admin() || api_is_course_admin()) {
if (api_is_platform_admin() || api_is_course_admin() || api_is_course_tutor()) {
return ['value' => true, 'message' => ''];
}
}
@ -7962,6 +7959,10 @@ class Exercise
*/
public function getExerciseCategoryId()
{
if (empty($this->exerciseCategoryId)) {
return null;
}
return (int) $this->exerciseCategoryId;
}

@ -69,15 +69,7 @@ $exercisePath = substr($exercisePath, 0, strpos($exercisePath, $exfile));
$exercisePath = $exercisePath.'exercise.php';
// Clear the exercise session
Session::erase('objExercise');
Session::erase('objQuestion');
Session::erase('objAnswer');
Session::erase('questionList');
Session::erase('exerciseResult');
Session::erase('firstTime');
Session::erase('calculatedAnswerId');
Session::erase('duration_time_previous');
Session::erase('duration_time');
Exercise::cleanSessionVariables();
//General POST/GET/SESSION/COOKIES parameters recovery
$origin = api_get_origin();
@ -288,7 +280,6 @@ 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'] : '',
];
@ -628,7 +619,6 @@ if ($is_allowedToEdit) {
[6, 1, 5]
);
}
if (api_get_configuration_value('allow_exercise_categories') === false) {
echo Exercise::exerciseGrid(0, $page, $from, $limit, $keyword);
} else {

@ -41,10 +41,8 @@ require_once 'hotpotatoes.lib.php';
$_course = api_get_course_info();
// document path
$documentPath = api_get_path(SYS_COURSE_PATH).$_course['path']."/document";
$documentPath = api_get_path(SYS_COURSE_PATH).$_course['path'].'/document';
$origin = api_get_origin();
$path = isset($_GET['path']) ? Security::remove_XSS($_GET['path']) : null;
$is_allowedToEdit = api_is_allowed_to_edit(null, true) ||
api_is_drh() ||
api_is_student_boss() ||
@ -56,7 +54,6 @@ $TBL_TRACK_ATTEMPT = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
$TBL_TRACK_ATTEMPT_RECORDING = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING);
$TBL_LP_ITEM_VIEW = Database::get_course_table(TABLE_LP_ITEM_VIEW);
$allowCoachFeedbackExercises = api_get_setting('allow_coach_feedback_exercises') === 'true';
$course_id = api_get_course_int_id();
$exercise_id = isset($_REQUEST['exerciseId']) ? (int) $_REQUEST['exerciseId'] : 0;
$locked = api_resource_is_locked_by_gradebook($exercise_id, LINK_EXERCISE);
@ -155,7 +152,7 @@ $courseInfo = api_get_course_info();
//Send student email @todo move this code in a class, library
if (isset($_REQUEST['comments']) &&
$_REQUEST['comments'] == 'update' &&
$_REQUEST['comments'] === 'update' &&
($is_allowedToEdit || $is_tutor || $allowCoachFeedbackExercises)
) {
// Filtered by post-condition
@ -397,7 +394,7 @@ if ($is_allowedToEdit && $origin != 'learnpath') {
// Deleting an attempt
if (($is_allowedToEdit || $is_tutor || api_is_coach()) &&
isset($_GET['delete']) && $_GET['delete'] == 'delete' &&
isset($_GET['delete']) && $_GET['delete'] === 'delete' &&
!empty($_GET['did']) && $locked == false
) {
$exe_id = (int) $_GET['did'];
@ -420,7 +417,7 @@ if (($is_allowedToEdit || $is_tutor || api_is_coach()) &&
if ($is_allowedToEdit || $is_tutor) {
$interbreadcrumb[] = [
'url' => "exercise.php?".api_get_cidreq(),
'url' => 'exercise.php?'.api_get_cidreq(),
'name' => get_lang('Exercises'),
];
@ -442,11 +439,11 @@ if ($is_allowedToEdit || $is_tutor) {
}
if (($is_allowedToEdit || $is_tutor || api_is_coach()) &&
isset($_GET['a']) && $_GET['a'] == 'close' &&
isset($_GET['a']) && $_GET['a'] === 'close' &&
!empty($_GET['id']) && $locked == false
) {
// Close the user attempt otherwise left pending
$exe_id = intval($_GET['id']);
$exe_id = (int) $_GET['id'];
$sql = "UPDATE $TBL_TRACK_EXERCISES SET status = ''
WHERE exe_id = $exe_id AND status = 'incomplete'";
Database::query($sql);
@ -512,7 +509,7 @@ $extra = '<script>
});
</script>';
$extra .= '<div id="dialog-confirm" title="'.get_lang("ConfirmYourChoice").'">';
$extra .= '<div id="dialog-confirm" title="'.get_lang('ConfirmYourChoice').'">';
$form = new FormValidator(
'report',
'post',
@ -658,12 +655,8 @@ if ($is_allowedToEdit || $is_tutor) {
}';
}
// Autowidth
$extra_params['autowidth'] = 'true';
// Height auto
$extra_params['height'] = 'auto';
$extra_params['gridComplete'] = "
defaultGroupId = Cookies.get('default_group_".$exercise_id."');
if (typeof defaultGroupId !== 'undefined') {
@ -672,7 +665,6 @@ $extra_params['gridComplete'] = "
";
$extra_params['beforeRequest'] = "
//console.log('beforeRequest');
var defaultGroupId = $('#gs_group_name').val();
// Load from group menu
@ -682,7 +674,6 @@ if (typeof defaultGroupId !== 'undefined') {
// get from cookies
defaultGroupId = Cookies.get('default_group_".$exercise_id."');
$('#gs_group_name').val(defaultGroupId);
//console.log('from cookies');
}
if (typeof defaultGroupId !== 'undefined') {
@ -758,8 +749,6 @@ $gridJs = Display::grid_js(
// Update group
var defaultGroupId = Cookies.get('default_group_<?php echo $exercise_id; ?>');
//console.log('cookie GET defaultGroupId ' + defaultGroupId );
$('#gs_group_name').val(defaultGroupId);
// Adding search options
var options = {
@ -768,15 +757,12 @@ $gridJs = Display::grid_js(
'searchOnEnter': false,
afterSearch: function () {
$('#gs_group_name').on('change', function() {
//console.log('changed');
var defaultGroupId = $('#gs_group_name').val();
// Save default group id
Cookies.set('default_group_<?php echo $exercise_id; ?>', defaultGroupId);
//console.log('cookie SET defaultGroupId ' + defaultGroupId );
});
}
}
jQuery("#results").jqGrid('filterToolbar', options);
sgrid.triggerToolbar();
$('#results').on('click', 'a.exercise-recalculate', function (e) {

@ -118,7 +118,7 @@ $learnpath_id = isset($exercise_stat_info['orig_lp_id']) ? $exercise_stat_info['
$learnpath_item_id = isset($exercise_stat_info['orig_lp_item_id']) ? $exercise_stat_info['orig_lp_item_id'] : 0;
$learnpath_item_view_id = isset($exercise_stat_info['orig_lp_item_view_id']) ? $exercise_stat_info['orig_lp_item_view_id'] : 0;
if ($origin == 'learnpath') {
if ($origin === 'learnpath') {
?>
<form method="GET" action="exercise.php?<?php echo api_get_cidreq(); ?>">
<input type="hidden" name="origin" value="<?php echo $origin; ?>" />
@ -129,7 +129,6 @@ if ($origin == 'learnpath') {
}
$i = $total_score = $max_score = 0;
$remainingMessage = '';
$attemptButton = '';
@ -170,10 +169,9 @@ if ($objExercise->selectAttempts() > 0) {
} else {
$attempt_count++;
$remainingAttempts = $objExercise->selectAttempts() - $attempt_count;
if ($remainingAttempts) {
$attemptMessage = sprintf(get_lang('RemainingXAttempts'), $remainingAttempts);
$remainingMessage = sprintf("<p>%s</p> %s", $attemptMessage, $attemptButton);
$remainingMessage = sprintf('<p>%s</p> %s', $attemptMessage, $attemptButton);
}
}
} else {
@ -222,20 +220,12 @@ if (!in_array($origin, ['learnpath', 'embeddable'])) {
echo '</div>';
if (api_is_allowed_to_session_edit()) {
Session::erase('objExercise');
Session::erase('exe_id');
Session::erase('calculatedAnswerId');
Session::erase('duration_time_previous');
Session::erase('duration_time');
Exercise::cleanSessionVariables();
}
Display::display_footer();
} elseif ($origin === 'embeddable') {
if (api_is_allowed_to_session_edit()) {
Session::erase('objExercise');
Session::erase('exe_id');
Session::erase('calculatedAnswerId');
Session::erase('duration_time_previous');
Session::erase('duration_time');
Exercise::cleanSessionVariables();
}
Session::write('attempt_remaining', $remainingMessage);
@ -247,18 +237,13 @@ if (!in_array($origin, ['learnpath', 'embeddable'])) {
$href = $lp_mode === 'fullscreen' ? ' window.opener.location.href="'.$url.'" ' : ' top.location.href="'.$url.'"';
if (api_is_allowed_to_session_edit()) {
Session::erase('objExercise');
Session::erase('exe_id');
Session::erase('calculatedAnswerId');
Session::erase('duration_time_previous');
Session::erase('duration_time');
Exercise::cleanSessionVariables();
}
Session::write('attempt_remaining', $remainingMessage);
// Record the results in the learning path, using the SCORM interface (API)
echo "<script>window.parent.API.void_save_asset('$total_score', '$max_score', 0, 'completed');</script>";
echo '<script type="text/javascript">'.$href.'</script>';
Display::display_reduced_footer();
}

@ -358,6 +358,7 @@ function parseQti2($xmlData)
$currentQuestionItemBody = '';
$cardinality = '';
$nonHTMLTagToAvoid = [
'prompt',
'simpleChoice',
'choiceInteraction',
'inlineChoiceInteraction',
@ -391,6 +392,7 @@ function parseQti2($xmlData)
'category' => $node->getAttribute('category'),
'type' => '',
'tempdir' => $questionTempDir,
'description' => null,
];
break;
case 'section':
@ -620,6 +622,15 @@ function parseQti2($xmlData)
}
}
break;
case 'prompt':
$description = trim($node->nodeValue);
$description = htmlspecialchars_decode($description);
$description = Security::remove_XSS($description);
if (!empty($description)) {
$exerciseInfo['question'][$currentQuestionIdent]['description'] = $description;
}
break;
}
}
}

@ -7,16 +7,17 @@
interface ImsAnswerInterface
{
/**
* @param $questionIdent
* @param $questionStatment
* @param string $questionIdent
* @param string $questionStatment
* @param string $questionDesc
* @param string $questionMedia
*
* @return mixed
* @return string
*/
public function imsExportResponses($questionIdent, $questionStatment);
public function imsExportResponses($questionIdent, $questionStatment, $questionDesc = '', $questionMedia = '');
/**
* @param $questionIdent
* @param Question|null $question
*
* @return mixed
*/
@ -100,13 +101,20 @@ class ImsAnswerMultipleChoice extends Answer implements ImsAnswerInterface
{
/**
* Return the XML flow for the possible answers.
*
* @param string $questionIdent
* @param string $questionStatment
* @param string $questionDesc
* @param string $questionMedia
*
* @return string
*/
public function imsExportResponses($questionIdent, $questionStatment)
public function imsExportResponses($questionIdent, $questionStatment, $questionDesc = '', $questionMedia = '')
{
// @todo getAnswersList() converts the answers using api_html_entity_decode()
$this->answerList = $this->getAnswersList(true);
$out = ' <choiceInteraction responseIdentifier="'.$questionIdent.'" >'."\n";
$out .= ' <prompt><![CDATA['.formatExerciseQtiText($questionStatment).']]></prompt>'."\n";
$out .= ' <prompt><![CDATA['.formatExerciseQtiText($questionDesc).']]></prompt>'."\n";
if (is_array($this->answerList)) {
foreach ($this->answerList as $current_answer) {
$out .= '<simpleChoice identifier="answer_'.$current_answer['id'].'" fixed="false">
@ -179,8 +187,15 @@ class ImsAnswerFillInBlanks extends Answer implements ImsAnswerInterface
/**
* Export the text with missing words.
*
* @param string $questionIdent
* @param string $questionStatment
* @param string $questionDesc
* @param string $questionMedia
*
* @return string
*/
public function imsExportResponses($questionIdent, $questionStatment)
public function imsExportResponses($questionIdent, $questionStatment, $questionDesc = '', $questionMedia = '')
{
$this->answerList = $this->getAnswersList(true);
$text = isset($this->answerText) ? $this->answerText : '';
@ -236,8 +251,15 @@ class ImsAnswerMatching extends Answer implements ImsAnswerInterface
/**
* Export the question part as a matrix-choice, with only one possible answer per line.
*
* @param string $questionIdent
* @param string $questionStatment
* @param string $questionDesc
* @param string $questionMedia
*
* @return string
*/
public function imsExportResponses($questionIdent, $questionStatment)
public function imsExportResponses($questionIdent, $questionStatment, $questionDesc = '', $questionMedia = '')
{
$this->answerList = $this->getAnswersList(true);
$maxAssociation = max(count($this->leftList), count($this->rightList));
@ -322,8 +344,15 @@ class ImsAnswerHotspot extends Answer implements ImsAnswerInterface
private $gradeList = [];
/**
* TODO update this to match hot spots instead of copying matching
* @todo update this to match hot spots instead of copying matching
* Export the question part as a matrix-choice, with only one possible answer per line.
*
* @param string $questionIdent
* @param string $questionStatment
* @param string $questionDesc
* @param string $questionMedia
*
* @return string
*/
public function imsExportResponses($questionIdent, $questionStatment, $questionDesc = '', $questionMedia = '')
{
@ -406,15 +435,18 @@ class ImsAnswerHotspot extends Answer implements ImsAnswerInterface
class ImsAnswerFree extends Answer implements ImsAnswerInterface
{
/**
* TODO implement
* @todo implement
* Export the question part as a matrix-choice, with only one possible answer per line.
*
* @param string $questionIdent
* @param string $questionStatment
* @param string $questionDesc
* @param string $questionMedia
*
* @return string
*/
public function imsExportResponses(
$questionIdent,
$questionStatment,
$questionDesc = '',
$questionMedia = ''
) {
public function imsExportResponses($questionIdent, $questionStatment, $questionDesc = '', $questionMedia = '')
{
$questionDesc = formatExerciseQtiText($questionDesc);
return '<extendedTextInteraction responseIdentifier="'.$questionIdent.'" >

@ -10,7 +10,6 @@
* The two bits are separate to allow for a one-big-javascript and a one-big-html
* files to be built. Each export function thus returns an array of HTML+JS.
*
*
* @author Claro Team <cvs@claroline.net>
* @author Yannick Warnier <yannick.warnier@beeznest.com>
*

@ -15,10 +15,7 @@ require_once __DIR__.'/../inc/global.inc.php';
$current_course_tool = TOOL_QUIZ;
// Clear the exercise session just in case
Session::erase('objExercise');
Session::erase('calculatedAnswerId');
Session::erase('duration_time_previous');
Session::erase('duration_time');
Exercise::cleanSessionVariables();
$this_section = SECTION_COURSES;
@ -38,9 +35,9 @@ if (!$result) {
api_not_allowed(true);
}
$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;
$learnpathItemViewId = isset($_REQUEST['learnpath_item_view_id']) ? intval($_REQUEST['learnpath_item_view_id']) : 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;
$learnpathItemViewId = isset($_REQUEST['learnpath_item_view_id']) ? (int) $_REQUEST['learnpath_item_view_id'] : null;
$origin = api_get_origin();
$logInfo = [
@ -348,6 +345,7 @@ if (!empty($attempts)) {
case RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS_AND_RANKING:
case RESULT_DISABLE_SHOW_FINAL_SCORE_ONLY_WITH_CATEGORIES:
case RESULT_DISABLE_RANKING:
case RESULT_DISABLE_SHOW_ONLY_IN_CORRECT_ANSWER:
$header_names = [
get_lang('Attempt'),
get_lang('StartDate'),
@ -390,6 +388,7 @@ if (!empty($attempts)) {
}
$table_content = $table->toHtml();
}
$selectAttempts = $objExercise->selectAttempts();
if ($selectAttempts) {
$attempt_message = get_lang('Attempts').' '.$counter.' / '.$selectAttempts;
@ -410,6 +409,7 @@ if ($time_control) {
// Ofaj
//$html .= $message;
$disable = api_get_configuration_value('exercises_disable_new_attempts');
if ($disable && empty($exercise_stat_info)) {
$exercise_url_button = Display::return_message(get_lang('NewExerciseAttemptDisabled'));
}

@ -1412,6 +1412,11 @@ abstract class Question
'QuizQuestionDeleted',
api_get_user_id()
);
Event::addEvent(
LOG_QUESTION_DELETED,
LOG_QUESTION_ID,
$this->iid
);
$this->removePicture();
} else {
// just removes the exercise from the list
@ -1428,6 +1433,11 @@ abstract class Question
'QuizQuestionDeleted',
api_get_user_id()
);
Event::addEvent(
LOG_QUESTION_REMOVED_FROM_QUIZ,
LOG_QUESTION_ID,
$this->iid
);
}
return true;
@ -1600,7 +1610,7 @@ abstract class Question
// question name
if (api_get_configuration_value('save_titles_as_html')) {
$editorConfig = ['ToolbarSet' => 'Minimal'];
$editorConfig = ['ToolbarSet' => 'TitleAsHtml'];
$form->addHtmlEditor(
'questionName',
get_lang('Question'),

@ -1,6 +1,8 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CoreBundle\Entity\ExtraField as ExtraFieldEntity;
use ChamiloSession as Session;
use Knp\Component\Pager\Paginator;
@ -9,8 +11,6 @@ use Knp\Component\Pager\Paginator;
* This script allows administrators to manage questions and add them into their exercises.
* One question can be in several exercises.
*
* @package chamilo.exercise
*
* @author Olivier Brouckaert
* @author Julio Montoya adding support to query all questions from all session, courses, exercises
* @author Modify by hubert borderiou 2011-10-21 Question's category
@ -253,10 +253,8 @@ if (isset($_REQUEST['action'])) {
case 'clone':
if (!empty($_REQUEST['questions']) && !empty($fromExercise)) {
$questions = $_REQUEST['questions'];
$objExercise = new Exercise();
$objExercise->read($fromExercise, false);
$origin_course_id = (int) $_GET['course_id'];
$origin_course_info = api_get_course_info_by_id($origin_course_id);
$current_course = api_get_course_info();
@ -274,7 +272,7 @@ if (isset($_REQUEST['action'])) {
$new_question_obj = Question::read($new_id);
$new_question_obj->addToList($fromExercise);
//Reading Answers obj of the current course
$new_answer_obj = new Answer($old_question_id, $origin_course_id);
$new_answer_obj = new Answer($questionId, $origin_course_id);
$new_answer_obj->read();
//Duplicating the Answers in the current course
$new_answer_obj->duplicate($new_question_obj, $current_course);

@ -4334,8 +4334,10 @@ function get_whats_new()
access_tool = '".Database::escape_string($tool)."'";
$result = Database::query($sql);
$row = Database::fetch_array($result);
Session::write('last_forum_access', $row['access_date']);
$lastForumAccess = $row['access_date'];
if (isset($row['access_date'])) {
Session::write('last_forum_access', $row['access_date']);
$lastForumAccess = $row['access_date'];
}
}
$whatsNew = Session::read('whatsnew_post_info');
@ -6369,7 +6371,8 @@ function getAttachedFiles(
$courseId = (int) $courseId;
$attachId = (int) $attachId;
$postId = (int) $postId;
$threadId = !empty($threadId) ? intval($threadId) : isset($_REQUEST['thread']) ? intval($_REQUEST['thread']) : '';
$threadId = (int) $threadId;
if (empty($courseId)) {
// $courseId can be null, use api method
$courseId = api_get_course_int_id();

@ -19,13 +19,13 @@ $charset = api_get_system_encoding();
// Replace image path
$path_image = api_get_path(WEB_COURSE_PATH).api_get_course_path();
$path_image_search = '../..'.api_get_path(REL_COURSE_PATH).api_get_course_path();
$glossaryId = isset($_POST['glossary_id']) ? (int) $_POST['glossary_id'] : 0;
$glossaryId = isset($_REQUEST['glossary_id']) ? (int) $_REQUEST['glossary_id'] : 0;
$description = get_lang('NoResults');
if (!empty($glossaryId)) {
$description = GlossaryManager::get_glossary_term_by_glossary_id($glossaryId);
$description = str_replace($path_image_search, $path_image, $description);
} elseif (isset($_POST['glossary_data']) && $_POST['glossary_data'] == 'true') {
} elseif (isset($_REQUEST['glossary_data']) && $_REQUEST['glossary_data'] == 'true') {
// get_glossary_terms
$glossary_data = GlossaryManager::get_glossary_terms();
$glossary_all_data = [];
@ -35,16 +35,8 @@ if (!empty($glossaryId)) {
}
$description = implode('[|.|_|.|-|.|]', $glossary_all_data);
}
} elseif (isset($_POST['glossary_name'])) {
$glossaryName = Security::remove_XSS($_POST['glossary_name']);
$glossaryName = api_convert_encoding($glossaryName, $charset, 'UTF-8');
$glossaryName = trim($glossaryName);
if (api_get_configuration_value('save_titles_as_html')) {
$glossaryName = "%$glossaryName%";
}
$glossaryInfo = GlossaryManager::get_glossary_term_by_glossary_name($glossaryName);
} elseif (isset($_REQUEST['glossary_name'])) {
$glossaryInfo = GlossaryManager::get_glossary_term_by_glossary_name($_REQUEST['glossary_name']);
if (!empty($glossaryInfo)) {
$description = str_replace(

@ -13,6 +13,12 @@ if (!api_is_student_boss()) {
api_protect_course_script(true);
}
api_block_anonymous_users();
if (!api_is_allowed_to_edit() && !api_is_student_boss()) {
api_not_allowed(true);
}
api_set_more_memory_and_time_limits();
//extra javascript functions for in html head:
@ -26,12 +32,6 @@ function confirmation() {
}
</script>";
api_block_anonymous_users();
if (!api_is_allowed_to_edit() && !api_is_student_boss()) {
api_not_allowed(true);
}
$categoryId = isset($_GET['cat_id']) ? (int) $_GET['cat_id'] : 0;
$action = isset($_GET['action']) && $_GET['action'] ? $_GET['action'] : null;
$filterOfficialCode = isset($_POST['filter']) ? Security::remove_XSS($_POST['filter']) : null;

@ -121,17 +121,14 @@ switch ($action) {
if (!empty($htmlList)) {
$counter = 0;
//error_log('Loading html list');
$content = '';
foreach ($htmlList as $value) {
$content .= $value.'<pagebreak>';
//error_log('Loading html: '.$counter);
$counter++;
}
$tempFile = api_get_path(SYS_ARCHIVE_PATH).uniqid('gradebook_export_all').'.html';
file_put_contents($tempFile, $content);
//error_log('generating pdf');
$pdf->html_to_pdf(
$tempFile,
null,
@ -140,14 +137,12 @@ switch ($action) {
true,
true
);
//error_log('End generating');
}
// Delete calc_score session data
Session::erase('calc_score');
break;
case 'download':
//Session::write('use_gradebook_cache', true);
$userId = isset($_GET['user_id']) && $_GET['user_id'] ? $_GET['user_id'] : null;
$cats = Category::load($cat_id, null, null, null, null, null, false);
GradebookUtils::generateTable($courseInfo, $userId, $cats);

@ -1,6 +1,7 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Responses to AJAX calls.
*/

@ -209,4 +209,29 @@ class MailTemplateManager extends Model
return false;
}
/**
* Gets a custom mail template by the name of the template it replaces.
*
* @param string $templateType Name of the template file it replaces
*
* @return string
*/
public function getTemplateByType($templateType)
{
if (empty($templateType)) {
return '';
}
$result = Database::select(
'template',
$this->table,
['where' => ['type = ? ' => $templateType, ' AND url_id = ? ' => api_get_current_access_url_id()]],
'first'
);
if (empty($result)) {
return '';
}
return $result['template'];
}
}

@ -3,6 +3,8 @@
class NotificationEvent extends Model
{
const ACCOUNT_EXPIRATION = 1;
const JUSTIFICATION_EXPIRATION = 2;
public $table;
public $columns = [
'id',
@ -14,9 +16,6 @@ class NotificationEvent extends Model
'event_type',
'event_id',
];
const ACCOUNT_EXPIRATION = 1;
const JUSTIFICATION_EXPIRATION = 2;
public $extraFieldName;
/**
@ -63,7 +62,6 @@ class NotificationEvent extends Model
}
$form->freeze('event_id');
$form->addText('title', get_lang('Title'));
$form->addTextarea('content', get_lang('Content'));
$form->addText('link', get_lang('Link'), false);
@ -156,7 +154,7 @@ class NotificationEvent extends Model
'content' => $event['content'],
'event_text' => get_lang('ExpirationDate').': '.api_get_local_time($userInfo['expiration_date']),
'link' => $event['link'],
'persistent' => $event['persistent']
'persistent' => $event['persistent'],
];
}
break;
@ -197,7 +195,7 @@ class NotificationEvent extends Model
'content' => $event['content'],
'event_text' => $eventText,
'link' => $url,
'persistent' => $event['persistent']
'persistent' => $event['persistent'],
];
}
}

@ -279,8 +279,10 @@ define('LOG_USER_DELETE_ACCOUNT_REQUEST', 'user_delete_account_request');
define('LOG_QUESTION_CREATED', 'question_created');
define('LOG_QUESTION_UPDATED', 'question_updated');
define('LOG_QUESTION_DELETED', 'question_deleted');
define('LOG_QUESTION_REMOVED_FROM_QUIZ', 'question_removed_from_quiz');
define('USERNAME_PURIFIER', '/[^0-9A-Za-z_\.]/');
define('USERNAME_PURIFIER', '/[^0-9A-Za-z_\.-]/');
//used when login_is_email setting is true
define('USERNAME_PURIFIER_MAIL', '/[^0-9A-Za-z_\.@]/');
@ -708,7 +710,6 @@ require_once __DIR__.'/internationalization.lib.php';
*
* @return string the requested path or the converted path
*
*
* Notes about the current behaviour model:
* 1. Windows back-slashes are converted to slashes in the result.
* 2. A semi-absolute web-path is detected by its leading slash. On Linux systems, absolute system paths start with
@ -5168,11 +5169,14 @@ function api_max_sort_value($user_course_category, $user_id)
*
* @author Julian Prud'homme
*
* @param int the number of seconds
* @param int $seconds number of seconds
* @param string $space
* @param bool $showSeconds
* @param bool $roundMinutes
*
* @return string the formated time
* @return string the formatted time
*/
function api_time_to_hms($seconds, $space = ':')
function api_time_to_hms($seconds, $space = ':', $showSeconds = true, $roundMinutes = false)
{
// $seconds = -1 means that we have wrong data in the db.
if ($seconds == -1) {
@ -5191,6 +5195,24 @@ function api_time_to_hms($seconds, $space = ':')
// How many minutes ?
$min = floor(($seconds - ($hours * 3600)) / 60);
if ($roundMinutes) {
if ($min >= 45) {
$min = 45;
}
if ($min >= 30 && $min <= 44) {
$min = 30;
}
if ($min >= 15 && $min <= 29) {
$min = 15;
}
if ($min >= 0 && $min <= 14) {
$min = 0;
}
}
// How many seconds
$sec = floor($seconds - ($hours * 3600) - ($min * 60));
@ -5206,7 +5228,12 @@ function api_time_to_hms($seconds, $space = ':')
$min = "0$min";
}
return $hours.$space.$min.$space.$sec;
$seconds = '';
if ($showSeconds) {
$seconds = $space.$sec;
}
return $hours.$space.$min.$seconds;
}
/* FILE SYSTEM RELATED FUNCTIONS */
@ -6382,7 +6409,7 @@ function api_replace_dangerous_char($filename, $treat_spaces_as_hyphens = true)
250,
'',
true,
true,
false,
false,
false,
$treat_spaces_as_hyphens
@ -9016,7 +9043,28 @@ function api_protect_course_group($tool, $showHeader = true)
{
$groupId = api_get_group_id();
if (!empty($groupId)) {
if (api_is_platform_admin()) {
return true;
}
if (api_is_allowed_to_edit(false, true, true)) {
return true;
}
$userId = api_get_user_id();
$sessionId = api_get_session_id();
if (!empty($sessionId)) {
if (api_is_coach($sessionId, api_get_course_int_id())) {
return true;
}
if (api_is_drh()) {
if (SessionManager::isUserSubscribedAsHRM($sessionId, $userId)) {
return true;
}
}
}
$groupInfo = GroupManager::get_group_properties($groupId);
// Group doesn't exists
@ -9445,10 +9493,6 @@ function api_unserialize_content($type, $serialized, $ignoreErrors = false)
/**
* Set the From and ReplyTo properties to PHPMailer instance.
*
* @param PHPMailer $mailer
* @param array $sender
* @param array $replyToAddress
*
* @throws phpmailerException
*/
function api_set_noreply_and_from_address_to_mailer(PHPMailer $mailer, array $sender, array $replyToAddress = [])

@ -118,8 +118,6 @@ function array_to_string($array, $separator = ',')
}
/**
* @param array $array
*
* @return array
*/
function array_flatten(array $array)

@ -4903,6 +4903,31 @@ class CourseManager
return $hotCourses;
}
public function totalSubscribedUsersInCourses($urlId)
{
$table_course = Database::get_main_table(TABLE_MAIN_COURSE);
$table_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
$courseUsers = Database::get_main_table(TABLE_MAIN_COURSE_USER);
$urlId = (int) $urlId;
$sql = "SELECT count(cu.user_id) count
FROM $courseUsers cu
INNER JOIN $table_course_rel_access_url u
ON cu.c_id = u.c_id
WHERE
relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
u.access_url_id = $urlId AND
visibility <> ".COURSE_VISIBILITY_CLOSED." AND
visibility <> ".COURSE_VISIBILITY_HIDDEN."
";
$res = Database::query($sql);
$row = Database::fetch_array($res);
return $row['count'];
}
/**
* Get courses count.
*
@ -4948,8 +4973,9 @@ class CourseManager
{
$table_course = Database::get_main_table(TABLE_MAIN_COURSE);
$table_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
$sql = "SELECT count(id) FROM $table_course c";
if (!empty($urlId) && $urlId == intval($urlId)) {
$sql = "SELECT count(c.id) FROM $table_course c";
if (!empty($urlId)) {
$urlId = (int) $urlId;
$sql .= ", $table_course_rel_access_url u
WHERE
c.id = u.c_id AND
@ -5240,8 +5266,6 @@ class CourseManager
/**
* Course available settings variables see c_course_setting table.
*
* @param AppPlugin $appPlugin
*
* @return array
*/
public static function getCourseSettingVariables(AppPlugin $appPlugin)
@ -5311,7 +5335,6 @@ class CourseManager
}
/**
* @param AppPlugin $appPlugin
* @param string $variable
* @param string|array $value
* @param int $courseId
@ -6263,8 +6286,6 @@ class CourseManager
/**
* Get the course categories form a course list.
*
* @param array $courseList
*
* @return array
*/
public static function getCourseCategoriesFromCourseList(array $courseList)
@ -6312,8 +6333,6 @@ class CourseManager
}
/**
* @param Course $course
*
* @return bool
*/
public static function hasPicture(Course $course)
@ -6324,7 +6343,6 @@ class CourseManager
/**
* Get the course picture path.
*
* @param Course $course
* @param bool $fullSize
*
* @return string|null

@ -16,7 +16,7 @@ class CourseCategory
public static function getCategoryById($categoryId)
{
$table = Database::get_main_table(TABLE_MAIN_CATEGORY);
$categoryId = intval($categoryId);
$categoryId = (int) $categoryId;
$sql = "SELECT * FROM $table WHERE id = $categoryId";
$result = Database::query($sql);
if (Database::num_rows($result)) {
@ -29,7 +29,7 @@ class CourseCategory
/**
* Get category details from a simple category code.
*
* @param string $category The literal category code
* @param string $categoryCode The literal category code
*
* @return array
*/
@ -41,16 +41,18 @@ class CourseCategory
$result = Database::query($sql);
if (Database::num_rows($result)) {
$category = Database::fetch_array($result, 'ASSOC');
// Get access url id
$table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE_CATEGORY);
$sql = "SELECT * FROM $table WHERE course_category_id = ".$category['id'];
$result = Database::query($sql);
$result = Database::fetch_array($result);
if ($result) {
$category['access_url_id'] = $result['access_url_id'];
}
if ($category) {
// Get access url id
$table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE_CATEGORY);
$sql = "SELECT * FROM $table WHERE course_category_id = ".$category['id'];
$result = Database::query($sql);
$result = Database::fetch_array($result);
if ($result) {
$category['access_url_id'] = $result['access_url_id'];
}
return $category;
return $category;
}
}
return [];
@ -214,7 +216,7 @@ class CourseCategory
{
$table = Database::get_main_table(TABLE_MAIN_CATEGORY);
$categoryId = Database::escape_string($categoryId);
$delta = intval($delta);
$delta = (int) $delta;
// First get to the highest level possible in the tree
$result = Database::query("SELECT parent_id FROM $table WHERE code = '$categoryId'");
$row = Database::fetch_array($result);
@ -222,7 +224,6 @@ class CourseCategory
// if a parent was found, enter there to see if he's got one more parent
self::updateParentCategoryChildrenCount($row['parent_id'], $delta);
}
// Now we're at the top, get back down to update each child
//$children_count = courseCategoryChildrenCount($categoryId);
$sql = "UPDATE $table SET children_count = (children_count - ".abs($delta).") WHERE code = '$categoryId'";
if ($delta >= 0) {
@ -328,7 +329,7 @@ class CourseCategory
{
$table = Database::get_main_table(TABLE_MAIN_CATEGORY);
$code = Database::escape_string($code);
$tree_pos = intval($tree_pos);
$tree_pos = (int) $tree_pos;
$parent_id = Database::escape_string($parent_id);
$parentIdCondition = " AND (parent_id IS NULL OR parent_id = '' )";
@ -382,7 +383,7 @@ class CourseCategory
public static function courseCategoryChildrenCount($categoryId)
{
$table = Database::get_main_table(TABLE_MAIN_CATEGORY);
$categoryId = intval($categoryId);
$categoryId = (int) $categoryId;
$count = 0;
if (empty($categoryId)) {
return 0;

@ -858,7 +858,7 @@ class CourseHome
$item = [];
$studentview = false;
$tool['original_link'] = $tool['link'];
if ($tool['image'] == 'scormbuilder.gif') {
if ($tool['image'] === 'scormbuilder.gif') {
// Check if the published learnpath is visible for student
$lpId = self::getPublishedLpIdFromLink($tool['link']);
if (api_is_allowed_to_edit(null, true)) {
@ -928,7 +928,6 @@ class CourseHome
$info = pathinfo($tool['image']);
$basename = basename($tool['image'], '.'.$info['extension']); // $file is set to "index"
$tool['image'] = $basename.'_na.'.$info['extension'];
$link['name'] = Display::return_icon(
'invisible.png',
get_lang('Activate'),
@ -977,7 +976,7 @@ class CourseHome
}
}
$item['visibility'] = null;
$item['visibility'] = '';
if (isset($lnk) && is_array($lnk)) {
foreach ($lnk as $this_link) {
if (empty($tool['adminlink'])) {
@ -986,8 +985,6 @@ class CourseHome
$this_link['name'].'</a>';
}
}
} else {
$item['visibility'] .= '';
}
// NOTE : Table contains only the image file name, not full path
@ -1009,7 +1006,7 @@ class CourseHome
$qm_or_amp = strpos($tool['link'], '?') === false ? '?' : '&';
// If it's a link, we don't add the cidReq
if ($tool['image'] == 'file_html.png' || $tool['image'] == 'file_html_na.png') {
if ($tool['image'] === 'file_html.png' || $tool['image'] === 'file_html_na.png') {
$tool['link'] = $tool['link'];
} else {
$tool['link'] = $tool['link'].$qm_or_amp.api_get_cidreq();
@ -1216,7 +1213,7 @@ class CourseHome
'external_na.gif',
];
$toolName = Security::remove_XSS(stripslashes($tool['name']));
$toolName = Security::remove_XSS(stripslashes(strip_tags($tool['name'])));
if (isset($tool['image']) && in_array($tool['image'], $already_translated_icons)) {
return $toolName;
@ -1777,7 +1774,6 @@ class CourseHome
/**
* Find the tool icon when homepage_view is activity_big.
*
* @param array $item
* @param int $iconSize
* @param bool $generateId
*

@ -1723,6 +1723,8 @@ class Event
}
/**
* Get the last best result from all attempts in exercises per user (out of learning paths).
*
* @param int $user_id
* @param int $exercise_id
* @param int $courseId
@ -2268,6 +2270,17 @@ class Event
$courseTrackingTable = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
Database::insert($courseTrackingTable, $params);
// Time should also be added to the track_e_login table so as to
// affect total time on the platform
$params = [
'login_user_id' => $userId,
'login_date' => $loginDate,
'user_ip' => api_get_real_ip(),
'logout_date' => $logoutDate,
];
$platformTrackingTable = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
Database::insert($platformTrackingTable, $params);
return true;
}
@ -2300,6 +2313,7 @@ class Event
return false;
}
$courseTrackingTable = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
$platformTrackingTable = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
$courseId = (int) $courseId;
$userId = (int) $userId;
$sessionId = (int) $sessionId;
@ -2334,6 +2348,21 @@ class Event
$courseAccessId = $row[0];
$sql = "DELETE FROM $courseTrackingTable
WHERE course_access_id = $courseAccessId";
Database::query($sql);
}
$sql = "SELECT login_id
FROM $platformTrackingTable
WHERE
login_user_id = $userId AND
(UNIX_TIMESTAMP(logout_date) - UNIX_TIMESTAMP(login_date)) = '$virtualTime'
ORDER BY login_date DESC LIMIT 0,1";
$result = Database::query($sql);
if (Database::num_rows($result) > 0) {
// Found the latest connection
$row = Database::fetch_row($result);
$loginAccessId = $row[0];
$sql = "DELETE FROM $platformTrackingTable
WHERE login_id = $loginAccessId";
$result = Database::query($sql);
return $result;

@ -2780,7 +2780,7 @@ HOTSPOT;
$minNote = api_get_setting('exercise_min_score');
if ($maxNote != '' && $minNote != '') {
if (!empty($weight) && intval($weight) != 0) {
if (!empty($weight) && (float) $weight !== 0) {
$score = $minNote + ($maxNote - $minNote) * $score / $weight;
} else {
$score = $minNote;
@ -2833,6 +2833,7 @@ HOTSPOT;
$percentage = float_format($percentage, 1);
$score = float_format($score, 1);
$weight = float_format($weight, 1);
if ($roundValues) {
$whole = floor($percentage); // 1
$fraction = $percentage - $whole; // .25
@ -2871,6 +2872,7 @@ HOTSPOT;
if ($hidePercentageSign) {
$percentageSign = '';
}
$html = $percentage."$percentageSign ($score / $weight)";
if ($show_only_percentage) {
$html = $percentage.$percentageSign;
@ -2888,6 +2890,7 @@ HOTSPOT;
// Ignore other formats and use the configuratio['exercise_score_format'] value
// But also keep the round values settings.
$format = api_get_configuration_value('exercise_score_format');
if (!empty($format)) {
$html = ScoreDisplay::instance()->display_score([$score, $weight], $format);
}
@ -2994,7 +2997,6 @@ HOTSPOT;
}
/**
* @param FormValidator $form
* @param string $name
* @param $weight
* @param $selected
@ -3547,7 +3549,7 @@ EOT;
$best_score = 0;
if (!empty($user_results)) {
foreach ($user_results as $result) {
if (!empty($result['exe_weighting']) && intval($result['exe_weighting']) != 0) {
if (!empty($result['exe_weighting']) && (float) $result['exe_weighting'] != 0) {
$score = $result['exe_result'] / $result['exe_weighting'];
if ($score >= $best_score) {
$best_score = $score;
@ -4953,12 +4955,9 @@ EOT;
->getScalarResult();
$data = [];
/** @var TrackEExercises $item */
foreach ($result as $item) {
$bestAttemp = self::get_best_attempt_by_user($item['exeUserId'], $exerciseId, $courseId, $sessionId = 0);
$data[] = $bestAttemp;
$data[] = self::get_best_attempt_by_user($item['exeUserId'], $exerciseId, $courseId, $sessionId = 0);
}
usort(
@ -4979,7 +4978,6 @@ EOT;
// flags to display the same position in case of tie
$lastScore = $data[0]['exe_result'];
$position = 1;
$data = array_map(
function ($item) use (&$lastScore, &$position) {
if ($item['exe_result'] < $lastScore) {
@ -5056,7 +5054,6 @@ EOT;
}
/**
* @param Exercise $objExercise
* @param float $score
* @param float $weight
* @param bool $checkPassPercentage
@ -5298,7 +5295,6 @@ EOT;
}
/**
* @param DateTime $time
* @param int $userId
* @param int $courseId
* @param int $sessionId
@ -5410,7 +5406,6 @@ EOT;
*
* @param float $totalScore
* @param float $totalWeight
* @param Exercise $objExercise
* @param int $studentId
* @param string $courseCode
* @param int $sessionId
@ -5468,4 +5463,104 @@ EOT;
return Category::getDownloadCertificateBlock($certificate);
}
/**
* @param int $exeId ID from track_e_exercises
* @param int $userId User ID
* @param int $exerciseId Exercise ID
* @param int $courseId Optional. Coure ID.
*
* @throws \Doctrine\ORM\ORMException
* @throws \Doctrine\ORM\OptimisticLockException
* @throws \Doctrine\ORM\TransactionRequiredException
*
* @return TrackEExercises|null
*/
public static function recalculateResult($exeId, $userId, $exerciseId, $courseId = 0)
{
if (empty($userId) || empty($exerciseId)) {
return null;
}
$em = Database::getManager();
/** @var TrackEExercises $trackedExercise */
$trackedExercise = $em->getRepository('ChamiloCoreBundle:TrackEExercises')->find($exeId);
if (empty($trackedExercise)) {
return null;
}
if ($trackedExercise->getExeUserId() != $userId ||
$trackedExercise->getExeExoId() != $exerciseId
) {
return null;
}
$questionList = $trackedExercise->getDataTracking();
if (empty($questionList)) {
return null;
}
$questionList = explode(',', $questionList);
$exercise = new Exercise($courseId);
$courseInfo = $courseId ? api_get_course_info_by_id($courseId) : [];
if ($exercise->read($exerciseId) === false) {
return null;
}
$totalScore = 0;
$totalWeight = 0;
$pluginEvaluation = QuestionOptionsEvaluationPlugin::create();
$formula = 'true' === $pluginEvaluation->get(QuestionOptionsEvaluationPlugin::SETTING_ENABLE)
? $pluginEvaluation->getFormulaForExercise($exerciseId)
: 0;
if (empty($formula)) {
foreach ($questionList as $questionId) {
$question = Question::read($questionId, $courseInfo);
if (false === $question) {
continue;
}
$totalWeight += $question->selectWeighting();
// We're inside *one* question. Go through each possible answer for this question
$result = $exercise->manage_answer(
$exeId,
$questionId,
[],
'exercise_result',
[],
false,
true,
false,
$exercise->selectPropagateNeg(),
[],
[],
true
);
// Adding the new score.
$totalScore += $result['score'];
}
} else {
$totalScore = $pluginEvaluation->getResultWithFormula($exeId, $formula);
$totalWeight = $pluginEvaluation->getMaxScore();
}
$trackedExercise
->setExeResult($totalScore)
->setExeWeighting($totalWeight);
$em->persist($trackedExercise);
$em->flush();
return $trackedExercise;
}
}

@ -390,7 +390,6 @@ class ExerciseShowFunctions
echo '<td width="5%">';
echo Display::return_icon($icon, null, null, ICON_SIZE_TINY);
echo '</td>';
if ($exercise->showExpectedChoiceColumn()) {
if ($hide_expected_answer === false) {
echo '<td width="5%">';

@ -75,25 +75,42 @@ class GlossaryManager
*
* @author Isaac Flores <florespaz_isaac@hotmail.com>
*
* @param string $glossary_name The glossary term name
* @param string $name The glossary term name
*
* @return array The glossary info
*/
public static function get_glossary_term_by_glossary_name($glossary_name)
public static function get_glossary_term_by_glossary_name($name)
{
$table = Database::get_course_table(TABLE_GLOSSARY);
$session_id = api_get_session_id();
$course_id = api_get_course_int_id();
$sql_filter = api_get_session_condition($session_id);
$sql = 'SELECT * FROM '.$table.'
$sessionCondition = api_get_session_condition($session_id);
$glossaryName = Security::remove_XSS($name);
$glossaryName = api_convert_encoding($glossaryName, 'UTF-8', 'UTF-8');
$glossaryName = trim($glossaryName);
$parsed = $glossaryName;
if (api_get_configuration_value('save_titles_as_html')) {
$parsed = api_htmlentities($parsed);
$parsed = "%$parsed%";
}
$sql = "SELECT * FROM $table
WHERE
c_id = '.$course_id.' AND
name LIKE trim("'.Database::escape_string($glossary_name).'")'.$sql_filter;
c_id = $course_id AND
(
name LIKE '".Database::escape_string($glossaryName)."'
OR
name LIKE '".Database::escape_string($parsed)."'
)
$sessionCondition
LIMIT 1
";
$rs = Database::query($sql);
if (Database::num_rows($rs) > 0) {
$row = Database::fetch_array($rs, 'ASSOC');
return $row;
if (Database::num_rows($rs) > 0) {
return Database::fetch_array($rs, 'ASSOC');
}
return [];

@ -132,8 +132,6 @@ abstract class HookEvent implements HookEventInterface
/**
* Set an array with data needed by hooks.
*
* @param array $data
*
* @return $this
*/
public function setEventData(array $data)

@ -13,8 +13,6 @@
interface HookAdminBlockObserverInterface extends HookObserverInterface
{
/**
* @param HookAdminBlockEventInterface $hook
*
* @return int
*/
public function hookAdminBlock(HookAdminBlockEventInterface $hook);

@ -51,8 +51,6 @@ interface HookEventInterface
/**
* Set an array with data needed by hooks.
*
* @param array $data
*
* @return $this
*/
public function setEventData(array $data);

@ -2461,6 +2461,92 @@ class MessageManager
return $messages;
}
/**
* Get the data of the last received messages for a user.
*
* @param int $userId The user id
* @param int $lastId The id of the last received message
*
* @return array
*/
public static function getReceivedMessages($userId, $lastId = 0)
{
$userId = intval($userId);
$lastId = intval($lastId);
if (empty($userId)) {
return [];
}
$messagesTable = Database::get_main_table(TABLE_MESSAGE);
$userTable = Database::get_main_table(TABLE_MAIN_USER);
$sql = "SELECT m.*, u.user_id, u.lastname, u.firstname, u.picture_uri
FROM $messagesTable as m
INNER JOIN $userTable as u
ON m.user_sender_id = u.user_id
WHERE
m.user_receiver_id = $userId AND
m.msg_status IN (".MESSAGE_STATUS_NEW.", ".MESSAGE_STATUS_UNREAD.")
AND m.id > $lastId
ORDER BY m.send_date DESC";
$result = Database::query($sql);
$messages = [];
if ($result !== false) {
while ($row = Database::fetch_assoc($result)) {
$pictureInfo = UserManager::get_user_picture_path_by_id($row['user_id'], 'web');
$row['pictureUri'] = $pictureInfo['dir'].$pictureInfo['file'];
$messages[] = $row;
}
}
return $messages;
}
/**
* Get the data of the last received messages for a user.
*
* @param int $userId The user id
* @param int $lastId The id of the last received message
*
* @return array
*/
public static function getSentMessages($userId, $lastId = 0)
{
$userId = intval($userId);
$lastId = intval($lastId);
if (empty($userId)) {
return [];
}
$messagesTable = Database::get_main_table(TABLE_MESSAGE);
$userTable = Database::get_main_table(TABLE_MAIN_USER);
$sql = "SELECT m.*, u.user_id, u.lastname, u.firstname, u.picture_uri
FROM $messagesTable as m
INNER JOIN $userTable as u
ON m.user_receiver_id = u.user_id
WHERE
m.user_sender_id = $userId
AND m.msg_status = ".MESSAGE_STATUS_OUTBOX."
AND m.id > $lastId
ORDER BY m.send_date DESC";
$result = Database::query($sql);
$messages = [];
if ($result !== false) {
while ($row = Database::fetch_assoc($result)) {
$pictureInfo = UserManager::get_user_picture_path_by_id($row['user_id'], 'web');
$row['pictureUri'] = $pictureInfo['dir'].$pictureInfo['file'];
$messages[] = $row;
}
}
return $messages;
}
/**
* Check whether a message has attachments.
*
@ -2566,10 +2652,8 @@ class MessageManager
/**
* Send a notification to all admins when a new user is registered.
*
* @param User $user
*/
public static function sendNotificationByRegisteredUser(User $user)
public static function sendNotificationOfNewRegisteredUser(User $user)
{
$tplMailBody = new Template(
null,
@ -2610,6 +2694,86 @@ class MessageManager
}
}
/**
* Send a notification to all admins when a new user is registered
* while the approval method is used for users registration.
*/
public static function sendNotificationOfNewRegisteredUserApproval(User $user)
{
$tplMailBody = new Template(
null,
false,
false,
false,
false,
false,
false
);
$tplMailBody->assign('user', $user);
$tplMailBody->assign('is_western_name_order', api_is_western_name_order());
$userId = $user->getId();
$url_edit = Display::url(
api_get_path(WEB_CODE_PATH).'admin/user_edit.php?user_id='.$userId,
api_get_path(WEB_CODE_PATH).'admin/user_edit.php?user_id='.$userId
);
$tplMailBody->assign(
'manageUrl',
$url_edit
);
// Get extra field values for this user and reformat the array
$extraFieldValues = new ExtraFieldValue('user');
$userExtraFields = $extraFieldValues->getAllValuesByItem($userId);
$values = [];
foreach ($userExtraFields as $field => $value) {
$values[$value['variable']] = $value['value'];
}
$tplMailBody->assign(
'extra',
$values
);
$layoutContent = '';
$emailbody = '';
if (api_get_configuration_value('mail_template_system') == true) {
$mailTemplateManager = new MailTemplateManager();
$templateText = $mailTemplateManager->getTemplateByType('new_user_mail_to_admin_approval.tpl');
if (empty($templateText)) {
} else {
// custom procedure to load a template as a string (doesn't use cache so may slow down)
$template = $tplMailBody->twig->createTemplate($templateText);
$emailbody = $template->render($tplMailBody->params);
}
}
if (empty($emailbody)) {
$layoutContent = $tplMailBody->get_template('mail/new_user_mail_to_admin_approval.tpl');
$emailbody = $tplMailBody->fetch($layoutContent);
}
$emailsubject = '['.get_lang('ApprovalForNewAccount').'] '.$user->getUsername();
if (api_get_configuration_value('send_inscription_notification_to_general_admin_only')) {
$email = api_get_setting('emailAdministrator');
$firstname = api_get_setting('administratorSurname');
$lastname = api_get_setting('administratorName');
api_mail_html("$firstname $lastname", $email, $emailsubject, $emailbody);
} else {
$admins = UserManager::get_all_administrators();
foreach ($admins as $admin_info) {
self::send_message(
$admin_info['user_id'],
$emailsubject,
$emailbody,
[],
[],
null,
null,
null,
null,
$userId
);
}
}
}
/**
* Get the error log from failed mailing
* This assumes a complex setup where you have a cron script regularly copying the mail queue log

@ -183,7 +183,8 @@ class SessionManager
? (empty($accessUrlId) ? api_get_current_access_url_id() : (int) $accessUrlId)
: 1;
if (is_array($_configuration[$accessUrlId]) &&
if (isset($_configuration[$accessUrlId]) &&
is_array($_configuration[$accessUrlId]) &&
isset($_configuration[$accessUrlId]['hosting_limit_sessions']) &&
$_configuration[$accessUrlId]['hosting_limit_sessions'] > 0
) {
@ -2420,6 +2421,8 @@ class SessionManager
SET nbr_users = (SELECT count(user_id) FROM $tbl_session_rel_user WHERE session_id = $sessionId)
WHERE id = $sessionId";
Database::query($sql);
return true;
}
/**
@ -3717,9 +3720,9 @@ class SessionManager
}
return $sessions;
} else {
return false;
}
return false;
}
/**
@ -4287,7 +4290,7 @@ class SessionManager
$tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
$tbl_session_rel_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
$session_id = (int) $session_id;
$sqlSelect = '*, c.id, c.id as real_id';
$sqlSelect = '*, c.id, c.id as real_id, c.code as course_code';
if ($getCount) {
$sqlSelect = 'COUNT(1) as count';
@ -4764,27 +4767,34 @@ class SessionManager
/**
* Copies a session with the same data to a new session.
* The new copy is not assigned to the same promotion. @see subscribe_sessions_to_promotions() for that.
* The new copy is not assigned to the same promotion.
*
* @param int Session ID
* @param bool Whether to copy the relationship with courses
* @param bool Whether to copy the relationship with users
* @param bool New courses will be created
* @param bool Whether to set exercises and learning paths in the new session to invisible by default
* @param int $id Session ID
* @param bool $copy_courses Whether to copy the relationship with courses
* @param bool $copyTeachersAndDrh
* @param bool $create_new_courses New courses will be created
* @param bool $set_exercises_lp_invisible Set exercises and LPs in the new session to invisible by default
*
* @return int The new session ID on success, 0 otherwise
*
* @see subscribe_sessions_to_promotions() for that.
*
* @todo make sure the extra session fields are copied too
*/
public static function copy(
$id,
$copy_courses = true,
$copy_users = true,
$copyTeachersAndDrh = true,
$create_new_courses = false,
$set_exercises_lp_invisible = false
) {
$id = intval($id);
$id = (int) $id;
$s = self::fetch($id);
if (empty($s)) {
return false;
}
// Check all dates before copying
// Get timestamp for now in UTC - see http://php.net/manual/es/function.time.php#117251
$now = time() - date('Z');
@ -4809,6 +4819,24 @@ class SessionManager
if (api_strtotime($s['coach_access_end_date']) < $now) {
$s['coach_access_end_date'] = $inOneMonth;
}
// Now try to create the session
$extraFieldValue = new ExtraFieldValue('session');
$extraFieldsValues = $extraFieldValue->getAllValuesByItem($id);
$extraFieldsValuesToCopy = [];
if (!empty($extraFieldsValues)) {
foreach ($extraFieldsValues as $extraFieldValue) {
//$extraFieldsValuesToCopy['extra_'.$extraFieldValue['variable']] = $extraFieldValue['value'];
$extraFieldsValuesToCopy['extra_'.$extraFieldValue['variable']]['extra_'.$extraFieldValue['variable']] = $extraFieldValue['value'];
}
}
if (isset($extraFieldsValuesToCopy['extra_image']) && isset($extraFieldsValuesToCopy['extra_image']['extra_image'])) {
$extraFieldsValuesToCopy['extra_image'] = [
'tmp_name' => api_get_path(SYS_UPLOAD_PATH).$extraFieldsValuesToCopy['extra_image']['extra_image'],
'error' => 0,
];
}
// Now try to create the session
$sid = self::create_session(
$s['name'].' '.get_lang('CopyLabelSuffix'),
@ -4821,7 +4849,11 @@ class SessionManager
(int) $s['id_coach'],
$s['session_category_id'],
(int) $s['visibility'],
true
true,
$s['duration'],
$s['description'],
$s['show_description'],
$extraFieldsValuesToCopy
);
if (!is_numeric($sid) || empty($sid)) {
@ -4831,7 +4863,6 @@ class SessionManager
if ($copy_courses) {
// Register courses from the original session to the new session
$courses = self::get_course_list_by_session_id($id);
$short_courses = $new_short_courses = [];
if (is_array($courses) && count($courses) > 0) {
foreach ($courses as $course) {
@ -4839,7 +4870,6 @@ class SessionManager
}
}
$courses = null;
// We will copy the current courses of the session to new courses
if (!empty($short_courses)) {
if ($create_new_courses) {
@ -4897,27 +4927,50 @@ class SessionManager
$short_courses = $new_short_courses;
self::add_courses_to_session($sid, $short_courses, true);
$short_courses = null;
if ($create_new_courses === false && $copyTeachersAndDrh) {
foreach ($short_courses as $courseItemId) {
$coachList = self::getCoachesByCourseSession($id, $courseItemId);
foreach ($coachList as $userId) {
self::set_coach_to_course_session($userId, $sid, $courseItemId);
}
}
}
}
}
if ($copy_users) {
if ($copyTeachersAndDrh) {
// Register users from the original session to the new session
$users = self::get_users_by_session($id);
$short_users = [];
if (is_array($users) && count($users) > 0) {
foreach ($users as $user) {
$short_users[] = $user['user_id'];
if (!empty($users)) {
$userListByStatus = [];
foreach ($users as $userData) {
$userData['relation_type'] = (int) $userData['relation_type'];
$userListByStatus[$userData['relation_type']][] = $userData;
}
}
$users = null;
//Subscribing in read only mode
self::subscribeUsersToSession(
foreach ($userListByStatus as $status => $userList) {
$userList = array_column($userList, 'user_id');
switch ($status) {
case 0:
/*self::subscribeUsersToSession(
$sid,
$short_users,
$userList,
SESSION_VISIBLE_READ_ONLY,
false,
true
);
$short_users = null;
);*/
break;
case 1:
// drh users
foreach ($userList as $drhId) {
$userInfo = api_get_user_info($drhId);
self::subscribeSessionsToDrh($userInfo, [$sid], false, false);
}
break;
}
}
}
}
return $sid;
@ -4948,16 +5001,17 @@ class SessionManager
/**
* Get the number of sessions.
*
* @param int ID of the URL we want to filter on (optional)
* @param int $access_url_id ID of the URL we want to filter on (optional)
*
* @return int Number of sessions
*/
public static function count_sessions($access_url_id = null)
public static function count_sessions($access_url_id = 0)
{
$session_table = Database::get_main_table(TABLE_MAIN_SESSION);
$access_url_rel_session_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
$access_url_id = (int) $access_url_id;
$sql = "SELECT count(s.id) FROM $session_table s";
if (!empty($access_url_id) && $access_url_id == intval($access_url_id)) {
if (!empty($access_url_id)) {
$sql .= ", $access_url_rel_session_table u ".
" WHERE s.id = u.session_id AND u.access_url_id = $access_url_id";
}
@ -5658,9 +5712,30 @@ SQL;
// Adding the relationship "Session - User" for students
$userList = [];
if (is_array($users)) {
$extraFieldValueCareer = new ExtraFieldValue('career');
$careerList = isset($enreg['extra_careerid']) && !empty($enreg['extra_careerid']) ? $enreg['extra_careerid'] : [];
$careerList = str_replace(['[', ']'], '', $careerList);
$careerList = explode(',', $careerList);
$finalCareerIdList = [];
foreach ($careerList as $careerId) {
$realCareerIdList = $extraFieldValueCareer->get_item_id_from_field_variable_and_field_value(
'external_career_id',
$careerId
);
if (isset($realCareerIdList['item_id'])) {
$finalCareerIdList[] = $realCareerIdList['item_id'];
}
}
foreach ($users as $user) {
$user_id = UserManager::get_user_id_from_username($user);
if ($user_id !== false) {
if (!empty($finalCareerIdList)) {
foreach ($finalCareerIdList as $careerId) {
UserManager::addUserCareer($user_id, $careerId);
}
}
$userList[] = $user_id;
// Insert new users.
$sql = "INSERT IGNORE INTO $tbl_session_user SET
@ -7111,7 +7186,6 @@ SQL;
* Returns the number of days the student has left in a session when using
* sessions durations.
*
* @param array $sessionInfo
* @param int $userId
*
* @return int
@ -7154,9 +7228,9 @@ SQL;
*/
public static function editUserSessionDuration($duration, $userId, $sessionId)
{
$duration = intval($duration);
$userId = intval($userId);
$sessionId = intval($sessionId);
$duration = (int) $duration;
$userId = (int) $userId;
$sessionId = (int) $sessionId;
if (empty($userId) || empty($sessionId)) {
return false;
@ -7210,8 +7284,8 @@ SQL;
public static function isUserSubscribedAsStudent($sessionId, $userId)
{
$sessionRelUserTable = Database::get_main_table(TABLE_MAIN_SESSION_USER);
$sessionId = intval($sessionId);
$userId = intval($userId);
$sessionId = (int) $sessionId;
$userId = (int) $userId;
// COUNT(1) actually returns the number of rows from the table (as if
// counting the results from the first column)
@ -7242,8 +7316,8 @@ SQL;
{
$sessionRelUserTable = Database::get_main_table(TABLE_MAIN_SESSION_USER);
$sessionId = intval($sessionId);
$userId = intval($userId);
$sessionId = (int) $sessionId;
$userId = (int) $userId;
// COUNT(1) actually returns the number of rows from the table (as if
// counting the results from the first column)
@ -7859,6 +7933,10 @@ SQL;
"variable IN ( ".implode(", ", $variablePlaceHolders)." ) " => $variables,
]);
if (empty($fieldList)) {
return [];
}
$fields = [];
// Index session fields
@ -8030,7 +8108,6 @@ SQL;
}
/**
* @param FormValidator $form
* @param array $sessionInfo Optional
*
* @return array
@ -8954,7 +9031,7 @@ SQL;
$limit = '';
if (!empty($options['limit'])) {
$limit = " LIMIT ".$options['limit'];
$limit = ' LIMIT '.$options['limit'];
}
$query = "$select FROM $tbl_session s
@ -9002,10 +9079,10 @@ SQL;
}
}
$query .= ") AS session_table";
$query .= ') AS s';
if (!empty($options['order'])) {
$query .= " ORDER BY ".$options['order'];
$query .= ' ORDER BY '.$options['order'];
}
$result = Database::query($query);
@ -9453,9 +9530,6 @@ SQL;
}
/**
* @param Course $course
* @param Session $session
*
* @return int
*/
public static function getCountUsersInCourseSession(
@ -9485,9 +9559,6 @@ SQL;
/**
* Get course IDs where user in not subscribed in session.
*
* @param User $user
* @param Session $session
*
* @return array
*/
public static function getAvoidedCoursesInSession(User $user, Session $session)
@ -9528,6 +9599,7 @@ SQL;
}
$userRelSession = self::getUserSession($userId, $sessionId);
if ($userRelSession) {
if (isset($userRelSession['collapsed']) && $userRelSession['collapsed'] != '') {
$collapsed = $userRelSession['collapsed'];

@ -629,8 +629,6 @@ class SkillRelUser extends Model
/**
* Get the URL for the issue.
*
* @param SkillRelUserEntity $skillIssue
*
* @return string
*/
public static function getIssueUrl(SkillRelUserEntity $skillIssue)
@ -641,8 +639,6 @@ class SkillRelUser extends Model
/**
* Get the URL for the All issues page.
*
* @param SkillRelUserEntity $skillIssue
*
* @return string
*/
public static function getIssueUrlAll(SkillRelUserEntity $skillIssue)
@ -653,8 +649,6 @@ class SkillRelUser extends Model
/**
* Get the URL for the assertion.
*
* @param SkillRelUserEntity $skillIssue
*
* @return string
*/
public static function getAssertionUrl(SkillRelUserEntity $skillIssue)
@ -1344,7 +1338,6 @@ class Skill extends Model
}
/**
* @param Vertex $vertex
* @param array $skills
* @param int $level
*
@ -2379,7 +2372,6 @@ class Skill extends Model
}
/**
* @param FormValidator $form
* @param array $skillInfo
*
* @return array
@ -2519,7 +2511,6 @@ class Skill extends Model
/**
* Assign a user with a SkilRelItem object.
*
* @param FormValidator $form
* @param int $typeId see ITEM_TYPE_* constants
* @param int $itemId
* @param int $userId
@ -2595,7 +2586,6 @@ class Skill extends Model
/**
* Add skills select ajax for an item (exercise, lp).
*
* @param FormValidator $form
* @param int $typeId see ITEM_TYPE_* constants
* @param int $itemId
*
@ -2874,8 +2864,6 @@ class Skill extends Model
/**
* Relate skill with an item (exercise, gradebook, lp, etc).
*
* @param FormValidator $form
*
* @return bool
*/
public static function saveSkillsToCourseFromForm(FormValidator $form)
@ -2959,7 +2947,6 @@ class Skill extends Model
/**
* Get the icon (badge image) URL.
*
* @param SkillEntity $skill
* @param bool $getSmall Optional. Allow get the small image
*
* @return string
@ -3008,7 +2995,7 @@ class Skill extends Model
}
$skillLevelRepo = $entityManager->getRepository('ChamiloSkillBundle:Level');
$skillUser = new \Chamilo\CoreBundle\Entity\SkillRelUser();
$skillUser = new SkillRelUserEntity();
$skillUser->setUser($user);
$skillUser->setSkill($skill);

@ -342,6 +342,13 @@ class SortableTable extends HTML_Table
echo $this->return_table();
}
public function toArray()
{
$headers = array_column($this->getHeaders(), 'label');
return array_merge([$headers], $this->table_data);
}
/**
* Displays the table, complete with navigation buttons to browse through
* the data-pages.
@ -350,7 +357,6 @@ class SortableTable extends HTML_Table
{
$empty_table = false;
$content = $this->get_table_html();
if ($this->get_total_number_of_items() == 0) {
$cols = $this->getColCount();
$this->setCellAttributes(
@ -362,7 +368,6 @@ class SortableTable extends HTML_Table
$this->setCellContents(1, 0, $message_empty);
$empty_table = true;
}
$html = '';
$params = $this->get_sortable_table_param_string().'&amp;'.$this->get_additional_url_paramstring();
@ -453,6 +458,7 @@ class SortableTable extends HTML_Table
$html .= '<td> ';
$html .= '</td>';
}
$html .= '</tr>';
$html .= '</table>';
@ -789,7 +795,6 @@ class SortableTable extends HTML_Table
}
$result[] = '<option value="'.$nr.'" '.($nr == $this->per_page ? 'selected="selected"' : '').'>'.$nr.'</option>';
}
// @todo no limits
//if ($total_number_of_items < 500) {
$result[] = '<option value="'.$total_number_of_items.'" '.($total_number_of_items == $this->per_page ? 'selected="selected"' : '').'>'.api_ucfirst(get_lang('All')).'</option>';
//}

@ -1,4 +1,5 @@
<?php
/* For licensing terms, see /license.txt */
/**
@ -334,6 +335,8 @@ class SystemAnnouncementManager
* @param int $send_mail Whether to send an e-mail to all users (1) or not (0)
* @param bool $add_to_calendar
* @param bool $sendEmailTest
* @param int $careerId
* @param int $promotionId
*
* @return mixed insert_id on success, false on failure
*/
@ -346,7 +349,9 @@ class SystemAnnouncementManager
$lang = '',
$send_mail = 0,
$add_to_calendar = false,
$sendEmailTest = false
$sendEmailTest = false,
$careerId = 0,
$promotionId = 0
) {
$original_content = $content;
$a_dateS = explode(' ', $date_start);
@ -421,6 +426,11 @@ class SystemAnnouncementManager
'access_url_id' => $current_access_url_id,
];
if (api_get_configuration_value('allow_careers_in_global_announcements') && !empty($careerId)) {
$params['career_id'] = (int) $careerId;
$params['promotion_id'] = (int) $promotionId;
}
foreach ($visibility as $key => $value) {
$params[$key] = $value;
}
@ -430,19 +440,15 @@ class SystemAnnouncementManager
if ($resultId) {
if ($sendEmailTest) {
self::send_system_announcement_by_email(
$title,
$content,
$resultId,
$visibility,
$lang,
true
);
} else {
if ($send_mail == 1) {
self::send_system_announcement_by_email(
$title,
$content,
$visibility,
$lang
$resultId,
$visibility
);
}
}
@ -539,6 +545,8 @@ class SystemAnnouncementManager
* @param array $lang
* @param int $send_mail
* @param bool $sendEmailTest
* @param int $careerId
* @param int $promotionId
*
* @return bool True on success, false on failure
*/
@ -551,7 +559,9 @@ class SystemAnnouncementManager
$visibility,
$lang = null,
$send_mail = 0,
$sendEmailTest = false
$sendEmailTest = false,
$careerId = 0,
$promotionId = 0
) {
$em = Database::getManager();
$announcement = $em->find('ChamiloCoreBundle:SysAnnouncement', $id);
@ -610,26 +620,6 @@ class SystemAnnouncementManager
$content
);
if ($sendEmailTest) {
self::send_system_announcement_by_email(
$title,
$content,
null,
null,
$lang,
$sendEmailTest
);
} else {
if ($send_mail == 1) {
self::send_system_announcement_by_email(
$title,
$content,
$visibility,
$lang
);
}
}
$dateStart = new DateTime($start, new DateTimeZone('UTC'));
$dateEnd = new DateTime($end, new DateTimeZone('UTC'));
@ -650,12 +640,39 @@ class SystemAnnouncementManager
// Update visibility
$list = self::getVisibilityList();
$table = Database::get_main_table(TABLE_MAIN_SYSTEM_ANNOUNCEMENTS);
if (api_get_configuration_value('allow_careers_in_global_announcements') && !empty($careerId)) {
$params = [];
$params['career_id'] = (int) $careerId;
$params['promotion_id'] = (int) $promotionId;
Database::update(
$table,
$params,
['id = ? ' => $id]
);
}
foreach ($list as $key => $title) {
$value = isset($visibility[$key]) && $visibility[$key] ? 1 : 0;
$sql = "UPDATE $table SET $key = '$value' WHERE id = $id";
Database::query($sql);
}
if ($sendEmailTest) {
self::send_system_announcement_by_email(
$id,
$visibility,
true
);
} else {
if ($send_mail == 1) {
self::send_system_announcement_by_email(
$id,
$visibility
);
}
}
return true;
}
@ -669,7 +686,7 @@ class SystemAnnouncementManager
public static function delete_announcement($id)
{
$table = Database::get_main_table(TABLE_MAIN_SYSTEM_ANNOUNCEMENTS);
$id = intval($id);
$id = (int) $id;
$sql = "DELETE FROM $table WHERE id =".$id;
$res = Database::query($sql);
if ($res === false) {
@ -689,7 +706,7 @@ class SystemAnnouncementManager
public static function get_announcement($id)
{
$table = Database::get_main_table(TABLE_MAIN_SYSTEM_ANNOUNCEMENTS);
$id = intval($id);
$id = (int) $id;
$sql = "SELECT * FROM ".$table." WHERE id = ".$id;
$announcement = Database::fetch_object(Database::query($sql));
@ -731,22 +748,28 @@ class SystemAnnouncementManager
/**
* Send a system announcement by e-mail to all teachers/students depending on parameters.
*
* @param string $title
* @param string $content
* @param int $id
* @param array $visibility
* @param string $language Language (optional, considered for all languages if left empty)
* @param bool $sendEmailTest
*
* @return bool True if the message was sent or there was no destination matching.
* False on database or e-mail sending error.
*/
public static function send_system_announcement_by_email(
$title,
$content,
$id,
$visibility,
$language = null,
$sendEmailTest = false
) {
$announcement = self::get_announcement($id);
if (empty($announcement)) {
return false;
}
$title = $announcement->title;
$content = $announcement->content;
$language = $announcement->lang;
$content = str_replace(['\r\n', '\n', '\r'], '', $content);
$now = api_get_utc_datetime();
$teacher = $visibility['visible_teacher'];
@ -797,6 +820,29 @@ class SystemAnnouncementManager
// Expiration date
$sql .= " AND (expiration_date = '' OR expiration_date IS NULL OR expiration_date > '$now') ";
// @todo check if other filters will apply for the career/promotion option.
if (isset($announcement->career_id) && !empty($announcement->career_id)) {
$promotion = new Promotion();
$promotionList = $promotion->get_all_promotions_by_career_id($announcement->career_id);
if (isset($announcement->promotion_id) && !empty($announcement->promotion_id)) {
$promotionList = [];
$promotionList[] = $promotion->get($announcement->promotion_id);
}
if (!empty($promotionList)) {
foreach ($promotionList as $promotion) {
$sessionList = SessionManager::get_all_sessions_by_promotion($promotion['id']);
foreach ($sessionList as $session) {
$users = SessionManager::get_users_by_session($session['id'], 0);
foreach ($users as $user) {
MessageManager::send_message_simple($user['user_id'], $title, $content);
}
}
}
}
return true;
}
if ((empty($teacher) || $teacher == '0') && (empty($student) || $student == '0')) {
return true;
}

@ -349,9 +349,18 @@ class UserGroup extends Model
{
// action links
echo '<div class="actions">';
echo '<a href="../admin/usergroups.php">'.
Display::return_icon('back.png', get_lang('BackTo').' '.get_lang('PlatformAdmin'), '', '32').
'</a>';
$courseInfo = api_get_course_info();
if (empty($courseInfo)) {
echo '<a href="../admin/usergroups.php">'.
Display::return_icon('back.png', get_lang('BackTo').' '.get_lang('PlatformAdmin'), '', '32').
'</a>';
} else {
echo Display::url(
Display::return_icon('back.png', get_lang('BackTo').' '.get_lang('PlatformAdmin'), '', '32'),
api_get_path(WEB_CODE_PATH).'user/class.php?'.api_get_cidreq()
);
}
echo '</div>';
echo Display::grid_html('usergroups');
}

@ -3741,7 +3741,8 @@ class UserManager
// The session course list doesn't have any position,
// then order the course list by course code
$list = array_column($myCourseList, 'course_code');
array_multisort($myCourseList, SORT_ASC, $list);
@array_multisort($myCourseList, SORT_ASC, $list);
}
}

@ -34,6 +34,15 @@ use Symfony\Component\Finder\Finder;
class learnpath
{
const MAX_LP_ITEM_TITLE_LENGTH = 32;
const STATUS_CSS_CLASS_NAME = [
'not attempted' => 'scorm_not_attempted',
'incomplete' => 'scorm_not_attempted',
'failed' => 'scorm_failed',
'completed' => 'scorm_completed',
'passed' => 'scorm_completed',
'succeeded' => 'scorm_completed',
'browsed' => 'scorm_completed',
];
public $attempt = 0; // The number for the current ID view.
public $cc; // Course (code) this learnpath is located in. @todo change name for something more comprensible ...
@ -253,11 +262,6 @@ class learnpath
ORDER BY parent_item_id, display_order";
$res = Database::query($sql);
if ($debug) {
error_log('learnpath::__construct() '.__LINE__.' - query lp items: '.$sql);
error_log('-- Start while--');
}
$lp_item_id_list = [];
while ($row = Database::fetch_array($res)) {
$lp_item_id_list[] = $row['iid'];
@ -342,10 +346,6 @@ class learnpath
}
}
if ($debug) {
error_log('learnpath::__construct() '.__LINE__.' ----- end while ----');
}
if (!empty($lp_item_id_list)) {
$lp_item_id_list_to_string = implode("','", $lp_item_id_list);
if (!empty($lp_item_id_list_to_string)) {
@ -359,14 +359,6 @@ class learnpath
lp_view_id = ".$this->get_view_id()." AND
lp_item_id IN ('".$lp_item_id_list_to_string."')
ORDER BY view_count DESC ";
if ($debug) {
error_log(
'learnpath::__construct() - Selecting item_views: '.$sql,
0
);
}
$status_list = [];
$res = Database::query($sql);
while ($row = Database:: fetch_array($res)) {
@ -503,9 +495,6 @@ class learnpath
$userId = 0
) {
$course_id = $this->course_info['real_id'];
if ($this->debug > 0) {
error_log('In learnpath::add_item('.$parent.','.$previous.','.$type.','.$id.','.$title.')');
}
if (empty($course_id)) {
// Sometimes Oogie doesn't catch the course info but sets $this->cc
$this->course_info = api_get_course_info($this->cc);
@ -527,7 +516,7 @@ class learnpath
WHERE
c_id = $course_id AND
lp_id = ".$this->get_id()." AND
parent_item_id = ".$parent;
parent_item_id = $parent ";
$res_count = Database::query($sql);
$row = Database::fetch_array($res_count);
@ -618,9 +607,6 @@ class learnpath
$new_item_id = Database::insert($tbl_lp_item, $params);
if ($new_item_id) {
if ($this->debug > 2) {
error_log('Inserting dir/chapter: '.$new_item_id, 0);
}
$sql = "UPDATE $tbl_lp_item SET id = iid WHERE iid = $new_item_id";
Database::query($sql);
@ -912,10 +898,6 @@ class learnpath
{
$debug = $this->debug;
if ($debug) {
error_log('Learnpath::autocomplete_parents()');
}
if (empty($item)) {
$item = $this->current;
}
@ -1028,9 +1010,6 @@ class learnpath
*/
public function close()
{
if ($this->debug > 0) {
error_log('In learnpath::close()', 0);
}
if (empty($this->lp_id)) {
$this->error = 'Trying to close this learnpath but no ID is set';
@ -1177,21 +1156,20 @@ class learnpath
public function delete_children_items($id)
{
$course_id = $this->course_info['real_id'];
if ($this->debug > 0) {
error_log('In learnpath::delete_children_items('.$id.')', 0);
}
$num = 0;
if (empty($id) || $id != strval(intval($id))) {
$id = (int) $id;
if (empty($id) || empty($course_id)) {
return false;
}
$lp_item = Database::get_course_table(TABLE_LP_ITEM);
$sql = "SELECT * FROM $lp_item
WHERE c_id = ".$course_id." AND parent_item_id = $id";
WHERE c_id = $course_id AND parent_item_id = $id";
$res = Database::query($sql);
while ($row = Database::fetch_array($res)) {
$num += $this->delete_children_items($row['iid']);
$sql = "DELETE FROM $lp_item
WHERE c_id = ".$course_id." AND iid = ".$row['iid'];
WHERE c_id = $course_id AND iid = ".$row['iid'];
Database::query($sql);
$num++;
}
@ -1211,11 +1189,9 @@ class learnpath
public function delete_item($id)
{
$course_id = api_get_course_int_id();
if ($this->debug > 0) {
error_log('In learnpath::delete_item()', 0);
}
$id = (int) $id;
// TODO: Implement the resource removal.
if (empty($id) || $id != strval(intval($id))) {
if (empty($id) || empty($course_id)) {
return false;
}
// First select item to get previous, next, and display order.
@ -1232,15 +1208,9 @@ class learnpath
$parent = $row['parent_item_id'];
$lp = $row['lp_id'];
// Delete children items.
$num = $this->delete_children_items($id);
if ($this->debug > 2) {
error_log('learnpath::delete_item() - deleted '.$num.' children of element '.$id, 0);
}
$this->delete_children_items($id);
// Now delete the item.
$sql_del = "DELETE FROM $lp_item WHERE iid = $id";
if ($this->debug > 2) {
error_log('Deleting item: '.$sql_del, 0);
}
Database::query($sql_del);
// Now update surrounding items.
$sql_upd = "UPDATE $lp_item SET next_item_id = $next
@ -1559,10 +1529,6 @@ class learnpath
$minScore = 0,
$maxScore = 100
) {
if ($this->debug > 0) {
error_log('In learnpath::edit_item_prereq('.$id.','.$prerequisite_id.','.$minScore.','.$maxScore.')', 0);
}
$id = (int) $id;
$prerequisite_id = (int) $prerequisite_id;

@ -1,11 +1,10 @@
<?php
/* For licensing terms, see /license.txt */
/**
* This is the tracking library for Chamilo.
*
* @package chamilo.reporting
*
* Calculates the time spent on the course
*
* @param int $user_id the user id
@ -31,7 +30,7 @@ if (!$is_allowedToTrack) {
$this_section = SECTION_TRACKING;
$user_id = isset($_REQUEST['student']) ? (int) $_REQUEST['student'] : 0;
$session_id = (int) $_GET['id_session'];
$session_id = isset($_REQUEST['id_session']) ? (int) $_REQUEST['id_session'] : 0;
$type = isset($_REQUEST['type']) ? Security::remove_XSS($_REQUEST['type']) : '';
$course_code = isset($_REQUEST['course']) ? Security::remove_XSS($_REQUEST['course']) : '';
$courseInfo = api_get_course_info($course_code);
@ -93,13 +92,23 @@ function loadGraph() {
var startDate = $('#date_from').val();
var endDate = $('#date_to').val();
var type = $('#type option:selected').val();
var url = '".$url."&startDate='+startDate+'&endDate='+endDate+'&type='+type;
$.ajax({
url: '".$url."&startDate='+startDate+'&endDate='+endDate+'&type='+type,
url: url,
dataType: 'json',
success: function(db) {
if (!db.is_empty) {
// Display confirmation message to the user
$('#messages').html(db.result).stop().css('opacity', 1).fadeIn(30);
var exportLink = $('<a></a>').
attr(\"href\", url+'&export=excel')
.attr('class', 'btn btn-default')
.attr('target', '_blank')
.html('".addslashes(get_lang('ExportAsXLS'))."');
$('#messages').append(exportLink);
$('#cev_cont_stats').html(db.stats);
$('#graph' ).html(db.graph_result);
} else {
@ -118,17 +127,12 @@ $(function() {
changeMonth: true,
changeYear: true
});
$(\"#cev_button\").hide();
});
</script>";
$htmlHeadXtra[] = '<script>
$(function() {
$("#cev_button").hide();
$("#container-9").tabs({remote: true});
});
</script>';
$interbreadcrumb[] = ['url' => '#', 'name' => get_lang('AccessDetails')];
Display::display_header('');
@ -157,12 +161,12 @@ $form->display();
</div><br />
<div id="cev_cont_stats">
<?php
if ($result_to_print != '') {
$rst = get_stats($user_id, $courseInfo, $session_id);
$foo_stats = '<strong>'.get_lang('Total').': </strong>'.$rst['total'].'<br />';
$foo_stats .= '<strong>'.get_lang('Average').': </strong>'.$rst['avg'].'<br />';
$foo_stats .= '<strong>'.get_lang('Quantity').' : </strong>'.$rst['times'].'<br />';
echo $foo_stats;
$data = MySpace::getStats($user_id, $courseInfo, $session_id);
if (!empty($data)) {
$stats = '<strong>'.get_lang('Total').': </strong>'.$data['total'].'<br />';
$stats .= '<strong>'.get_lang('Average').': </strong>'.$data['avg'].'<br />';
$stats .= '<strong>'.get_lang('Quantity').' : </strong>'.$data['times'].'<br />';
echo $stats;
} else {
echo Display::return_message(get_lang('NoDataAvailable'), 'warning');
}

@ -238,6 +238,5 @@ $template->assign('sequences', $sessionRequirements);
$template->assign('is_premium', $sessionIsPremium);
$layout = $template->get_template('session/about.tpl');
$content = $template->fetch($layout);
//$template->assign('header', $session->getName());
$template->assign('content', $content);
$template->display_one_col_template();

@ -22,13 +22,10 @@ SessionManager::protectSession($id_session);
// setting breadcrumbs
$interbreadcrumb[] = ['url' => 'session_list.php', 'name' => get_lang('SessionList')];
$interbreadcrumb[] = [
'url' => "resume_session.php?id_session=".$id_session,
"name" => get_lang('SessionOverview'),
'url' => 'resume_session.php?id_session='.$id_session,
'name' => get_lang('SessionOverview'),
];
// Database Table Definitions
$tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
$tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
$tbl_user = Database::get_main_table(TABLE_MAIN_USER);
$tbl_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
@ -320,8 +317,6 @@ $UserList = $SessionList = [];
$sessions = [];
if (isset($_POST['form_sent']) && $_POST['form_sent']) {
$form_sent = $_POST['form_sent'];
$firstLetterUser = isset($_POST['firstLetterUser']) ? $_POST['firstLetterUser'] : '';
$firstLetterSession = isset($_POST['firstLetterSession']) ? $_POST['firstLetterSession'] : '';
$UserList = isset($_POST['sessionUsersList']) ? $_POST['sessionUsersList'] : [];
if (!is_array($UserList)) {

@ -122,8 +122,6 @@ echo $form->returnForm();
Display::display_footer();
/**
* @param Session $session
*
* @return array
*/
function getSessionCourseList(Session $session)

@ -1,11 +1,10 @@
<?php
/* For licensing terms, see /license.txt */
use ChamiloSession as Session;
/**
* @package chamilo.social
*
* @author Julio Montoya <gugli100@gmail.com>
* @autor Alex Aragon <alex.aragon@beeznest.com> CSS Design and Template
*/
@ -65,10 +64,10 @@ if (api_get_setting('profile', 'picture') == 'true') {
)) {
$table_user = Database::get_main_table(TABLE_MAIN_USER);
$sql = "UPDATE $table_user
SET
picture_uri = '$new_picture'
WHERE user_id = ".api_get_user_id();
$result = Database::query($sql);
SET
picture_uri = '$new_picture'
WHERE user_id = ".$user_id;
Database::query($sql);
}
}
}

@ -41,7 +41,7 @@ SocialManager::handlePosts(api_get_self().'?u='.$friendId);
if (isset($_GET['u'])) {
//I'm your friend? I can see your profile?
$user_id = intval($_GET['u']);
$user_id = (int) $_GET['u'];
if (api_is_anonymous($user_id, true)) {
api_not_allowed(true);
}

@ -2,7 +2,7 @@
{% block body %}
<script>
$(document).ready(function () {
$(function () {
$('#date').datepicker({
dateFormat: 'yy-mm-dd'
});

@ -31,13 +31,10 @@
function main(container)
{
// Checks if the browser is supported
if (!mxClient.isBrowserSupported())
{
if (!mxClient.isBrowserSupported()) {
// Displays an error message if the browser is not supported.
mxUtils.error('Browser is not supported!', 200, false);
}
else
{
} else {
// Disables the built-in context menu
mxEvent.disableContextMenu(container);
@ -50,8 +47,7 @@
graph.setEnabled(false);
// Enables connect preview for the default edge style
graph.connectionHandler.createEdgeState = function(me)
{
graph.connectionHandler.createEdgeState = function(me) {
var edge = graph.createEdge(null, null, null, null, null);
return new mxCellState(this.graph.view, edge, this.graph.getCellStyle(edge));

@ -635,6 +635,8 @@ if ($export_csv) {
if (empty($sessionId)) {
$csv_headers[] = get_lang('Survey');
} else {
$csv_headers[] = get_lang('RegistrationDate');
}
$csv_headers[] = get_lang('FirstLoginInCourse');
@ -653,7 +655,6 @@ if ($export_csv) {
array_unshift($csvContentInSession, $csv_headers);
if ($sessionId) {
$sessionData = [];
$sessionInfo = api_get_session_info($sessionId);
$sessionDates = SessionManager::parseSessionDates($sessionInfo);

@ -41,6 +41,8 @@ $(function() {
$actionsLeft = '';
$actionsRight = '';
$usergroup = new UserGroup();
$actions = '';
if (api_is_allowed_to_edit()) {
if ($type === 'registered') {
$actionsLeft .= '<a href="class.php?'.api_get_cidreq().'&type=not_registered">'.
@ -51,8 +53,8 @@ if (api_is_allowed_to_edit()) {
$form = new FormValidator(
'groups',
'post',
api_get_self(),
'get',
api_get_self().'?type='.$type,
'',
[],
FormValidator::LAYOUT_INLINE
@ -66,15 +68,18 @@ if (api_is_allowed_to_edit()) {
'group_filter',
get_lang('Groups'),
$options,
['id' => 'group_filter']
['id' => 'group_filter', 'disable_js' => 'disable_js']
);
$form->addHidden('type', $type);
$form->addText('keyword', '', false);
$form->setDefaults(['group_filter' => $groupFilter]);
$actionsRight = $form->returnForm();
$form->addCourseHiddenParams();
$form->addButtonSearch(get_lang('SearchButton'));
$actionsRight .= $form->returnForm();
}
$actions = Display::toolbarAction('actions-class', [$actionsLeft, $actionsRight]);
}
if (api_is_allowed_to_edit()) {
$actions = Display::toolbarAction('actions-class', [$actionsLeft, $actionsRight]);
$action = isset($_GET['action']) ? $_GET['action'] : null;
switch ($action) {
case 'add_class_to_course':
@ -104,7 +109,7 @@ if (api_is_allowed_to_edit()) {
}
// jqgrid will use this URL to do the selects
$url = api_get_path(WEB_AJAX_PATH).'model.ajax.php?a=get_usergroups_teacher&type='.$type.'&group_filter='.$groupFilter;
$url = api_get_path(WEB_AJAX_PATH).'model.ajax.php?a=get_usergroups_teacher&type='.$type.'&group_filter='.$groupFilter.'&keyword='.$keyword;
// The order is important you need to check the the $column variable in the model.ajax.php file
$columns = [
@ -177,5 +182,6 @@ $(function() {
echo $actions;
echo UserManager::getUserSubscriptionTab(4);
echo Display::return_message(get_lang('UserClassExplanation'));
$usergroup->display_teacher_view();
Display::display_footer();

@ -55,29 +55,18 @@ api_protect_course_script();
api_block_anonymous_users();
api_protect_course_group(GroupManager::GROUP_TOOL_WIKI);
/* TRACKING */
Event::event_access_tool(TOOL_WIKI);
if ($groupId) {
$group_properties = GroupManager::get_group_properties($groupId);
$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').' '.Security::remove_XSS($group_properties['name']),
'url' => api_get_path(WEB_CODE_PATH).'group/group_space.php?'.api_get_cidreq(),
'name' => get_lang('GroupSpace').' '.Security::remove_XSS($group_properties['name']),
];
//ensure this tool in groups whe it's private or deactivated
if ($group_properties['wiki_state'] == 0) {
api_not_allowed();
} elseif ($group_properties['wiki_state'] == 2) {
if (!api_is_allowed_to_edit(false, true) and
!GroupManager :: is_user_in_group(api_get_user_id(), $group_properties)
) {
api_not_allowed();
}
}
}
$is_allowed_to_edit = api_is_allowed_to_edit(false, true);

@ -4897,7 +4897,6 @@ class Wiki
if (api_is_allowed_to_edit(false, true) || api_is_platform_admin()) {
// only by professors if page is hidden
//only by professors if page is hidden
$sql = "SELECT * FROM ".$tbl_wiki." s1
WHERE s1.c_id = $course_id AND linksto LIKE '%".Database::escape_string(
$page

Loading…
Cancel
Save