This commit is contained in:
Xes
2025-08-14 22:37:50 +02:00
parent fb6d5d5926
commit 3641e93527
9156 changed files with 1813532 additions and 0 deletions

1
main/inc/ajax/.htaccess Normal file
View File

@@ -0,0 +1 @@
Options -Indexes

BIN
main/inc/ajax/Wami.swf Normal file

Binary file not shown.

View File

@@ -0,0 +1,272 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CoreBundle\Entity\BranchSync;
use Chamilo\CoreBundle\Entity\Repository\BranchSyncRepository;
use GuzzleHttp\Client;
/**
* Responses to AJAX calls.
*/
require_once __DIR__.'/../global.inc.php';
api_protect_admin_script();
$action = isset($_REQUEST['a']) ? $_REQUEST['a'] : null;
switch ($action) {
case 'update_changeable_setting':
$url_id = api_get_current_access_url_id();
if (api_is_global_platform_admin() && $url_id == 1) {
if (isset($_GET['id']) && !empty($_GET['id'])) {
$params = ['variable = ? ' => [$_GET['id']]];
$data = api_get_settings_params($params);
if (!empty($data)) {
foreach ($data as $item) {
$params = ['id' => $item['id'], 'access_url_changeable' => $_GET['changeable']];
api_set_setting_simple($params);
}
}
echo '1';
}
}
break;
case 'version':
// Fix session block when loading admin/index.php and changing page
session_write_close();
echo version_check();
break;
case 'get_extra_content':
$blockName = isset($_POST['block']) ? Security::remove_XSS($_POST['block']) : null;
if (empty($blockName)) {
exit;
}
if (api_is_multiple_url_enabled()) {
$accessUrlId = api_get_current_access_url_id();
if ($accessUrlId == -1) {
exit;
}
$urlInfo = api_get_access_url($accessUrlId);
$url = api_remove_trailing_slash(preg_replace('/https?:\/\//i', '', $urlInfo['url']));
$cleanUrl = str_replace('/', '-', $url);
$newUrlDir = api_get_path(SYS_APP_PATH)."home/$cleanUrl/admin/";
} else {
$newUrlDir = api_get_path(SYS_APP_PATH)."home/admin/";
}
if (!file_exists($newUrlDir)) {
exit;
}
if (!Security::check_abs_path("{$newUrlDir}{$blockName}_extra.html", $newUrlDir)) {
exit;
}
if (!file_exists("{$newUrlDir}{$blockName}_extra.html")) {
exit;
}
echo file_get_contents("{$newUrlDir}{$blockName}_extra.html");
break;
case 'get_latest_news':
if (api_get_configuration_value('admin_chamilo_announcements_disable') === true) {
break;
}
try {
$latestNews = getLatestNews();
$latestNews = json_decode($latestNews, true);
echo Security::remove_XSS($latestNews['text'], COURSEMANAGER);
break;
} catch (Exception $e) {
break;
}
}
/**
* Displays either the text for the registration or the message that the installation is (not) up to date.
*
* @return string html code
*
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
*
* @version august 2006
*
* @todo have a 6 monthly re-registration
*/
function version_check()
{
$tbl_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
$sql = 'SELECT selected_value FROM '.$tbl_settings.' WHERE variable = "registered" ';
$result = Database::query($sql);
$row = Database::fetch_array($result, 'ASSOC');
// The site has not been registered yet.
$return = '';
if ($row['selected_value'] == 'false') {
$return .= get_lang('VersionCheckExplanation');
$return .= '<form class="version-checking" action="'.api_get_path(WEB_CODE_PATH).'admin/index.php" id="VersionCheck" name="VersionCheck" method="post">';
$return .= '<label class="checkbox"><input type="checkbox" name="donotlistcampus" value="1" id="checkbox" />'.get_lang('HideCampusFromPublicPlatformsList');
$return .= '</label><button type="submit" class="btn btn-primary btn-block" name="Register" value="'.get_lang('EnableVersionCheck').'" id="register" >'.get_lang('EnableVersionCheck').'</button>';
$return .= '</form>';
check_system_version();
} else {
// site not registered. Call anyway
$return .= check_system_version();
}
return $return;
}
/**
* Check if the current installation is up to date
* The code is borrowed from phpBB and slighlty modified.
*
* @throws \Exception
* @throws \InvalidArgumentException
*
* @return string language string with some layout (color)
*/
function check_system_version()
{
// Check if curl is available.
if (!in_array('curl', get_loaded_extensions())) {
return '<span style="color:red">'.get_lang('ImpossibleToContactVersionServerPleaseTryAgain').'</span>';
}
$url = 'https://version.chamilo.org';
$options = [
'verify' => false,
];
$urlValidated = false;
try {
$client = new GuzzleHttp\Client();
$res = $client->request('GET', $url, $options);
if ($res->getStatusCode() == '200' || $res->getStatusCode() == '301') {
$urlValidated = true;
}
} catch (Exception $e) {
}
// the chamilo version of your installation
$system_version = trim(api_get_configuration_value('system_version'));
if ($urlValidated) {
// The number of courses
$number_of_courses = Statistics::countCourses();
// The number of users
$number_of_users = Statistics::countUsers();
$number_of_active_users = Statistics::countUsers(
null,
null,
null,
true
);
// The number of sessions
$number_of_sessions = SessionManager::count_sessions(api_get_current_access_url_id());
$packager = api_get_configuration_value('packager');
if (empty($packager)) {
$packager = 'chamilo';
}
$uniqueId = '';
$entityManager = Database::getManager();
/** @var BranchSyncRepository $branch */
$repository = $entityManager->getRepository('ChamiloCoreBundle:BranchSync');
/** @var BranchSync $branch */
$branch = $repository->getTopBranch();
if (is_a($branch, '\Chamilo\CoreBundle\Entity\BranchSync')) {
$uniqueId = $branch->getUniqueId();
}
$data = [
'url' => api_get_path(WEB_PATH),
'campus' => api_get_setting('siteName'),
'contact' => api_get_setting('emailAdministrator'), // the admin's e-mail, with the only purpose of being able to contact admins to inform about critical security issues
'version' => $system_version,
'numberofcourses' => $number_of_courses, // to sum up into non-personal statistics - see https://version.chamilo.org/stats/
'numberofusers' => $number_of_users, // to sum up into non-personal statistics
'numberofactiveusers' => $number_of_active_users, // to sum up into non-personal statistics
'numberofsessions' => $number_of_sessions,
//The donotlistcampus setting recovery should be improved to make
// it true by default - this does not affect numbers counting
'donotlistcampus' => api_get_setting('donotlistcampus'),
'organisation' => api_get_setting('Institution'),
'language' => api_get_setting('platformLanguage'), //helps us know the spread of language usage for campuses, by main language
'adminname' => api_get_setting('administratorName').' '.api_get_setting('administratorSurname'), //not sure this is necessary...
'ip' => $_SERVER['REMOTE_ADDR'], //the admin's IP address, with the only purpose of trying to geolocate portals around the globe to draw a map
// Reference to the packager system or provider through which
// Chamilo is installed/downloaded. Packagers can change this in
// the default config file (main/install/configuration.dist.php)
// or in the installed config file. The default value is 'chamilo'
'packager' => $packager,
'unique_id' => $uniqueId,
];
$version = null;
$client = new GuzzleHttp\Client();
$url .= '?';
foreach ($data as $k => $v) {
$url .= urlencode($k).'='.urlencode($v).'&';
}
$res = $client->request('GET', $url, $options);
if ($res->getStatusCode() == '200') {
$versionData = $res->getHeader('X-Chamilo-Version');
if (isset($versionData[0])) {
$version = trim($versionData[0]);
}
}
if (version_compare($system_version, $version, '<')) {
$output = '<span style="color:red">'.get_lang('YourVersionNotUpToDate').'<br />
'.get_lang('LatestVersionIs').' <b>Chamilo '.$version.'</b>. <br />
'.get_lang('YourVersionIs').' <b>Chamilo '.$system_version.'</b>. <br />'.str_replace('http://www.chamilo.org', '<a href="http://www.chamilo.org">http://www.chamilo.org</a>', get_lang('PleaseVisitOurWebsite')).'</span>';
} else {
$output = '<span style="color:green">'.get_lang('VersionUpToDate').': Chamilo '.$version.'</span>';
}
return $output;
}
return '<span style="color:red">'.get_lang('ImpossibleToContactVersionServerPleaseTryAgain').'</span>';
}
/**
* Display the latest news from the Chamilo Association for admins.
*
* @throws \GuzzleHttp\Exception\GuzzleException
* @throws Exception
*
* @return string|void
*/
function getLatestNews()
{
$url = 'https://version.chamilo.org/news/latest.php';
$client = new Client();
$response = $client->request(
'GET',
$url,
[
'query' => [
'language' => api_get_interface_language(),
],
]
);
if ($response->getStatusCode() !== 200) {
throw new Exception(get_lang('DenyEntry'));
}
return $response->getBody()->getContents();
}

View File

@@ -0,0 +1,262 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Responses to AJAX calls.
*/
$type = isset($_REQUEST['type']) && in_array($_REQUEST['type'], ['personal', 'course', 'admin']) ? $_REQUEST['type'] : 'personal';
if ($type === 'personal') {
$cidReset = true; // fixes #5162
}
require_once __DIR__.'/../global.inc.php';
$action = $_REQUEST['a'] ?? null;
$group_id = api_get_group_id();
if ($type === 'course') {
api_protect_course_script(true);
}
$logInfo = [
'tool' => TOOL_CALENDAR_EVENT,
'action' => $action,
];
Event::registerLog($logInfo);
$agenda = new Agenda($type);
// get filtered type
$type = $agenda->getType();
$em = Database::getManager();
switch ($action) {
case 'add_event':
if (!$agenda->getIsAllowedToEdit()) {
break;
}
if (false === Security::check_token('get')) {
exit;
}
$add_as_announcement = $_REQUEST['add_as_annonuncement'] ?? null;
$title = $_REQUEST['title'] ?? null;
$content = $_REQUEST['content'] ?? null;
$comment = $_REQUEST['comment'] ?? null;
$userToSend = $_REQUEST['users_to_send'] ?? [];
$inviteesList = $_REQUEST['invitees'] ?? [];
$isCollective = isset($_REQUEST['collective']);
$notificationCount = $_REQUEST['notification_count'] ?? [];
$notificationPeriod = $_REQUEST['notification_period'] ?? [];
$careerId = $_REQUEST['career_id'] ?? 0;
$promotionId = $_REQUEST['promotion_id'] ?? 0;
$subscriptionVisibility = (int) ($_REQUEST['subscription_visibility'] ?? 0);
$subscriptionItemId = isset($_REQUEST['subscription_item']) ? (int) $_REQUEST['subscription_item'] : null;
$maxSubscriptions = (int) ($_REQUEST['max_subscriptions'] ?? 0);
$reminders = $notificationCount ? array_map(null, $notificationCount, $notificationPeriod) : [];
$eventId = $agenda->addEvent(
$_REQUEST['start'],
$_REQUEST['end'],
$_REQUEST['all_day'],
$title,
$content,
$userToSend,
$add_as_announcement,
null,
[],
null,
$comment,
'',
$inviteesList,
$isCollective,
$reminders,
(int) $careerId,
(int) $promotionId,
$subscriptionVisibility,
$subscriptionItemId,
$maxSubscriptions
);
echo $eventId;
break;
case 'edit_event':
if (!$agenda->getIsAllowedToEdit()) {
break;
}
if (false === Security::check_token('get')) {
exit;
}
$id_list = explode('_', $_REQUEST['id']);
$id = $id_list[1];
$agenda->editEvent(
$id,
$_REQUEST['start'],
$_REQUEST['end'],
$_REQUEST['all_day'],
$title,
$content
);
break;
case 'delete_event':
if (!$agenda->getIsAllowedToEdit()) {
break;
}
if (false === Security::check_token('get')) {
exit;
}
$id_list = explode('_', $_REQUEST['id']);
$id = $id_list[1];
$deleteAllEventsFromSerie = isset($_REQUEST['delete_all_events']);
$agenda->deleteEvent($id, $deleteAllEventsFromSerie);
break;
case 'resize_event':
if (!$agenda->getIsAllowedToEdit()) {
break;
}
if (false === Security::check_token('get')) {
exit;
}
$minute_delta = $_REQUEST['minute_delta'];
$id = explode('_', $_REQUEST['id']);
$id = $id[1];
$agenda->resizeEvent($id, $minute_delta);
break;
case 'move_event':
if (!$agenda->getIsAllowedToEdit()) {
break;
}
if (false === Security::check_token('get')) {
exit;
}
$minute_delta = $_REQUEST['minute_delta'];
$allDay = $_REQUEST['all_day'];
$id = explode('_', $_REQUEST['id']);
$id = $id[1];
$agenda->move_event($id, $minute_delta, $allDay);
break;
case 'get_events':
$filter = $_REQUEST['user_id'] ?? null;
$sessionId = $_REQUEST['session_id'] ?? null;
$result = $agenda->parseAgendaFilter($filter);
$groupId = current($result['groups']);
$userId = current($result['users']);
$start = isset($_REQUEST['start']) ? api_strtotime($_REQUEST['start']) : null;
$end = isset($_REQUEST['end']) ? api_strtotime($_REQUEST['end']) : null;
if ($type === 'personal' && !empty($sessionId)) {
$agenda->setSessionId($sessionId);
}
$events = $agenda->getEvents(
$start,
$end,
api_get_course_int_id(),
$groupId,
$userId
);
header('Content-Type: application/json');
echo $events;
break;
case 'get_user_agenda':
// Used in the admin user list.
api_protect_admin_script();
if (api_is_allowed_to_edit(null, true)) {
//@todo move this in the agenda class
$DaysShort = api_get_week_days_short();
$MonthsLong = api_get_months_long();
$user_id = (int) $_REQUEST['user_id'];
$my_course_list = CourseManager::get_courses_list_by_user_id($user_id, true);
if (!is_array($my_course_list)) {
// this is for the special case if the user has no courses (otherwise you get an error)
$my_course_list = [];
}
$today = getdate();
$year = (!empty($_GET['year']) ? (int) $_GET['year'] : null);
if ($year == null) {
$year = $today['year'];
}
$month = (!empty($_GET['month']) ? (int) $_GET['month'] : null);
if ($month == null) {
$month = $today['mon'];
}
$day = (!empty($_GET['day']) ? (int) $_GET['day'] : null);
if ($day == null) {
$day = $today['mday'];
}
$monthName = $MonthsLong[$month - 1];
$week = null;
$agendaitems = Agenda::get_myagendaitems(
$user_id,
$my_course_list,
$month,
$year
);
$agendaitems = Agenda::get_global_agenda_items(
$agendaitems,
$day,
$month,
$year,
$week,
"month_view"
);
if (api_get_setting('allow_personal_agenda') == 'true') {
$agendaitems = Agenda::get_personal_agenda_items(
$user_id,
$agendaitems,
$day,
$month,
$year,
$week,
"month_view"
);
}
Agenda::display_mymonthcalendar(
$user_id,
$agendaitems,
$month,
$year,
[],
$monthName,
false
);
}
break;
case 'event_subscribe':
if (!$agenda->getIsAllowedToEdit()) {
break;
}
if (false === Security::check_token('get')) {
exit;
}
$id = (int) explode('_', $_REQUEST['id'])[1];
$agenda->subscribeCurrentUserToEvent($id);
break;
case 'event_unsubscribe':
if (!$agenda->getIsAllowedToEdit()) {
break;
}
if (false === Security::check_token('get')) {
exit;
}
$id = (int) explode('_', $_REQUEST['id'])[1];
$agenda->unsubscribeCurrentUserToEvent($id);
break;
default:
echo '';
}
exit;

View File

@@ -0,0 +1,233 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Responses to AJAX calls.
*/
require_once __DIR__.'/../global.inc.php';
$action = $_REQUEST['a'] ?? null;
$isAllowedToEdit = api_is_allowed_to_edit();
$courseInfo = api_get_course_info();
$courseCode = api_get_course_id();
$courseId = api_get_course_int_id();
$groupId = api_get_group_id();
$sessionId = api_get_session_id();
$currentUserId = api_get_user_id();
$isTutor = false;
if (!empty($groupId)) {
$groupInfo = GroupManager::get_group_properties($groupId);
$isTutor = GroupManager::is_tutor_of_group(api_get_user_id(), $groupInfo);
if ($isTutor) {
$isAllowedToEdit = true;
}
}
switch ($action) {
case 'preview':
$userInCourse = false;
if ($courseId != 0 && CourseManager::is_user_subscribed_in_course($currentUserId, CourseManager::get_course_code_from_course_id($courseId), $sessionId)) {
$userInCourse = true;
}
$allowToEdit = (
api_is_allowed_to_edit(false, true) ||
(api_get_course_setting('allow_user_edit_announcement') && !api_is_anonymous() && $userInCourse) ||
($sessionId && api_is_coach() && api_get_configuration_value('allow_coach_to_edit_announcements'))
);
$drhHasAccessToSessionContent = api_drh_can_access_all_session_content();
if (!empty($sessionId) && $drhHasAccessToSessionContent) {
$allowToEdit = $allowToEdit || api_is_drh();
}
if ($allowToEdit === false && !empty($groupId)) {
$groupProperties = GroupManager::get_group_properties($groupId);
// Check if user is tutor group
$isTutor = GroupManager::is_tutor_of_group(api_get_user_id(), $groupProperties, $courseId);
if ($isTutor) {
$allowToEdit = true;
}
// Last chance ... students can send announcements.
if ($groupProperties['announcements_state'] == GroupManager::TOOL_PRIVATE_BETWEEN_USERS) {
// check if user is a group member to give access
$groupInfo = GroupManager::get_group_properties($groupId);
if (array_key_exists($currentUserId, GroupManager::get_subscribed_users($groupInfo))) {
$allowToEdit = true;
}
}
}
if ($allowToEdit === false) {
exit;
}
$users = isset($_REQUEST['users']) ? json_decode($_REQUEST['users']) : '';
$formParams = [];
if (isset($_REQUEST['form'])) {
parse_str($_REQUEST['form'], $formParams);
}
$previewGroups = [];
$previewUsers = [];
$previewTotal = [];
if (empty($groupId)) {
if (empty($users) ||
(!empty($users) && isset($users[0]) && $users[0] == 'everyone')
) {
// All users in course session
if (empty($sessionId)) {
$students = CourseManager::get_user_list_from_course_code($courseInfo['code']);
} else {
$students = CourseManager::get_user_list_from_course_code($courseInfo['code'], $sessionId);
}
foreach ($students as $student) {
$previewUsers[] = $student['user_id'];
}
$groupList = GroupManager::get_group_list(null, $courseInfo, null, $sessionId);
foreach ($groupList as $group) {
$previewGroups[] = $group['iid'];
}
} else {
$send_to = CourseManager::separateUsersGroups($users);
// Storing the selected groups
if (is_array($send_to['groups']) &&
!empty($send_to['groups'])
) {
$counter = 1;
foreach ($send_to['groups'] as $group) {
$previewGroups[] = $group;
}
}
// Storing the selected users
if (is_array($send_to['users'])) {
$counter = 1;
foreach ($send_to['users'] as $user) {
$previewUsers[] = $user;
}
}
}
} else {
$send_to_users = CourseManager::separateUsersGroups($users);
$sentToAllGroup = false;
if (empty($send_to_users['groups']) && empty($send_to_users['users'])) {
$previewGroups[] = $groupId;
$sentToAllGroup = true;
}
if ($sentToAllGroup === false) {
if (!empty($send_to_users['groups'])) {
foreach ($send_to_users['groups'] as $group) {
$previewGroups[] = $group;
}
}
if (!empty($send_to_users['users'])) {
foreach ($send_to_users['users'] as $user) {
$previewUsers[] = $user;
}
}
}
}
if (isset($formParams['send_to_users_in_session']) && $formParams['send_to_users_in_session'] == 1) {
$sessionList = SessionManager::get_session_by_course(api_get_course_int_id());
if (!empty($sessionList)) {
foreach ($sessionList as $sessionInfo) {
$sessionId = $sessionInfo['id'];
$userList = CourseManager::get_user_list_from_course_code(
$courseCode,
$sessionId
);
if (!empty($userList)) {
foreach ($userList as $user) {
$previewUsers[] = $user;
}
}
}
}
}
if (isset($formParams['send_to_hrm_users']) && $formParams['send_to_hrm_users'] == 1) {
foreach ($previewUsers as $userId) {
$userInfo = api_get_user_info($userId);
$drhList = UserManager::getDrhListFromUser($userId);
if (!empty($drhList)) {
foreach ($drhList as $drhInfo) {
$previewUsers[] = $drhInfo['id'];
}
}
}
}
if (isset($formParams['send_me_a_copy_by_email']) && $formParams['send_me_a_copy_by_email'] == 1) {
$previewUsers[] = api_get_user_id();
}
$previewUserNames = [];
$previewGroupNames = [];
if (!empty($previewGroups)) {
$previewGroups = array_unique($previewGroups);
foreach ($previewGroups as $groupId) {
$groupInfo = GroupManager::get_group_properties($groupId);
$previewGroupNames[] = Display::label($groupInfo['name'], 'info');
}
$previewTotal = $previewGroupNames;
}
if (!empty($previewUsers)) {
$previewUsers = array_unique($previewUsers);
foreach ($previewUsers as $userId) {
$userInfo = api_get_user_info($userId);
$previewUserNames[] = Display::label($userInfo['complete_name']);
}
$previewTotal = array_merge($previewTotal, $previewUserNames);
}
$previewTotal = array_map(function ($value) { return ''.$value; }, $previewTotal);
echo json_encode($previewTotal);
break;
case 'delete_item':
if ($isAllowedToEdit) {
if (empty($_REQUEST['id'])) {
return false;
}
if (!empty($sessionId) && api_is_allowed_to_session_edit(false, true) == false && empty($groupId)) {
return false;
}
$list = explode(',', $_REQUEST['id']);
foreach ($list as $itemId) {
if (!api_is_session_general_coach() || api_is_element_in_the_session(TOOL_ANNOUNCEMENT, $itemId)) {
$result = AnnouncementManager::get_by_id(
api_get_course_int_id(),
$itemId
);
if (!empty($result)) {
$delete = true;
if (!empty($groupId) && $isTutor) {
if ($groupId != $result['to_group_id']) {
$delete = false;
}
}
if ($delete) {
AnnouncementManager::delete_announcement($courseInfo, $itemId);
}
}
}
}
}
break;
default:
echo '';
break;
}
exit;

View File

@@ -0,0 +1,22 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Responses to AJAX calls.
*/
require_once __DIR__.'/../global.inc.php';
api_protect_admin_script();
$action = isset($_REQUEST['a']) ? $_REQUEST['a'] : null;
switch ($action) {
case 'get_promotions':
$careerId = isset($_REQUEST['career_id']) ? (int) $_REQUEST['career_id'] : 0;
$career = new Promotion();
$promotions = $career->get_all_promotions_by_career_id($careerId);
echo json_encode($promotions);
break;
}

145
main/inc/ajax/chat.ajax.php Normal file
View File

@@ -0,0 +1,145 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Responses to AJAX calls.
*/
$_dont_save_user_course_access = true;
require_once __DIR__.'/../global.inc.php';
api_block_anonymous_users();
if (api_get_setting('allow_global_chat') == 'false') {
exit;
}
$action = isset($_REQUEST['action']) ? $_REQUEST['action'] : '';
// Course Chat
if ($action === 'preview') {
echo CourseChatUtils::prepareMessage($_REQUEST['message']);
exit;
}
$toUserId = isset($_REQUEST['to']) ? $_REQUEST['to'] : null;
$message = isset($_REQUEST['message']) ? $_REQUEST['message'] : null;
$currentUserId = api_get_user_id();
$chat = new Chat();
if (Chat::disableChat()) {
exit;
}
if ($chat->isChatBlockedByExercises()) {
// Disconnecting the user
$chat->setUserStatus(0);
exit;
}
switch ($action) {
case 'get_message_status':
$messageId = isset($_REQUEST['message_id']) ? $_REQUEST['message_id'] : 0;
$messageInfo = $chat->get($messageId);
if ($messageInfo && $messageInfo['from_user'] == $currentUserId) {
echo json_encode($messageInfo);
}
break;
case 'chatheartbeat':
$chat->heartbeat();
break;
case 'close_window':
// Closes friend window
$chatId = isset($_POST['chatbox']) ? $_POST['chatbox'] : '';
$chat->closeWindow($chatId);
echo '1';
exit;
break;
case 'close':
// Disconnects user from all chat
$chat->close();
echo '1';
exit;
break;
case 'create_room':
if (api_get_configuration_value('hide_chat_video')) {
api_not_allowed();
}
/*$room = VideoChat::getChatRoomByUsers(api_get_user_id(), $toUserId);
if ($room === false) {
$createdRoom = VideoChat::createRoom(api_get_user_id(), $toUserId);
if ($createdRoom === false) {
echo Display::return_message(
get_lang('ChatRoomNotCreated'),
'error'
);
break;
}
$room = VideoChat::getChatRoomByUsers(api_get_user_id(), $toUserId);
}
$videoChatUrl = api_get_path(WEB_LIBRARY_JS_PATH)."chat/video.php?room={$room['id']}";
$videoChatLink = Display::url(
Display::returnFontAwesomeIcon('video-camera').get_lang('StartVideoChat'),
$videoChatUrl
);
$chat->send(
api_get_user_id(),
$toUserId,
$videoChatLink,
false,
false
);
echo Display::tag('p', $videoChatLink, ['class' => 'lead']);*/
break;
case 'get_contacts':
echo $chat->getContacts();
break;
case 'get_previous_messages':
$userId = isset($_REQUEST['user_id']) ? $_REQUEST['user_id'] : 0;
$visibleMessages = isset($_REQUEST['visible_messages']) ? $_REQUEST['visible_messages'] : 0;
if (empty($userId)) {
return '';
}
$items = $chat->getPreviousMessages(
$userId,
$currentUserId,
$visibleMessages
);
if (!empty($items)) {
sort($items);
echo json_encode($items);
exit;
}
echo json_encode([]);
exit;
break;
case 'notify_not_support':
$chat->send(
$currentUserId,
$toUserId,
get_lang('TheXUserBrowserDoesNotSupportWebRTC')
);
break;
case 'sendchat':
$chat->send($currentUserId, $toUserId, $message);
break;
case 'startchatsession':
$chat->startSession();
break;
case 'set_status':
$status = isset($_REQUEST['status']) ? (int) $_REQUEST['status'] : 0;
$chat->setUserStatus($status);
break;
default:
echo '';
}
exit;

View File

@@ -0,0 +1,421 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CoreBundle\Component\Utils\ChamiloApi;
/**
* Responses to AJAX calls.
*/
require_once __DIR__.'/../global.inc.php';
$action = $_REQUEST['a'];
$user_id = api_get_user_id();
switch ($action) {
case 'add_course_vote':
$course_id = (int) $_REQUEST['course_id'];
$star = (int) $_REQUEST['star'];
if (!api_is_anonymous()) {
CourseManager::add_course_vote($user_id, $star, $course_id, 0);
}
$point_info = CourseManager::get_course_ranking($course_id, 0);
$ajax_url = api_get_path(WEB_AJAX_PATH).'course.ajax.php?a=add_course_vote';
$rating = Display::return_rating_system(
'star_'.$course_id,
$ajax_url.'&amp;course_id='.$course_id,
$point_info,
false
);
echo $rating;
break;
case 'get_course_image':
$courseId = ChamiloApi::getCourseIdByDirectory($_REQUEST['code']);
$courseInfo = api_get_course_info_by_id($courseId);
$image = isset($_REQUEST['image']) && in_array($_REQUEST['image'], ['course_image_large_source', 'course_image_source', 'course_email_image_large_source', 'course_email_image_source']) ? $_REQUEST['image'] : '';
if ($courseInfo && $image) {
// Arbitrarily set a cache of 10' for the course image to
// avoid hammering the server with otherwise unfrequently
// changed images that can have some weight
$now = time() + 600; //time must be in GMT anyway
$headers = [
'Expires' => gmdate('D, d M Y H:i:s ', $now).'GMT',
'Cache-Control' => 'max-age=600',
];
DocumentManager::file_send_for_download($courseInfo[$image], null, null, null, $headers);
}
break;
case 'get_user_courses':
// Only search my courses
if (api_is_platform_admin() || api_is_session_admin()) {
$userId = (int) $_REQUEST['user_id'];
$list = CourseManager::get_courses_list_by_user_id(
$userId,
false
);
if (!empty($list)) {
foreach ($list as $course) {
$courseInfo = api_get_course_info_by_id($course['real_id']);
echo $courseInfo['title'].'<br />';
}
} else {
echo get_lang('UserHasNoCourse');
}
}
break;
case 'get_my_courses_and_sessions':
// Search my courses and sessions allowed for admin, session admin, teachers
$currentCourseId = api_get_course_int_id();
$currentSessionId = api_get_session_id();
if (api_is_platform_admin() || api_is_session_admin() || api_is_allowed_to_edit()) {
$list = CourseManager::get_courses_list_by_user_id(
api_get_user_id(),
true,
false,
false,
[],
true,
true
);
if (empty($list)) {
echo json_encode([]);
break;
}
$courseList = [];
if (!empty($list)) {
foreach ($list as $course) {
$courseInfo = api_get_course_info_by_id($course['real_id']);
$sessionId = 0;
if (isset($course['session_id']) && !empty($course['session_id'])) {
$sessionId = $course['session_id'];
}
$sessionName = '';
if (isset($course['session_name']) && !empty($course['session_name'])) {
$sessionName = ' ('.$course['session_name'].')';
}
// Skip current course/course session
if ($currentCourseId == $courseInfo['real_id'] && $sessionId == $currentSessionId) {
continue;
}
$courseList['items'][] = [
'id' => $courseInfo['real_id'].'_'.$sessionId,
'text' => $courseInfo['title'].$sessionName,
];
}
echo json_encode($courseList);
}
}
break;
case 'search_category':
if (api_is_platform_admin() || api_is_allowed_to_create_course()) {
$categories = CourseCategory::searchCategoryByKeyword($_REQUEST['q']);
if (empty($categories)) {
echo json_encode([]);
break;
}
$categoryToAvoid = '';
if (!api_is_platform_admin()) {
$categoryToAvoid = api_get_configuration_value('course_category_code_to_use_as_model');
}
$list = [];
foreach ($categories as $item) {
$categoryCode = $item['code'];
if (!empty($categoryToAvoid) && $categoryToAvoid == $categoryCode) {
continue;
}
$list['items'][] = [
'id' => $categoryCode,
'text' => '('.$categoryCode.') '.strip_tags($item['name']),
];
}
echo json_encode($list);
}
break;
case 'search_course':
if (api_is_teacher() || api_is_platform_admin()) {
if (isset($_GET['session_id']) && !empty($_GET['session_id'])) {
//if session is defined, lets find only courses of this session
$courseList = SessionManager::get_course_list_by_session_id(
$_GET['session_id'],
$_GET['q']
);
} else {
//if session is not defined lets search all courses STARTING with $_GET['q']
//TODO change this function to search not only courses STARTING with $_GET['q']
if (api_is_platform_admin()) {
$courseList = CourseManager::get_courses_list(
0,
0,
'title',
'ASC',
-1,
$_GET['q'],
null,
true
);
} elseif (api_is_teacher()) {
$courseList = CourseManager::get_course_list_of_user_as_course_admin(api_get_user_id(), $_GET['q']);
$category = api_get_configuration_value('course_category_code_to_use_as_model');
if (!empty($category)) {
$alreadyAdded = [];
if (!empty($courseList)) {
$alreadyAdded = array_column($courseList, 'id');
}
$coursesInCategory = CourseCategory::getCoursesInCategory($category, $_GET['q']);
foreach ($coursesInCategory as $course) {
if (!in_array($course['id'], $alreadyAdded)) {
$courseList[] = $course;
}
}
}
}
}
$results = [];
if (empty($courseList)) {
echo json_encode([]);
break;
}
foreach ($courseList as $course) {
$title = $course['title'];
if (!empty($course['category_code'])) {
$parents = CourseCategory::getParentsToString($course['category_code']);
$title = $parents.$course['title'];
}
$results['items'][] = [
'id' => $course['id'],
'text' => $title,
];
}
echo json_encode($results);
}
break;
case 'search_course_by_session':
if (api_is_platform_admin()) {
$results = SessionManager::get_course_list_by_session_id($_GET['session_id'], $_GET['q']);
$results2 = [];
if (is_array($results) && !empty($results)) {
foreach ($results as $item) {
$item2 = [];
foreach ($item as $id => $internal) {
if ($id == 'id') {
$item2[$id] = $internal;
}
if ($id == 'title') {
$item2['text'] = $internal;
}
}
$results2[] = $item2;
}
echo json_encode($results2);
} else {
echo json_encode([]);
}
}
break;
case 'search_course_by_session_all':
if (api_is_platform_admin()) {
if ($_GET['session_id'] == 'TODOS' || $_GET['session_id'] == 'T') {
$_GET['session_id'] = '%';
}
$results = SessionManager::get_course_list_by_session_id_like(
$_GET['session_id'],
$_GET['q']
);
$results2 = ['items' => []];
if (!empty($results)) {
foreach ($results as $item) {
$item2 = [];
foreach ($item as $id => $internal) {
if ($id == 'id') {
$item2[$id] = $internal;
}
if ($id == 'title') {
$item2['text'] = $internal;
}
}
$results2['items'][] = $item2;
}
}
echo json_encode($results2);
}
break;
case 'search_user_by_course':
$sessionId = $_GET['session_id'];
$course = api_get_course_info_by_id($_GET['course_id']);
$isPlatformAdmin = api_is_platform_admin();
$userIsSubscribedInCourse = CourseManager::is_user_subscribed_in_course(
api_get_user_id(),
$course['code'],
!empty($sessionId),
$sessionId
);
if ($isPlatformAdmin || $userIsSubscribedInCourse) {
$json = [
'items' => [],
];
$keyword = Database::escape_string($_GET['q']);
$status = 0;
if (empty($sessionId)) {
$status = STUDENT;
}
$userList = CourseManager::get_user_list_from_course_code(
$course['code'],
$sessionId,
null,
null,
$status,
false,
false,
false,
[],
[],
[],
true,
[],
$_GET['q']
);
foreach ($userList as $user) {
$userCompleteName = api_get_person_name($user['firstname'], $user['lastname']);
$json['items'][] = [
'id' => $user['user_id'],
'text' => "{$user['username']} ($userCompleteName)",
'avatarUrl' => UserManager::getUserPicture($user['id']),
'username' => $user['username'],
'completeName' => $userCompleteName,
];
}
echo json_encode($json);
}
break;
case 'search_exercise_by_course':
if (api_is_platform_admin()) {
$course = api_get_course_info_by_id($_GET['course_id']);
$session_id = (!empty($_GET['session_id'])) ? (int) $_GET['session_id'] : 0;
$exercises = ExerciseLib::get_all_exercises(
$course,
$session_id,
false,
$_GET['q'],
true,
3
);
foreach ($exercises as $exercise) {
$data[] = ['id' => $exercise['iid'], 'text' => html_entity_decode($exercise['title'])];
}
if (!empty($data)) {
$data[] = ['id' => 'T', 'text' => 'TODOS'];
echo json_encode($data);
} else {
echo json_encode([['id' => 'T', 'text' => 'TODOS']]);
}
}
break;
case 'search_survey_by_course':
if (api_is_platform_admin()) {
$survey = Database::get_course_table(TABLE_SURVEY);
$sql = "SELECT survey_id as id, title, anonymous
FROM $survey
WHERE
c_id = %d AND
session_id = %d AND
title LIKE '%s'";
$sql_query = sprintf(
$sql,
(int) $_GET['course_id'],
(int) $_GET['session_id'],
'%'.Database::escape_string($_GET['q']).'%'
);
$result = Database::query($sql_query);
while ($survey = Database::fetch_assoc($result)) {
$survey['title'] .= ($survey['anonymous'] == 1) ? ' ('.get_lang('Anonymous').')' : '';
$data[] = [
'id' => $survey['id'],
'text' => strip_tags(html_entity_decode($survey['title'])),
];
}
if (!empty($data)) {
echo json_encode($data);
} else {
echo json_encode([]);
}
}
break;
case 'display_sessions_courses':
$sessionId = (int) $_GET['session'];
$userTable = Database::get_main_table(TABLE_MAIN_USER);
$coursesData = SessionManager::get_course_list_by_session_id($sessionId);
$courses = [];
foreach ($coursesData as $courseId => $course) {
$coachData = SessionManager::getCoachesByCourseSession($sessionId, $courseId);
$coachName = '';
if (!empty($coachData)) {
$userResult = Database::select('lastname,firstname', $userTable, [
'where' => [
'user_id = ?' => $coachData[0],
],
], 'first');
$coachName = api_get_person_name($userResult['firstname'], $userResult['lastname']);
}
$courses[] = [
'id' => $courseId,
'name' => $course['title'],
'coachName' => $coachName,
];
}
echo json_encode($courses);
break;
case 'course_logout':
$logoutInfo = [
'uid' => api_get_user_id(),
'cid' => api_get_course_int_id(),
'sid' => api_get_session_id(),
];
$logInfo = [
'tool' => 'close-window',
'tool_id' => 0,
'tool_id_detail' => 0,
'action' => 'exit',
];
Event::registerLog($logInfo);
$result = (int) Event::courseLogout($logoutInfo);
echo $result;
break;
default:
echo '';
}
exit;

View File

@@ -0,0 +1,43 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Responses to AJAX calls.
*/
require_once __DIR__.'/../global.inc.php';
api_protect_admin_script();
$action = $_REQUEST['a'];
switch ($action) {
case 'show_courses':
$categoryId = (int) $_REQUEST['id'];
$categoryInfo = CourseCategory::getCategoryById($categoryId);
if (!empty($categoryInfo)) {
$courses = CourseCategory::getCoursesInCategory($categoryInfo['code'], '', false, false);
$table = new HTML_Table(['class' => 'table table-hover table-striped data_table']);
$headers = [
get_lang('Name'),
];
$row = 0;
$column = 0;
foreach ($headers as $header) {
$table->setHeaderContents($row, $column, $header);
$column++;
}
$result = '';
foreach ($courses as $course) {
$row++;
$courseLink = '<a href="'.api_get_path(WEB_PATH).'courses/'.$course['directory'].'/index.php">'.$course['title'].'</a>';
$table->setCellContents($row, 0, $courseLink);
}
echo $table->toHtml();
exit;
}
break;
}
exit;

View File

@@ -0,0 +1,98 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Responses to AJAX calls for course chat.
*/
use Symfony\Component\HttpFoundation\JsonResponse as HttpResponse;
use Symfony\Component\HttpFoundation\Request as HttpRequest;
require_once __DIR__.'/../global.inc.php';
if (!api_protect_course_script(false)) {
exit;
}
$courseId = api_get_course_int_id();
$userId = api_get_user_id();
$sessionId = api_get_session_id();
$groupId = api_get_group_id();
$json = ['status' => false];
$httpRequest = HttpRequest::createFromGlobals();
$httpResponse = HttpResponse::create();
$courseChatUtils = new CourseChatUtils($courseId, $userId, $sessionId, $groupId);
$token = Security::getTokenFromSession('course_chat');
if ($httpRequest->headers->get('x-token') !== $token) {
$_REQUEST['action'] = 'error';
}
switch ($_REQUEST['action']) {
case 'chat_logout':
$logInfo = [
'tool' => TOOL_CHAT,
'action' => 'exit',
'action_details' => 'exit-chat',
];
Event::registerLog($logInfo);
break;
case 'track':
$courseChatUtils->keepUserAsConnected();
$courseChatUtils->disconnectInactiveUsers();
$friend = isset($_REQUEST['friend']) ? (int) $_REQUEST['friend'] : 0;
$filePath = $courseChatUtils->getFileName(true, $friend);
$newFileSize = file_exists($filePath) ? filesize($filePath) : 0;
$oldFileSize = isset($_GET['size']) ? (int) $_GET['size'] : -1;
$newUsersOnline = $courseChatUtils->countUsersOnline();
$oldUsersOnline = isset($_GET['users_online']) ? (int) $_GET['users_online'] : 0;
$json = [
'status' => true,
'data' => [
'oldFileSize' => file_exists($filePath) ? filesize($filePath) : 0,
'history' => $newFileSize !== $oldFileSize ? $courseChatUtils->readMessages(false, $friend) : null,
'usersOnline' => $newUsersOnline,
'userList' => $newUsersOnline != $oldUsersOnline ? $courseChatUtils->listUsersOnline() : null,
'currentFriend' => $friend,
],
];
break;
case 'preview':
$json = [
'status' => true,
'data' => [
'message' => CourseChatUtils::prepareMessage($_REQUEST['message']),
],
];
break;
case 'reset':
$friend = isset($_REQUEST['friend']) ? (int) $_REQUEST['friend'] : 0;
$json = [
'status' => true,
'data' => $courseChatUtils->readMessages(true, $friend),
];
break;
case 'write':
$friend = isset($_REQUEST['friend']) ? (int) $_REQUEST['friend'] : 0;
$writed = $courseChatUtils->saveMessage($_POST['message'], $friend);
$json = [
'status' => $writed,
'data' => [
'writed' => $writed,
],
];
break;
}
$token = Security::get_token('course_chat');
$httpResponse->headers->set('x-token', $token);
$httpResponse->setData($json);
$httpResponse->send();

View File

@@ -0,0 +1,754 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CourseBundle\Entity\CTool;
use ChamiloSession as Session;
// @todo refactor this script, create a class that manage the jqgrid requests
/**
* Responses to AJAX calls.
*/
$action = $_GET['a'];
switch ($action) {
case 'set_visibility':
require_once __DIR__.'/../global.inc.php';
$course_id = api_get_course_int_id();
$sessionId = api_get_session_id();
// Allow tool visibility in sessions.
$allowEditionInSession = api_get_configuration_value('allow_edit_tool_visibility_in_session');
$em = Database::getManager();
$repository = $em->getRepository('ChamiloCourseBundle:CTool');
if (api_is_allowed_to_edit(null, true)) {
$criteria = [
'cId' => $course_id,
//'sessionId' => 0,
'iid' => (int) $_GET['id'],
];
/** @var CTool $tool */
$tool = $repository->findOneBy($criteria);
$visibility = 0;
if ($allowEditionInSession && !empty($sessionId)) {
$newLink = str_replace('id_session=0', 'id_session='.$sessionId, $tool->getLink());
$criteria = [
'cId' => $course_id,
'sessionId' => $sessionId,
//'iid' => (int) $_GET['id'],
'link' => $newLink,
];
/** @var CTool $tool */
$toolInSession = $repository->findOneBy($criteria);
if ($toolInSession) {
// Use the session
$tool = $toolInSession;
$visibility = $toolInSession->getVisibility();
} else {
// Creates new row in c_tool
$toolInSession = clone $tool;
$toolInSession->setLink($newLink);
$toolInSession->setIid(0);
$toolInSession->setId(0);
$toolInSession->setVisibility(0);
$toolInSession->setSessionId($sessionId);
$em->persist($toolInSession);
$em->flush();
// Update id with iid
$toolInSession->setId($toolInSession->getIid());
$em->persist($toolInSession);
$em->flush();
// $tool will be updated later
$tool = $toolInSession;
}
} else {
$visibility = $tool->getVisibility();
}
$toolImage = $tool->getImage();
$customIcon = $tool->getCustomIcon();
if (api_get_setting('homepage_view') !== 'activity_big') {
$toolImage = Display::return_icon(
$toolImage,
null,
null,
null,
null,
true
);
$inactiveImage = str_replace('.gif', '_na.gif', $toolImage);
} else {
// Display::return_icon() also checks in the app/Resources/public/css/themes/{theme}/icons folder
$toolImage = (substr($toolImage, 0, strpos($toolImage, '.'))).'.png';
$toolImage = Display::return_icon(
$toolImage,
get_lang(ucfirst($tool->getName())),
null,
ICON_SIZE_BIG,
null,
true
);
$inactiveImage = str_replace('.png', '_na.png', $toolImage);
}
if (isset($customIcon) && !empty($customIcon)) {
$toolImage = CourseHome::getCustomWebIconPath().$customIcon;
$inactiveImage = CourseHome::getCustomWebIconPath().CourseHome::getDisableIcon($customIcon);
}
$requested_image = $visibility == 0 ? $toolImage : $inactiveImage;
$requested_class = $visibility == 0 ? '' : 'text-muted';
$requested_message = $visibility == 0 ? 'is_active' : 'is_inactive';
$requested_view = $visibility == 0 ? 'visible.png' : 'invisible.png';
$requestedVisible = $visibility == 0 ? 1 : 0;
$requested_view = $visibility == 0 ? 'visible.png' : 'invisible.png';
$requestedVisible = $visibility == 0 ? 1 : 0;
$requested_fa_class = $visibility == 0 ? 'fa fa-eye '.$requested_class : 'fa fa-eye-slash '.$requested_class;
// HIDE AND REACTIVATE TOOL
if ($_GET['id'] == strval(intval($_GET['id']))) {
$tool->setVisibility($requestedVisible);
$em->persist($tool);
$em->flush();
// Also hide the tool in all sessions
if ($allowEditionInSession && empty($sessionId)) {
$criteria = [
'cId' => $course_id,
'name' => $tool->getName(),
];
/** @var CTool $toolItem */
$tools = $repository->findBy($criteria);
foreach ($tools as $toolItem) {
$toolSessionId = $toolItem->getSessionId();
if (!empty($toolSessionId)) {
$toolItem->setVisibility($requestedVisible);
$em->persist($toolItem);
}
}
$em->flush();
}
}
$response = [
'image' => $requested_image,
'tclass' => $requested_class,
'message' => $requested_message,
'view' => $requested_view,
'fclass' => $requested_fa_class,
];
echo json_encode($response);
}
break;
case 'set_visibility_for_all':
require_once __DIR__.'/../global.inc.php';
$course_id = api_get_course_int_id();
$sessionId = api_get_session_id();
$allowEditionInSession = api_get_configuration_value('allow_edit_tool_visibility_in_session');
$response = [];
$tools_ids = json_decode($_GET['tools_ids']);
$em = Database::getManager();
$repository = $em->getRepository('ChamiloCourseBundle:CTool');
// Allow tool visibility in sessions.
if (api_is_allowed_to_edit(null, true)) {
if (is_array($tools_ids) && count($tools_ids) != 0) {
$total_tools = count($tools_ids);
for ($i = 0; $i < $total_tools; $i++) {
$tool_id = (int) $tools_ids[$i];
$criteria = [
'cId' => $course_id,
'sessionId' => 0,
'iid' => $tool_id,
];
/** @var CTool $tool */
$tool = $repository->findOneBy($criteria);
$visibility = $tool->getVisibility();
if ($allowEditionInSession && !empty($sessionId)) {
$criteria = [
'cId' => $course_id,
'sessionId' => $sessionId,
'name' => $tool->getName(),
];
/** @var CTool $tool */
$toolInSession = $repository->findOneBy($criteria);
if ($toolInSession) {
// Use the session
$tool = $toolInSession;
$visibility = $toolInSession->getVisibility();
} else {
// Creates new row in c_tool
$toolInSession = clone $tool;
$toolInSession->setIid(0);
$toolInSession->setId(0);
$toolInSession->setVisibility(0);
$toolInSession->setSessionId($session_id);
$em->persist($toolInSession);
$em->flush();
// Update id with iid
$toolInSession->setId($toolInSession->getIid());
$em->persist($toolInSession);
$em->flush();
// $tool will be updated later
$tool = $toolInSession;
}
}
$toolImage = $tool->getImage();
$customIcon = $tool->getCustomIcon();
if (api_get_setting('homepage_view') != 'activity_big') {
$toolImage = Display::return_icon(
$toolImage,
null,
null,
null,
null,
true
);
$inactiveImage = str_replace('.gif', '_na.gif', $toolImage);
} else {
// Display::return_icon() also checks in the app/Resources/public/css/themes/{theme}/icons folder
$toolImage = (substr($toolImage, 0, strpos($toolImage, '.'))).'.png';
$toolImage = Display::return_icon(
$toolImage,
get_lang(ucfirst($tool->getName())),
null,
ICON_SIZE_BIG,
null,
true
);
$inactiveImage = str_replace('.png', '_na.png', $toolImage);
}
if (isset($customIcon) && !empty($customIcon)) {
$toolImage = CourseHome::getCustomWebIconPath().$customIcon;
$inactiveImage = CourseHome::getCustomWebIconPath().CourseHome::getDisableIcon($customIcon);
}
$requested_image = $visibility == 0 ? $toolImage : $inactiveImage;
$requested_class = $visibility == 0 ? '' : 'text-muted';
$requested_message = $visibility == 0 ? 'is_active' : 'is_inactive';
$requested_view = $visibility == 0 ? 'visible.png' : 'invisible.png';
$requestedVisible = $visibility == 0 ? 1 : 0;
$requested_view = $visibility == 0 ? 'visible.png' : 'invisible.png';
$requested_fa_class = $visibility == 0 ? 'fa fa-eye '.$requested_class : 'fa fa-eye-slash '.$requested_class;
$requestedVisible = $visibility == 0 ? 1 : 0;
// HIDE AND REACTIVATE TOOL
if ($tool_id == strval(intval($tool_id))) {
$tool->setVisibility($requestedVisible);
$em->persist($tool);
$em->flush();
// Also hide the tool in all sessions
if ($allowEditionInSession && empty($sessionId)) {
$criteria = [
'cId' => $course_id,
'name' => $tool->getName(),
];
/** @var CTool $toolItem */
$tools = $repository->findBy($criteria);
foreach ($tools as $toolItem) {
$toolSessionId = $toolItem->getSessionId();
if (!empty($toolSessionId)) {
$toolItem->setVisibility($requestedVisible);
$em->persist($toolItem);
}
}
$em->flush();
}
}
$response[] = [
'image' => $requested_image,
'tclass' => $requested_class,
'message' => $requested_message,
'view' => $requested_view,
'fclass' => $requested_fa_class,
'id' => $tool_id,
];
}
}
}
echo json_encode($response);
break;
case 'show_course_information':
require_once __DIR__.'/../global.inc.php';
// Get the name of the database course.
$course_info = api_get_course_info($_GET['code']);
$content = get_lang('NoDescription');
if (!empty($course_info)) {
if (api_get_setting('course_catalog_hide_private') === 'true' &&
$course_info['visibility'] == COURSE_VISIBILITY_REGISTERED
) {
echo get_lang('PrivateAccess');
break;
}
$table = Database::get_course_table(TABLE_COURSE_DESCRIPTION);
$sql = "SELECT * FROM $table
WHERE c_id = ".$course_info['real_id']." AND session_id = 0
ORDER BY id";
$result = Database::query($sql);
if (Database::num_rows($result) > 0) {
while ($description = Database::fetch_object($result)) {
$descriptions[$description->id] = $description;
}
// Function that displays the details of the course description in html.
$content = CourseManager::get_details_course_description_html(
$descriptions,
api_get_system_encoding(),
false
);
}
}
echo $content;
break;
case 'session_courses_lp_default':
/**
* @todo this functions need to belong to a class or a special
* wrapper to process the AJAX petitions from the jqgrid
*/
require_once __DIR__.'/../global.inc.php';
$now = time();
$page = (int) $_REQUEST['page']; //page
$limit = (int) $_REQUEST['rows']; // quantity of rows
//index to filter
$sidx = isset($_REQUEST['sidx']) && !empty($_REQUEST['sidx']) ? $_REQUEST['sidx'] : 'id';
$sord = $_REQUEST['sord']; //asc or desc
if (!in_array($sord, ['asc', 'desc'])) {
$sord = 'desc';
}
$session_id = (int) $_REQUEST['session_id'];
$course_id = (int) $_REQUEST['course_id'];
//Filter users that does not belong to the session
if (!api_is_platform_admin()) {
$new_session_list = UserManager::get_personal_session_course_list(api_get_user_id());
$my_session_list = [];
foreach ($new_session_list as $item) {
if (!empty($item['session_id'])) {
$my_session_list[] = $item['session_id'];
}
}
if (!in_array($session_id, $my_session_list)) {
break;
}
}
$start = $limit * $page - $limit;
$course_list = SessionManager::get_course_list_by_session_id($session_id);
$count = 0;
$temp = [];
foreach ($course_list as $item) {
$courseInfo = api_get_course_info($item['code']);
$list = new LearnpathList(api_get_user_id(), $courseInfo, $session_id);
$flat_list = $list->get_flat_list();
$lps[$item['code']] = $flat_list;
$course_url = api_get_path(WEB_COURSE_PATH).$item['directory'].'/?id_session='.$session_id;
$item['title'] = Display::url($item['title'], $course_url, ['target' => SESSION_LINK_TARGET]);
foreach ($flat_list as $lp_id => $lp_item) {
$isAllowedToEdit = api_is_allowed_to_edit(null, true);
if (!$isAllowedToEdit && 0 == $lp_item['lp_visibility']) {
continue;
}
$temp[$count]['id'] = $lp_id;
$lp = new learnpath($item['code'], $lp_id, api_get_user_id());
if ($lp->progress_db == 100) {
continue;
}
$lp_url = api_get_path(WEB_CODE_PATH).'lp/lp_controller.php?cidReq='.$item['code'].'&id_session='.$session_id.'&lp_id='.$lp_id.'&action=view';
$last_date = Tracking::get_last_connection_date_on_the_course(
api_get_user_id(),
$item,
$session_id,
false
);
if (empty($lp_item['modified_on'])) {
$lp_date = api_get_local_time($lp_item['created_on']);
$image = 'new.gif';
$label = get_lang('LearnpathAdded');
} else {
$lp_date = api_get_local_time($lp_item['modified_on']);
$image = 'moderator_star.png';
$label = get_lang('LearnpathUpdated');
}
$icons = '';
if (strtotime($last_date) < strtotime($lp_date)) {
$icons = Display::return_icon($image, get_lang('TitleNotification').': '.$label.' - '.$lp_date);
}
if (!empty($lp_item['publicated_on'])) {
$date = substr($lp_item['publicated_on'], 0, 10);
} else {
$date = '-';
}
// Checking LP publicated and expired_on dates
if (!empty($lp_item['publicated_on'])) {
if ($now < api_strtotime($lp_item['publicated_on'], 'UTC')) {
continue;
}
}
if (!empty($lp_item['expired_on'])) {
if ($now > api_strtotime($lp_item['expired_on'], 'UTC')) {
continue;
}
}
$temp[$count]['cell'] = [
$date,
$item['title'],
Display::url($icons.' '.$lp_item['lp_name'], $lp_url, ['target' => SESSION_LINK_TARGET]),
];
$temp[$count]['course'] = strip_tags($item['title']);
$temp[$count]['lp'] = $lp_item['lp_name'];
$temp[$count]['date'] = $lp_item['publicated_on'];
$count++;
}
}
$temp = msort($temp, $sidx, $sord);
$i = 0;
$response = new stdClass();
foreach ($temp as $key => $row) {
$row = $row['cell'];
if (!empty($row)) {
if ($key >= $start && $key < ($start + $limit)) {
$response->rows[$i]['id'] = $key;
$response->rows[$i]['cell'] = [$row[0], $row[1], $row[2]];
$i++;
}
}
}
$total_pages = 0;
if ($count > 0 && $limit > 0) {
$total_pages = ceil($count / $limit);
}
$response->total = $total_pages;
if ($page > $total_pages) {
$response->page = $total_pages;
} else {
$response->page = $page;
}
$response->records = $count;
echo json_encode($response);
break;
case 'session_courses_lp_by_week':
require_once __DIR__.'/../global.inc.php';
$now = time();
$page = (int) $_REQUEST['page']; //page
$limit = (int) $_REQUEST['rows']; // quantity of rows
$sidx = isset($_REQUEST['sidx']) && !empty($_REQUEST['sidx']) ? $_REQUEST['sidx'] : 'course';
$sidx = str_replace(['week desc,', ' '], '', $sidx);
$sord = $_REQUEST['sord']; //asc or desc
if (!in_array($sord, ['asc', 'desc'])) {
$sord = 'desc';
}
$session_id = (int) $_REQUEST['session_id'];
$course_id = (int) $_REQUEST['course_id'];
//Filter users that does not belong to the session
if (!api_is_platform_admin()) {
$new_session_list = UserManager::get_personal_session_course_list(api_get_user_id());
$my_session_list = [];
foreach ($new_session_list as $item) {
if (!empty($item['session_id'])) {
$my_session_list[] = $item['session_id'];
}
}
if (!in_array($session_id, $my_session_list)) {
break;
}
}
$start = $limit * $page - $limit;
$course_list = SessionManager::get_course_list_by_session_id($session_id);
$count = 0;
$temp = [];
foreach ($course_list as $item) {
if (isset($course_id) && !empty($course_id)) {
if ($course_id != $item['id']) {
continue;
}
}
$list = new LearnpathList(
api_get_user_id(),
api_get_course_info($item['code']),
$session_id,
'lp.publicatedOn DESC'
);
$flat_list = $list->get_flat_list();
$lps[$item['code']] = $flat_list;
$item['title'] = Display::url(
$item['title'],
api_get_path(WEB_COURSE_PATH).$item['directory'].'/?id_session='.$session_id,
['target' => SESSION_LINK_TARGET]
);
foreach ($flat_list as $lp_id => $lp_item) {
$temp[$count]['id'] = $lp_id;
$lp_url = api_get_path(WEB_CODE_PATH).'lp/lp_controller.php?cidReq='.$item['code'].'&id_session='.$session_id.'&lp_id='.$lp_id.'&action=view';
$last_date = Tracking::get_last_connection_date_on_the_course(
api_get_user_id(),
$item,
$session_id,
false
);
if (empty($lp_item['modified_on'])) {
$lp_date = api_get_local_time($lp_item['created_on']);
$image = 'new.gif';
$label = get_lang('LearnpathAdded');
} else {
$lp_date = api_get_local_time($lp_item['modified_on']);
$image = 'moderator_star.png';
$label = get_lang('LearnpathUpdated');
}
if (strtotime($last_date) < strtotime($lp_date)) {
$icons = Display::return_icon($image, get_lang('TitleNotification').': '.$label.' - '.$lp_date);
}
if (!empty($lp_item['publicated_on'])) {
$date = substr($lp_item['publicated_on'], 0, 10);
} else {
$date = '-';
}
// Checking LP publicated and expired_on dates
if (!empty($lp_item['publicated_on'])) {
$week_data = date('Y', api_strtotime($lp_item['publicated_on'], 'UTC')).' - '.get_week_from_day($lp_item['publicated_on']);
if ($now < api_strtotime($lp_item['publicated_on'], 'UTC')) {
continue;
}
} else {
$week_data = '';
}
if (!empty($lp_item['expired_on'])) {
if ($now > api_strtotime($lp_item['expired_on'], 'UTC')) {
continue;
}
}
$temp[$count]['cell'] = [
$week_data,
$date,
$item['title'],
Display::url($icons.' '.$lp_item['lp_name'], $lp_url, ['target' => SESSION_LINK_TARGET]),
];
$temp[$count]['course'] = strip_tags($item['title']);
$temp[$count]['lp'] = $lp_item['lp_name'];
$count++;
}
}
if (!empty($sidx)) {
$temp = msort($temp, $sidx, $sord);
}
$response = new stdClass();
$i = 0;
foreach ($temp as $key => $row) {
$row = $row['cell'];
if (!empty($row)) {
if ($key >= $start && $key < ($start + $limit)) {
$response->rows[$i]['id'] = $key;
$response->rows[$i]['cell'] = [$row[0], $row[1], $row[2], $row[3]];
$i++;
}
}
}
$total_pages = 0;
if ($count > 0 && $limit > 0) {
$total_pages = ceil($count / $limit);
}
$response->total = $total_pages;
if ($page > $total_pages) {
$response->page = $total_pages;
} else {
$response->page = $page;
}
$response->records = $count;
echo json_encode($response);
break;
case 'session_courses_lp_by_course':
require_once __DIR__.'/../global.inc.php';
$now = time();
$page = (int) $_REQUEST['page']; //page
$limit = (int) $_REQUEST['rows']; // quantity of rows
$sidx = isset($_REQUEST['sidx']) && !empty($_REQUEST['sidx']) ? $_REQUEST['sidx'] : 'id';
$sidx = str_replace(['course asc,', ' '], '', $sidx);
$sord = $_REQUEST['sord']; //asc or desc
if (!in_array($sord, ['asc', 'desc'])) {
$sord = 'desc';
}
$session_id = (int) $_REQUEST['session_id'];
$course_id = (int) $_REQUEST['course_id'];
//Filter users that does not belong to the session
if (!api_is_platform_admin()) {
$new_session_list = UserManager::get_personal_session_course_list(api_get_user_id());
$my_session_list = [];
foreach ($new_session_list as $item) {
if (!empty($item['session_id'])) {
$my_session_list[] = $item['session_id'];
}
}
if (!in_array($session_id, $my_session_list)) {
break;
}
}
$start = $limit * $page - $limit;
$course_list = SessionManager::get_course_list_by_session_id($session_id);
$count = 0;
$temp = [];
foreach ($course_list as $item) {
if (isset($course_id) && !empty($course_id)) {
if ($course_id != $item['id']) {
continue;
}
}
$list = new LearnpathList(
api_get_user_id(),
api_get_course_info($item['code']),
$session_id
);
$flat_list = $list->get_flat_list();
$lps[$item['code']] = $flat_list;
$item['title'] = Display::url(
$item['title'],
api_get_path(WEB_COURSE_PATH).$item['directory'].'/?id_session='.$session_id,
['target' => SESSION_LINK_TARGET]
);
foreach ($flat_list as $lp_id => $lp_item) {
$isAllowedToEdit = api_is_allowed_to_edit(null, true);
if (!$isAllowedToEdit && 0 == $lp_item['lp_visibility']) {
continue;
}
$temp[$count]['id'] = $lp_id;
$lp_url = api_get_path(WEB_CODE_PATH).'lp/lp_controller.php?cidReq='.$item['code'].'&id_session='.$session_id.'&lp_id='.$lp_id.'&action=view';
$last_date = Tracking::get_last_connection_date_on_the_course(
api_get_user_id(),
$item,
$session_id,
false
);
if (empty($lp_item['modified_on'])) {
$lp_date = api_get_local_time($lp_item['created_on']);
$image = 'new.gif';
$label = get_lang('LearnpathAdded');
} else {
$lp_date = api_get_local_time($lp_item['modified_on']);
$image = 'moderator_star.png';
$label = get_lang('LearnpathUpdated');
}
$icons = '';
if (strtotime($last_date) < strtotime($lp_date)) {
$icons = Display::return_icon($image, get_lang('TitleNotification').': '.$label.' - '.$lp_date);
}
if (!empty($lp_item['publicated_on'])) {
$date = substr($lp_item['publicated_on'], 0, 10);
} else {
$date = '-';
}
// Checking LP publicated and expired_on dates
if (!empty($lp_item['publicated_on'])) {
if ($now < api_strtotime($lp_item['publicated_on'], 'UTC')) {
continue;
}
}
if (!empty($lp_item['expired_on'])) {
if ($now > api_strtotime($lp_item['expired_on'], 'UTC')) {
continue;
}
}
$temp[$count]['cell'] = [
$date,
$item['title'],
Display::url($icons.' '.$lp_item['lp_name'], $lp_url, ['target' => SESSION_LINK_TARGET]),
];
$temp[$count]['course'] = strip_tags($item['title']);
$temp[$count]['lp'] = $lp_item['lp_name'];
$temp[$count]['date'] = $lp_item['publicated_on'];
$count++;
}
}
$temp = msort($temp, $sidx, $sord);
$response = new stdClass();
$i = 0;
foreach ($temp as $key => $row) {
$row = $row['cell'];
if (!empty($row)) {
if ($key >= $start && $key < ($start + $limit)) {
$response->rows[$i]['id'] = $key;
$response->rows[$i]['cell'] = [$row[0], $row[1], $row[2]];
$i++;
}
}
}
$total_pages = 0;
if ($count > 0 && $limit > 0) {
$total_pages = ceil($count / $limit);
}
$response->total = $total_pages;
$response->page = $page;
if ($page > $total_pages) {
$response->page = $total_pages;
}
$response->records = $count;
echo json_encode($response);
break;
case 'get_notification':
$courseId = isset($_REQUEST['course_id']) ? (int) $_REQUEST['course_id'] : 0;
$sessionId = isset($_REQUEST['session_id']) ? (int) $_REQUEST['session_id'] : 0;
$status = isset($_REQUEST['status']) ? (int) $_REQUEST['status'] : 0;
if (empty($courseId)) {
break;
}
require_once __DIR__.'/../global.inc.php';
$courseInfo = api_get_course_info_by_id($courseId);
$courseInfo['id_session'] = $sessionId;
$courseInfo['status'] = $status;
$id = 'notification_'.$courseId.'_'.$sessionId.'_'.$status;
$notificationId = Session::read($id);
if ($notificationId) {
echo Display::show_notification($courseInfo, false);
Session::erase($notificationId);
}
break;
default:
echo '';
}
exit;

View File

@@ -0,0 +1,27 @@
<?php
/* For licensing terms, see /license.txt */
use Symfony\Component\HttpFoundation\Request as HttpRequest;
use Symfony\Component\HttpFoundation\Response as HttpResponse;
require_once __DIR__.'/../global.inc.php';
$httpRequest = HttpRequest::createFromGlobals();
$action = $httpRequest->query->has('a') ? $httpRequest->query->get('a') : $httpRequest->request->get('a');
TrackingCourseLog::protectIfNotAllowed();
$courseInfo = api_get_course_info();
$sessionId = api_get_session_id();
$httpResponse = HttpResponse::create();
if ($action == 'graph') {
$content = TrackingCourseLog::returnCourseGraphicalReport($courseInfo, $sessionId);
$httpResponse->setContent($content);
}
$httpResponse->send();

View File

@@ -0,0 +1,302 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Responses to AJAX calls for the document upload.
*/
use Chamilo\CoreBundle\Component\Editor\Driver\Driver;
require_once __DIR__.'/../global.inc.php';
$action = $_REQUEST['a'];
switch ($action) {
case 'get_dir_size':
api_protect_course_script(true);
$path = $_GET['path'] ?? '';
$isAllowedToEdit = api_is_allowed_to_edit();
$size = DocumentManager::getTotalFolderSize($path, $isAllowedToEdit);
echo format_file_size($size);
break;
case 'get_dirs_size':
api_protect_course_script(true);
$requests = $_GET['requests'] ?? '';
$isAllowedToEdit = api_is_allowed_to_edit();
$response = [];
$requests = explode(',', $requests);
foreach ($requests as $request) {
$fileSize = DocumentManager::getTotalFolderSize($request, $isAllowedToEdit);
$data = [
'id' => $request,
'size' => format_file_size($fileSize),
];
$response[] = $data;
}
echo json_encode($response);
break;
case 'get_document_quota':
// Getting the course quota
$courseQuota = DocumentManager::get_course_quota();
// Calculating the total space
$total = DocumentManager::documents_total_space(api_get_course_int_id());
// Displaying the quota
echo DocumentManager::displaySimpleQuota($courseQuota, $total);
break;
case 'upload_file':
api_protect_course_script(true);
if (isset($_REQUEST['chunkAction']) && 'send' === $_REQUEST['chunkAction']) {
// It uploads the files in chunks
if (!empty($_FILES)) {
$tempDirectory = api_get_path(SYS_ARCHIVE_PATH);
$files = $_FILES['files'];
$fileList = [];
foreach ($files as $name => $array) {
$counter = 0;
foreach ($array as $data) {
$fileList[$counter][$name] = $data;
$counter++;
}
}
if (!empty($fileList)) {
foreach ($fileList as $n => $file) {
$tmpFile = disable_dangerous_file(
api_replace_dangerous_char($file['name'])
);
file_put_contents(
$tempDirectory.$tmpFile,
fopen($file['tmp_name'], 'r'),
FILE_APPEND
);
}
}
}
echo json_encode([
'files' => $_FILES,
'errorStatus' => 0,
]);
exit;
} else {
// User access same as upload.php
$is_allowed_to_edit = api_is_allowed_to_edit(null, true);
$sessionId = api_get_session_id();
if (!$is_allowed_to_edit && $sessionId && $_REQUEST['curdirpath'] == "/basic-course-documents__{$sessionId}__0") {
$session = SessionManager::fetch($sessionId);
if (!empty($session) && $session['session_admin_id'] == api_get_user_id()) {
$is_allowed_to_edit = true;
}
}
// This needs cleaning!
if (api_get_group_id()) {
$groupInfo = GroupManager::get_group_properties(api_get_group_id());
// Only course admin or group members allowed
if ($is_allowed_to_edit || GroupManager::is_user_in_group(api_get_user_id(), $groupInfo)) {
if (!GroupManager::allowUploadEditDocument(
api_get_user_id(),
api_get_course_int_id(),
$groupInfo
)) {
exit;
}
} else {
exit;
}
} elseif ($is_allowed_to_edit ||
DocumentManager::is_my_shared_folder(api_get_user_id(), $_REQUEST['curdirpath'], api_get_session_id())
) {
// ??
} else {
// No course admin and no group member...
exit;
}
$directoryParentId = isset($_POST['directory_parent_id']) ? (int) $_POST['directory_parent_id'] : 0;
$currentDirectory = '';
if (empty($directoryParentId)) {
$currentDirectory = $_REQUEST['curdirpath'] ?? '';
} else {
$documentData = DocumentManager::get_document_data_by_id($directoryParentId, api_get_course_id());
if ($documentData) {
$currentDirectory = $documentData['path'];
}
}
if (empty($currentDirectory)) {
$currentDirectory = DIRECTORY_SEPARATOR;
}
$ifExists = $_POST['if_exists'] ?? '';
$unzip = isset($_POST['unzip']) ? 1 : 0;
if (empty($ifExists)) {
$fileExistsOption = api_get_setting('document_if_file_exists_option');
$defaultFileExistsOption = 'rename';
if (!empty($fileExistsOption)) {
$defaultFileExistsOption = $fileExistsOption;
}
} else {
$defaultFileExistsOption = $ifExists;
}
if (!empty($_FILES)) {
$files = $_FILES['files'];
$fileList = [];
foreach ($files as $name => $array) {
$counter = 0;
foreach ($array as $data) {
$fileList[$counter][$name] = $data;
$counter++;
}
}
$resultList = [];
foreach ($fileList as $fileInfo) {
$file = processChunkedFile($fileInfo);
$globalFile = [];
$globalFile['files'] = $file;
$result = DocumentManager::upload_document(
$globalFile,
$currentDirectory,
'',
'', // comment
$unzip,
$defaultFileExistsOption,
false,
false,
'files'
);
$json = [];
if (!empty($result) && is_array($result)) {
$json['name'] = api_htmlentities($result['title']);
$json['link'] = Display::url(
api_htmlentities($result['title']),
api_htmlentities($result['url']),
['target' => '_blank']
);
$json['url'] = $result['url'];
$json['size'] = format_file_size($file['size']);
$json['type'] = api_htmlentities($file['type']);
$json['result'] = Display::return_icon(
'accept.png',
get_lang('Uploaded')
);
} else {
$json['name'] = $file['name'] ?? get_lang('Unknown');
$json['url'] = '';
$json['error'] = get_lang('Error');
}
$resultList[] = $json;
}
echo json_encode(['files' => $resultList]);
exit;
}
}
break;
case 'ck_uploadimage':
if (true !== api_get_configuration_value('enable_uploadimage_editor')) {
exit;
}
api_protect_course_script(true);
// it comes from uploaimage drag and drop ckeditor
$isCkUploadImage = ($_COOKIE['ckCsrfToken'] == $_POST['ckCsrfToken']);
if (!$isCkUploadImage) {
exit;
}
$data = [];
$fileUpload = $_FILES['upload'];
$mimeType = mime_content_type($fileUpload['tmp_name']);
$isMimeAccepted = (new Driver())->mimeAccepted($mimeType, ['image']);
if (!$isMimeAccepted) {
exit;
}
$isAllowedToEdit = api_is_allowed_to_edit(null, true);
if ($isAllowedToEdit) {
$globalFile = ['files' => $fileUpload];
$result = DocumentManager::upload_document(
$globalFile,
'/',
'',
'',
0,
'rename',
false,
false,
'files'
);
if (!$result) {
exit;
}
$relativeUrl = str_replace(api_get_path(WEB_PATH), '/', $result['direct_url']);
$data = [
'uploaded' => 1,
'fileName' => $fileUpload['name'],
'url' => $relativeUrl,
];
} else {
$userId = api_get_user_id();
$syspath = UserManager::getUserPathById($userId, 'system').'my_files';
if (!is_dir($syspath)) {
mkdir($syspath, api_get_permissions_for_new_directories(), true);
}
$webpath = UserManager::getUserPathById($userId, 'web').'my_files';
$fileUploadName = $fileUpload['name'];
if (file_exists($syspath.$fileUploadName)) {
$extension = pathinfo($fileUploadName, PATHINFO_EXTENSION);
$fileName = pathinfo($fileUploadName, PATHINFO_FILENAME);
$suffix = '_'.uniqid();
$fileUploadName = $fileName.$suffix.'.'.$extension;
}
$personalDriver = new PersonalDriver();
$uploadResult = $personalDriver->mimeAccepted(mime_content_type($fileUpload['tmp_name']), ['image']);
if (!$uploadResult || !move_uploaded_file($fileUpload['tmp_name'], $syspath.$fileUploadName)) {
exit;
}
$url = $webpath.$fileUploadName;
$relativeUrl = str_replace(api_get_path(WEB_PATH), '/', $url);
$data = [
'uploaded' => 1,
'fileName' => $fileUploadName,
'url' => $relativeUrl,
];
}
echo json_encode($data);
exit;
case 'document_preview':
$courseInfo = api_get_course_info_by_id($_REQUEST['course_id']);
if (!empty($courseInfo) && is_array($courseInfo)) {
echo DocumentManager::get_document_preview(
$courseInfo,
false,
'_blank',
$_REQUEST['session_id']
);
}
break;
case 'document_destination':
//obtained the bootstrap-select selected value via ajax
$dirValue = $_POST['dirValue'] ?? null;
echo Security::remove_XSS($dirValue);
break;
}
exit;

View File

@@ -0,0 +1,120 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Responses to AJAX calls for the document upload.
*/
require_once __DIR__.'/../global.inc.php';
require_once api_get_path(SYS_CODE_PATH).'dropbox/dropbox_functions.inc.php';
$action = $_REQUEST['a'];
switch ($action) {
case 'upload_file':
api_protect_course_script(true);
if (isset($_REQUEST['chunkAction']) && 'send' === $_REQUEST['chunkAction']) {
// It uploads the files in chunks
if (!empty($_FILES)) {
$tempDirectory = api_get_path(SYS_ARCHIVE_PATH);
$files = $_FILES['files'];
$fileList = [];
foreach ($files as $name => $array) {
$counter = 0;
foreach ($array as $data) {
$fileList[$counter][$name] = $data;
$counter++;
}
}
if (!empty($fileList)) {
foreach ($fileList as $n => $file) {
$tmpFile = disable_dangerous_file(
api_replace_dangerous_char($file['name'])
);
file_put_contents(
$tempDirectory.$tmpFile,
fopen($file['tmp_name'], 'r'),
FILE_APPEND
);
}
}
}
echo json_encode([
'files' => $_FILES,
'errorStatus' => 0,
]);
exit;
} else {
// User access same as upload.php
$is_allowed_to_edit = api_is_allowed_to_edit(null, true);
$recipients = isset($_POST['recipients']) ? $_POST['recipients'] : '';
$id = isset($_GET['id']) ? (int) $_GET['id'] : 0;
if (empty($recipients) && empty($id)) {
$resultList[] = ['error' => get_lang('YouMustSelectAtLeastOneDestinee')];
echo json_encode(['files' => $resultList]);
exit;
}
$work = null;
if (!empty($id)) {
$work = new Dropbox_SentWork($id);
if (empty($work)) {
$resultList[] = ['error' => get_lang('Error')];
echo json_encode(['files' => $resultList]);
exit;
}
}
if (!empty($_FILES)) {
$files = $_FILES['files'];
$fileList = [];
foreach ($files as $name => $array) {
$counter = 0;
foreach ($array as $data) {
$fileList[$counter][$name] = $data;
$counter++;
}
}
$resultList = [];
foreach ($fileList as $fileInfo) {
$file = processChunkedFile($fileInfo);
$globalFile = [];
$globalFile['files'] = $file;
/** @var Dropbox_SentWork $result */
$result = store_add_dropbox($file, $work);
$json = [];
if (!empty($result)) {
$json['name'] = Display::url(
api_htmlentities($result->title),
api_htmlentities(api_get_path(WEB_CODE_PATH).'dropbox/index.php?'.api_get_cidreq()),
['target' => '_blank']
);
$json['url'] = api_get_path(WEB_CODE_PATH).'dropbox/index.php?'.api_get_cidreq();
$json['size'] = format_file_size($result->filesize);
$json['type'] = api_htmlentities($file['type']);
$json['result'] = Display::return_icon(
'accept.png',
get_lang('Uploaded')
);
} else {
$json['result'] = Display::return_icon(
'exclamation.png',
get_lang('Error')
);
}
$resultList[] = $json;
}
echo json_encode(['files' => $resultList]);
exit;
}
}
break;
}
exit;

View File

@@ -0,0 +1,25 @@
<?php
/* For licensing terms, see /license.txt */
require_once __DIR__.'/../global.inc.php';
$id = isset($_REQUEST['id']) ? $_REQUEST['id'] : null;
$action = isset($_REQUEST['action']) ? $_REQUEST['action'] : null;
$event_name = isset($_REQUEST['eventName']) ? $_REQUEST['eventName'] : null;
api_protect_admin_script();
switch ($action) {
case 'getEventTypes':
$events = Event::get_all_event_types();
echo json_encode($events);
break;
case 'getUsers':
$users = UserManager::get_user_list();
echo json_encode($users);
break;
case 'get_event_users':
$users = Event::get_event_users($event_name);
echo json_encode($users);
break;
}
exit;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,185 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CoreBundle\Entity\Tag;
require_once __DIR__.'/../global.inc.php';
$action = isset($_GET['a']) ? $_GET['a'] : '';
$type = isset($_REQUEST['type']) ? $_REQUEST['type'] : null;
$fieldId = isset($_REQUEST['field_id']) ? $_REQUEST['field_id'] : null;
switch ($action) {
case 'delete_file':
api_protect_admin_script();
$itemId = isset($_REQUEST['item_id']) ? $_REQUEST['item_id'] : null;
$extraFieldValue = new ExtraFieldValue($type);
$data = $extraFieldValue->get_values_by_handler_and_field_id($itemId, $fieldId);
if (!empty($data) && isset($data['id']) && !empty($data['value'])) {
$extraFieldValue->deleteValuesByHandlerAndFieldAndValue($itemId, $data['field_id'], $data['value']);
echo 1;
break;
}
echo 0;
break;
case 'get_second_select_options':
$option_value_id = isset($_REQUEST['option_value_id']) ? $_REQUEST['option_value_id'] : null;
if (!empty($type) && !empty($fieldId) && !empty($option_value_id)) {
$field_options = new ExtraFieldOption($type);
echo $field_options->get_second_select_field_options_by_field(
$option_value_id,
true
);
}
break;
case 'search_tags':
header('Content-Type: application/json');
$tag = $_REQUEST['q'] ?? null;
$pageLimit = isset($_REQUEST['page_limit']) ? (int) $_REQUEST['page_limit'] : 10;
$byId = !empty($_REQUEST['byid']);
$result = [];
if (empty($tag)) {
echo json_encode(['items' => $result]);
exit;
}
$tagRepo = Database::getManager()->getRepository(Tag::class);
if ('portfolio' === $type) {
$tags = $tagRepo
->findForPortfolioInCourseQuery(
api_get_course_entity(),
api_get_session_entity()
)
->getQuery()
->getResult();
} else {
$tags = $tagRepo->findByFieldIdAndText($fieldId, $tag, $pageLimit);
}
/** @var Tag $tag */
foreach ($tags as $tag) {
$result[] = [
'id' => $byId ? $tag->getId() : $tag->getTag(),
'text' => $tag->getTag(),
];
}
echo json_encode(['items' => $result]);
break;
case 'search_options_from_tags':
$type = isset($_REQUEST['type']) ? $_REQUEST['type'] : null;
$fieldId = isset($_REQUEST['field_id']) ? $_REQUEST['field_id'] : null;
$tag = isset($_REQUEST['tag']) ? $_REQUEST['tag'] : null;
$extraFieldOption = new ExtraFieldOption($type);
$from = isset($_REQUEST['from']) ? $_REQUEST['from'] : '';
$search = isset($_REQUEST['search']) ? $_REQUEST['search'] : '';
$options = isset($_REQUEST['options']) ? json_decode($_REQUEST['options']) : '';
$extraField = new ExtraField('session');
$result = $extraField->searchOptionsFromTags($from, $search, $options);
$options = [];
$groups = [];
foreach ($result as $data) {
// Try to get the translation
$displayText = $data['display_text'];
$valueToTranslate = str_replace('-', '', $data['value']);
$valueTranslated = str_replace(['[=', '=]'], '', get_lang($valueToTranslate));
if ($valueToTranslate != $valueTranslated) {
$displayText = $valueTranslated;
}
$groups[$displayText][] = [
'id' => $data['id'],
'text' => $data['tag'],
];
}
foreach ($groups as $key => $data) {
$options[] = [
'text' => $key,
'children' => $groups[$key],
];
}
echo json_encode($options);
break;
case 'order':
$variable = isset($_REQUEST['field_variable']) ? $_REQUEST['field_variable'] : '';
$save = isset($_REQUEST['save']) ? $_REQUEST['save'] : '';
$values = isset($_REQUEST['values']) ? json_decode($_REQUEST['values']) : '';
$extraField = new ExtraField('session');
$extraFieldInfo = $extraField->get_handler_field_info_by_field_variable(str_replace('extra_', '', $variable));
$em = Database::getManager();
$search = [
'user' => api_get_user_id(),
'field' => $extraFieldInfo['id'],
];
$extraFieldSavedSearch = $em->getRepository('ChamiloCoreBundle:ExtraFieldSavedSearch')->findOneBy($search);
if ($save) {
$extraField = new \Chamilo\CoreBundle\Entity\ExtraFieldSavedSearch('session');
if ($extraFieldSavedSearch) {
$extraFieldSavedSearch->setValue($values);
$em->merge($extraFieldSavedSearch);
$em->flush();
}
}
if ($extraFieldInfo) {
/** @var \Chamilo\CoreBundle\Entity\ExtraFieldSavedSearch $options */
$extraFieldSavedSearch = $em->getRepository('ChamiloCoreBundle:ExtraFieldSavedSearch')->findOneBy($search);
$values = $extraFieldSavedSearch->getValue();
$url = api_get_self().'?a=order&save=1&field_variable='.$variable;
$html = '
<script>
$(function() {
$( "#sortable" ).sortable();
$( "#sortable" ).disableSelection();
$( "#link_'.$variable.'" ).on("click", function() {
var newList = [];
$("#sortable").find("li").each(function(){
newList.push($(this).text());
});
var save = JSON.stringify(newList);
$.ajax({
url: "'.$url.'",
dataType: "json",
data: "values="+save,
success: function(data) {
}
});
alert("'.get_lang('Saved').'");
location.reload();
return false;
});
});
</script>';
$html .= '<ul id="sortable">';
foreach ($values as $value) {
$html .= '<li class="ui-state-default">';
$html .= $value;
$html .= '</li>';
}
$html .= '</ul>';
$html .= Display::url(get_lang('Save'), '#', ['id' => 'link_'.$variable, 'class' => 'btn btn-primary']);
echo $html;
}
break;
default:
exit;
break;
}
exit;

View File

@@ -0,0 +1,21 @@
<?php
/* For licensing terms, see /license.txt */
require_once __DIR__.'/../global.inc.php';
$action = isset($_REQUEST['a']) ? $_REQUEST['a'] : null;
switch ($action) {
case 'get_captcha':
header('Content-Type: image/jpeg');
$sessionVar = empty($_REQUEST['var']) ? '_HTML_QuickForm_CAPTCHA' : $_REQUEST['var'];
if (isset($_SESSION[$sessionVar]) && !empty($_SESSION[$sessionVar])) {
$obj = $_SESSION[$sessionVar];
// Force a new CAPTCHA for each one displayed/** @var Text_CAPTCHA $obj */;
$obj->generate(true);
echo $image = $obj->getCAPTCHA();
}
exit;
break;
}

View File

@@ -0,0 +1,204 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CourseBundle\Entity\CForumPost;
/**
* Responses to AJAX calls for forum attachments.
*
* @package chamilo/forum
*
* @author Daniel Barreto Alva <daniel.barreto@beeznest.com>
*/
require_once __DIR__.'/../global.inc.php';
require_once api_get_path(SYS_CODE_PATH).'forum/forumfunction.inc.php';
// First, protect this script
api_protect_course_script(false);
$action = isset($_REQUEST['a']) ? $_REQUEST['a'] : null;
// Create a default error response
$json = [
'error' => true,
'errorMessage' => 'ERROR',
];
// Check if exist action
if (!empty($action)) {
switch ($action) {
case 'upload_file':
$current_forum = get_forum_information($_REQUEST['forum']);
$current_forum_category = get_forumcategory_information($current_forum['forum_category']);
$current_thread = get_thread_information($_REQUEST['forum'], $_REQUEST['thread']);
if (!empty($_FILES) && !empty($_REQUEST['forum'])) {
// The user is not allowed here if
// 1. the forum category, forum or thread is invisible (visibility==0)
// 2. the forum category, forum or thread is locked (locked <>0)
// 3. if anonymous posts are not allowed
// The only exception is the course manager
// They are several pieces for clarity.
if (!api_is_allowed_to_edit(null, true) &&
(
($current_forum_category && $current_forum_category['visibility'] == 0) ||
$current_forum['visibility'] == 0
)
) {
$json['errorMessage'] = '1. the forum category, forum or thread is invisible (visibility==0)';
break;
}
if (!api_is_allowed_to_edit(null, true) &&
(
($current_forum_category && $current_forum_category['locked'] != 0) ||
$current_forum['locked'] != 0 || $current_thread['locked'] != 0
)
) {
$json['errorMessage'] = '2. the forum category, forum or thread is locked (locked <>0)';
break;
}
if (api_is_anonymous() && $current_forum['allow_anonymous'] == 0) {
$json['errorMessage'] = '3. if anonymous posts are not allowed';
break;
}
// If pass all previous control, user can edit post
$courseId = isset($_REQUEST['c_id']) ? intval($_REQUEST['c_id']) : api_get_course_int_id();
$json['courseId'] = $courseId;
$forumId = isset($_REQUEST['forum']) ? intval($_REQUEST['forum']) : null;
$json['forum'] = $forumId;
$threadId = isset($_REQUEST['thread']) ? intval($_REQUEST['thread']) : null;
$json['thread'] = $threadId;
$postId = isset($_REQUEST['postId']) ? intval($_REQUEST['postId']) : null;
$json['postId'] = $postId;
if (!empty($courseId) &&
!is_null($forumId) &&
!is_null($threadId) &&
!is_null($postId)
) {
// Save forum attachment
$attachId = add_forum_attachment_file('', $postId);
if ($attachId !== false) {
// Get prepared array of attachment data
$array = getAttachedFiles(
$forumId,
$threadId,
$postId,
$attachId,
$courseId
);
// Check if array data is consistent
if (isset($array['name'])) {
$json['error'] = false;
$json['errorMessage'] = 'Success';
$json = array_merge($json, $array);
}
}
}
}
echo json_encode($json);
break;
case 'delete_file':
$current_forum = get_forum_information($_REQUEST['forum']);
$current_forum_category = get_forumcategory_information($current_forum['forum_category']);
$current_thread = get_thread_information($_REQUEST['forum'], $_REQUEST['thread']);
// Check if set attachment ID and thread ID
if (isset($_REQUEST['attachId']) && isset($_REQUEST['thread'])) {
api_block_course_item_locked_by_gradebook($_REQUEST['thread'], LINK_FORUM_THREAD);
// The user is not allowed here if
// 1. the forum category, forum or thread is invisible (visibility==0)
// 2. the forum category, forum or thread is locked (locked <>0)
// 3. if anonymous posts are not allowed
// 4. if editing of replies is not allowed
// The only exception is the course manager
// They are several pieces for clarity.
if (!api_is_allowed_to_edit(null, true) &&
(
($current_forum_category && $current_forum_category['visibility'] == 0) ||
$current_forum['visibility'] == 0
)
) {
$json['errorMessage'] = '1. the forum category, forum or thread is invisible (visibility==0)';
break;
}
if (!api_is_allowed_to_edit(null, true) &&
(
($current_forum_category && $current_forum_category['locked'] != 0) ||
$current_forum['locked'] != 0 || $current_thread['locked'] != 0
)
) {
$json['errorMessage'] = '2. the forum category, forum or thread is locked (locked <>0)';
break;
}
if (api_is_anonymous() && $current_forum['allow_anonymous'] == 0) {
$json['errorMessage'] = '3. if anonymous posts are not allowed';
break;
}
$group_id = api_get_group_id();
$groupInfo = GroupManager::get_group_properties($group_id);
if (!api_is_allowed_to_edit(null, true) &&
$current_forum['allow_edit'] == 0 &&
($group_id && !GroupManager::is_tutor_of_group(api_get_user_id(), $groupInfo))
) {
$json['errorMessage'] = '4. if editing of replies is not allowed';
break;
}
// If pass all previous control, user can edit post
$attachId = $_REQUEST['attachId'];
$threadId = $_REQUEST['thread'];
// Delete forum attachment from database and file system
$affectedRows = delete_attachment(0, $attachId, false);
if ($affectedRows > 0) {
$json['error'] = false;
$json['errorMessage'] = 'Success';
}
}
echo json_encode($json);
break;
case 'change_post_status':
if (api_is_allowed_to_edit(false, true)) {
$postId = isset($_GET['post_id']) ? $_GET['post_id'] : '';
if (empty($postId)) {
exit;
}
$postId = str_replace('status_post_', '', $postId);
$em = Database::getManager();
/** @var CForumPost $post */
$post = $em->find('ChamiloCourseBundle:CForumPost', $postId);
if ($post) {
$forum = get_forums($post->getForumId(), api_get_course_id());
$status = $post->getStatus();
if (empty($status)) {
$status = CForumPost::STATUS_WAITING_MODERATION;
}
switch ($status) {
case CForumPost::STATUS_VALIDATED:
$changeTo = CForumPost::STATUS_REJECTED;
break;
case CForumPost::STATUS_WAITING_MODERATION:
$changeTo = CForumPost::STATUS_VALIDATED;
break;
case CForumPost::STATUS_REJECTED:
$changeTo = CForumPost::STATUS_WAITING_MODERATION;
break;
}
$post->setStatus($changeTo);
$em->persist($post);
$em->flush();
echo getPostStatus(
$forum,
[
'iid' => $post->getIid(),
'status' => $post->getStatus(),
],
false
);
}
}
break;
}
}
exit;

View File

@@ -0,0 +1,100 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Responses to AJAX calls.
*/
require_once __DIR__.'/../global.inc.php';
api_protect_course_script(true);
$action = $_REQUEST['a'];
switch ($action) {
case 'add_gradebook_comment':
if (true !== api_get_configuration_value('allow_gradebook_comments')) {
exit;
}
if (api_is_allowed_to_edit(null, true)) {
$userId = $_REQUEST['user_id'] ?? 0;
$gradeBookId = $_REQUEST['gradebook_id'] ?? 0;
$comment = $_REQUEST['comment'] ?? '';
GradebookUtils::saveComment($gradeBookId, $userId, $comment);
echo 1;
exit;
}
echo 0;
break;
case 'get_gradebook_weight':
if (api_is_allowed_to_edit(null, true)) {
$cat_id = $_GET['cat_id'];
$cat = Category::load($cat_id);
if ($cat && isset($cat[0])) {
echo $cat[0]->get_weight();
} else {
echo 0;
}
}
break; /*
case 'generate_custom_report':
if (api_is_allowed_to_edit(null, true)) {
$allow = api_get_configuration_value('gradebook_custom_student_report');
if (!$allow) {
exit;
}
$form = new FormValidator(
'search',
'get',
api_get_path(WEB_CODE_PATH).'gradebook/index.php?'.api_get_cidreq().'&action=generate_custom_report'
);
$form->addText('custom_course_id', get_lang('CourseId'));
$form->addDateRangePicker('range', get_lang('DateRange'));
$form->addHidden('action', 'generate_custom_report');
$form->addButtonSearch();
$form->display();
}
break;*/
case 'export_all_certificates':
$categoryId = (int) $_GET['cat_id'];
$filterOfficialCodeGet = isset($_GET['filter']) ? Security::remove_XSS($_GET['filter']) : null;
if (api_is_student_boss()) {
$userGroup = new UserGroup();
$userList = $userGroup->getGroupUsersByUser(api_get_user_id());
} else {
$userList = [];
if (!empty($filterOfficialCodeGet)) {
$userList = UserManager::getUsersByOfficialCode($filterOfficialCodeGet);
}
}
$courseCode = api_get_course_id();
$sessionId = api_get_session_id();
$commandScript = api_get_path(SYS_CODE_PATH).'gradebook/cli/export_all_certificates.php';
$userList = implode(',', $userList);
shell_exec("php $commandScript $courseCode $sessionId $categoryId $userList > /dev/null &");
break;
case 'verify_export_all_certificates':
$categoryId = (int) $_GET['cat_id'];
$courseCode = isset($_GET['cidReq']) ? Security::remove_XSS($_GET['cidReq']) : api_get_course_id();
$sessionId = isset($_GET['id_session']) ? (int) $_GET['id_session'] : api_get_session_id();
$date = api_get_utc_datetime(null, false, true);
$pdfName = 'certs_'.$courseCode.'_'.$sessionId.'_'.$categoryId.'_'.$date->format('Y-m-d');
$sysFinalFile = api_get_path(SYS_ARCHIVE_PATH)."$pdfName.pdf";
$webFinalFile = api_get_path(WEB_ARCHIVE_PATH)."$pdfName.pdf";
if (file_exists($sysFinalFile)) {
echo $webFinalFile;
}
break;
default:
echo '';
break;
}
exit;

View File

@@ -0,0 +1,27 @@
<?php
/* For licensing terms, see /license.txt */
require_once __DIR__.'/../global.inc.php';
$action = isset($_REQUEST['a']) ? $_REQUEST['a'] : '';
$isAllowedToEdit = api_is_allowed_to_edit();
switch ($action) {
case 'search':
if ($isAllowedToEdit) {
$groups = GroupManager::getGroupListFilterByName($_REQUEST['q'], null, api_get_course_int_id());
$list = [];
foreach ($groups as $group) {
$list[] = [
'id' => $group['iid'],
'text' => $group['name'],
];
}
echo json_encode(['items' => $list]);
}
break;
default:
break;
}
exit;

6
main/inc/ajax/index.html Normal file
View File

@@ -0,0 +1,6 @@
<html>
<head>
</head>
<body>
</body>
</html>

View File

@@ -0,0 +1,86 @@
<?php
/* For licensing terms, see /license.txt */
use GuzzleHttp\Client;
/**
* Responses to AJAX calls for install.
*/
require_once __DIR__.'/../../../vendor/autoload.php';
$action = $_GET['a'];
switch ($action) {
case 'send_contact_information':
if (!empty($_POST)) {
// get params from contact form
$person_name = $_POST['person_name'];
$person_email = $_POST['person_email'];
$person_role = $_POST['person_role'];
$financial_decision = $_POST['financial_decision'];
$contact_language = $_POST['language'];
$company_name = $_POST['company_name'];
$company_activity = $_POST['company_activity'];
$company_country = $_POST['company_country'];
$company_city = $_POST['company_city'];
// validating required fields
$a_required_fields = [$person_name, $person_role, $company_name, $company_activity, $company_country];
$required_field_error = false;
foreach ($a_required_fields as $required_file) {
if (trim($required_file) === '') {
$required_field_error = true;
break;
}
}
// Return error if any of the required fields is empty
if ($required_field_error) {
echo 'required_field_error';
break;
} else {
// save contact information with web service
// create a client
$url = 'https://version.chamilo.org/contactv2.php';
$options = [
'verify' => false,
];
$urlValidated = false;
try {
$client = new GuzzleHttp\Client();
$res = $client->request('GET', $url, $options);
if ($res->getStatusCode() == '200' || $res->getStatusCode() == '301') {
$urlValidated = true;
}
} catch (Exception $e) {
error_log("Could not check $url from ".__FILE__);
break;
}
$data = [
'person_name' => $person_name,
'person_email' => $person_email,
'person_role' => $person_role,
'financial_decision' => $financial_decision,
'contact_language' => $contact_language,
'company_name' => $company_name,
'company_activity' => $company_activity,
'company_country' => $company_country,
'company_city' => $company_city,
];
$client = new GuzzleHttp\Client();
$options['query'] = $data;
$res = $client->request('GET', $url, $options);
if ($res->getStatusCode() == '200') {
echo '1';
}
}
}
break;
default:
echo '';
}
exit;

View File

@@ -0,0 +1,81 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Responses to AJAX calls.
*/
require_once __DIR__.'/../global.inc.php';
api_protect_course_script(true);
$action = $_REQUEST['a'];
switch ($action) {
case 'translate_html':
header('Content-type: application/x-javascript');
echo api_get_language_translate_html();
break;
case 'translate_portfolio_category':
if (false === Security::check_token('get')) {
exit;
}
Security::clear_token();
if (isset($_REQUEST['new_language']) && isset($_REQUEST['variable_language']) && isset($_REQUEST['category_id'])) {
$newLanguage = Security::remove_XSS($_REQUEST['new_language']);
$langVariable = ltrim(
Security::remove_XSS($_REQUEST['variable_language']),
'$'
);
$categoryId = (int) $_REQUEST['category_id'];
$languageId = (int) $_REQUEST['id'];
$subLanguageId = (int) $_REQUEST['sub'];
$langFilesToLoad = SubLanguageManager::get_lang_folder_files_list(
api_get_path(SYS_LANG_PATH).'english',
true
);
$fileLanguage = $langFilesToLoad[0].'.inc.php';
$allDataOfLanguage = SubLanguageManager::get_all_information_of_sub_language($languageId, $subLanguageId);
$pathFolder = api_get_path(SYS_LANG_PATH).$allDataOfLanguage['dokeos_folder'].'/'.$fileLanguage;
$allFileOfDirectory = SubLanguageManager::get_all_language_variable_in_file($pathFolder);
$returnValue = SubLanguageManager::add_file_in_language_directory($pathFolder);
//update variable language
$allFileOfDirectory[$langVariable] = $newLanguage;
$resultArray = [];
foreach ($allFileOfDirectory as $key => $value) {
$resultArray[$key] = SubLanguageManager::write_data_in_file($pathFolder, $value, $key);
}
$variablesWithProblems = '';
if (!empty($resultArray)) {
foreach ($resultArray as $key => $result) {
if ($result == false) {
$variablesWithProblems .= $key.' <br />';
}
}
}
if (isset($_REQUEST['redirect'])) {
$message = Display::return_message(get_lang('TheNewWordHasBeenAdded'), 'success');
if (!empty($variablesWithProblems)) {
$message = Display::return_message(
$pathFolder.' '.get_lang('IsNotWritable').'<br /> '.api_ucwords(get_lang('ErrorsFound'))
.': <br />'.$variablesWithProblems,
'error'
);
}
Display::addFlash($message);
header('Location: '.api_get_path(WEB_CODE_PATH).'portfolio/index.php?'.api_get_cidreq().'&action=translate_category&id='.$categoryId.'&sub_language='.$subLanguageId);
exit;
}
}
break;
default:
echo '';
}
exit;

View File

@@ -0,0 +1,39 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Responses to AJAX calls.
*/
require_once __DIR__.'/../global.inc.php';
api_protect_course_script(true);
$action = $_REQUEST['a'];
switch ($action) {
case 'check_url':
if (api_is_allowed_to_edit(null, true)) {
$url = $_REQUEST['url'];
$result = \Link::checkUrl($url);
if ($result) {
echo Display::return_icon(
'check-circle.png',
get_lang('Ok'),
null,
ICON_SIZE_TINY
);
} else {
echo Display::return_icon(
'closed-circle.png',
get_lang('Wrong'),
null,
ICON_SIZE_TINY
);
}
}
break;
default:
echo '';
}
exit;

331
main/inc/ajax/lp.ajax.php Normal file
View File

@@ -0,0 +1,331 @@
<?php
/* For licensing terms, see /license.txt */
use ChamiloSession as Session;
/**
* Responses to AJAX calls.
*/
require_once __DIR__.'/../global.inc.php';
api_protect_course_script(true);
$debug = false;
$action = isset($_REQUEST['a']) ? $_REQUEST['a'] : '';
$courseId = api_get_course_int_id();
$sessionId = api_get_session_id();
if ($debug) {
error_log('----------lp.ajax-------------- action '.$action);
}
// We check if a tool provider
if (isset($_REQUEST['lti_launch_id'])) {
$ltiLaunchId = Security::remove_XSS($_REQUEST['lti_launch_id']);
$_SESSION['oLP']->lti_launch_id = $ltiLaunchId;
}
switch ($action) {
case 'get_lp_list_by_course':
$course_id = (isset($_GET['course_id']) && !empty($_GET['course_id'])) ? (int) $_GET['course_id'] : 0;
$session_id = (isset($_GET['session_id']) && !empty($_GET['session_id'])) ? (int) $_GET['session_id'] : 0;
$onlyActiveLp = !(api_is_platform_admin(true) || api_is_course_admin());
$results = learnpath::getLpList($course_id, $session_id, $onlyActiveLp);
$data = [];
if (!empty($results)) {
foreach ($results as $lp) {
$data[] = ['id' => $lp['id'], 'text' => html_entity_decode($lp['name'])];
}
}
echo json_encode($data);
break;
case 'get_documents':
$courseInfo = api_get_course_info();
$folderId = $_GET['folder_id'] ?? false;
if (empty($folderId)) {
exit;
}
$lpId = isset($_GET['lp_id']) ? $_GET['lp_id'] : false;
$url = isset($_GET['url']) ? $_GET['url'] : '';
$addMove = isset($_GET['add_move_button']) && $_GET['add_move_button'] == 1 ? true : false;
$showOnlyFolders = false;
if (isset($_GET['showOnlyFolders'])) {
$showOnlyFolders = (1 == (int) $_GET['showOnlyFolders']);
}
echo DocumentManager::get_document_preview(
$courseInfo,
$lpId,
null,
api_get_session_id(),
$addMove,
null,
$url,
true,
$showOnlyFolders,
$folderId,
false
);
break;
case 'add_lp_item':
if (api_is_allowed_to_edit(null, true)) {
/** @var learnpath $learningPath */
$learningPath = Session::read('oLP');
if ($learningPath) {
// Updating the lp.modified_on
$learningPath->set_modified_on();
$title = $_REQUEST['title'];
if ($_REQUEST['type'] == TOOL_QUIZ) {
$title = Exercise::format_title_variable($title);
}
$parentId = isset($_REQUEST['parent_id']) ? $_REQUEST['parent_id'] : '';
$previousId = isset($_REQUEST['previous_id']) ? $_REQUEST['previous_id'] : '';
$itemId = $learningPath->add_item(
$parentId,
$previousId,
$_REQUEST['type'],
$_REQUEST['id'],
$title,
null
);
/** @var learnpath $learningPath */
$learningPath = Session::read('oLP');
if ($learningPath) {
echo $learningPath->returnLpItemList(null);
}
}
}
break;
case 'update_lp_item_order':
if (api_is_allowed_to_edit(null, true)) {
// $new_order gets a value like "647|0^648|0^649|0^"
$new_order = $_POST['new_order'];
$sections = explode('^', $new_order);
$sections = array_filter($sections);
$orderList = [];
foreach ($sections as $items) {
[$id, $parentId] = explode('|', $items);
$orderList[$id] = $parentId;
}
learnpath::sortItemByOrderList($orderList);
echo Display::return_message(get_lang('Saved'), 'confirm');
}
break;
case 'record_audio':
if (api_is_allowed_to_edit(null, true) == false) {
exit;
}
/** @var Learnpath $lp */
$lp = Session::read('oLP');
$course_info = api_get_course_info();
$lpPathInfo = $lp->generate_lp_folder($course_info);
if (empty($lpPathInfo)) {
exit;
}
foreach (['video', 'audio'] as $type) {
if (isset($_FILES["${type}-blob"])) {
$fileName = $_POST["${type}-filename"];
$file = $_FILES["${type}-blob"];
$title = $_POST['audio-title'];
$fileInfo = pathinfo($fileName);
//$file['name'] = 'rec_'.date('Y-m-d_His').'_'.uniqid().'.'.$fileInfo['extension'];
$file['name'] = $title.'.'.$fileInfo['extension'];
$file['file'] = $file;
$result = DocumentManager::upload_document(
$file,
'/audio',
$file['name'],
null,
0,
'overwrite',
false,
false
);
if (!empty($result) && is_array($result)) {
$newDocId = $result['id'];
$courseId = $result['c_id'];
$lp->set_modified_on();
$lpItem = new learnpathItem($_REQUEST['lp_item_id']);
$lpItem->add_audio_from_documents($newDocId);
$data = DocumentManager::get_document_data_by_id($newDocId, $course_info['code']);
echo $data['document_url'];
exit;
}
}
}
break;
case 'get_forum_thread':
$lpId = isset($_GET['lp']) ? intval($_GET['lp']) : 0;
$lpItemId = isset($_GET['lp_item']) ? intval($_GET['lp_item']) : 0;
$sessionId = api_get_session_id();
if (empty($lpId) || empty($lpItemId)) {
echo json_encode([
'error' => true,
]);
break;
}
$learningPath = learnpath::getLpFromSession(
api_get_course_id(),
$lpId,
api_get_user_id()
);
$lpItem = $learningPath->getItem($lpItemId);
if (empty($lpItem)) {
echo json_encode([
'error' => true,
]);
break;
}
$lpHasForum = $learningPath->lpHasForum();
if (!$lpHasForum) {
echo json_encode([
'error' => true,
]);
break;
}
$forum = $learningPath->getForum($sessionId);
if (empty($forum)) {
require_once '../../forum/forumfunction.inc.php';
$forumCategory = getForumCategoryByTitle(
get_lang('LearningPaths'),
$courseId,
$sessionId
);
if (empty($forumCategory)) {
$forumCategoryId = store_forumcategory(
[
'lp_id' => 0,
'forum_category_title' => get_lang('LearningPaths'),
'forum_category_comment' => null,
],
[],
false
);
} else {
$forumCategoryId = $forumCategory['cat_id'];
}
$forumId = $learningPath->createForum($forumCategoryId);
} else {
$forumId = $forum['forum_id'];
}
$lpItemHasThread = $lpItem->lpItemHasThread($courseId);
if (!$lpItemHasThread) {
echo json_encode([
'error' => true,
]);
break;
}
$forumThread = $lpItem->getForumThread($courseId, $sessionId);
if (empty($forumThread)) {
$lpItem->createForumThread($forumId);
$forumThread = $lpItem->getForumThread($courseId, $sessionId);
}
$forumThreadId = $forumThread['thread_id'];
echo json_encode([
'error' => false,
'forumId' => intval($forum['forum_id']),
'threadId' => intval($forumThreadId),
]);
break;
case 'update_gamification':
$lp = Session::read('oLP');
$jsonGamification = [
'stars' => 0,
'score' => 0,
];
if ($lp) {
$score = $lp->getCalculateScore($sessionId);
$jsonGamification['stars'] = $lp->getCalculateStars($sessionId);
$jsonGamification['score'] = sprintf(get_lang('XPoints'), $score);
}
echo json_encode($jsonGamification);
break;
case 'check_item_position':
$lp = Session::read('oLP');
$lpItemId = isset($_GET['lp_item']) ? intval($_GET['lp_item']) : 0;
if ($lp) {
$position = $lp->isFirstOrLastItem($lpItemId);
echo json_encode($position);
}
break;
case 'get_parent_names':
$newItemId = isset($_GET['new_item']) ? intval($_GET['new_item']) : 0;
if (!$newItemId) {
break;
}
/** @var \learnpath $lp */
$lp = Session::read('oLP');
$parentNames = $lp->getCurrentItemParentNames($newItemId);
$response = '';
foreach ($parentNames as $parentName) {
$response .= '<p class="h5 hidden-xs hidden-md">'.$parentName.'</p>';
}
echo $response;
break;
case 'get_item_prerequisites':
/** @var learnpath $lp */
$lp = Session::read('oLP');
$itemId = isset($_GET['item_id']) ? (int) $_GET['item_id'] : 0;
if (empty($lp) || empty($itemId)) {
exit;
}
if ($lp->debug) {
error_log('--------------------------------------');
error_log('get_item_prerequisites');
}
$result = $lp->prerequisites_match($itemId);
if ($result) {
echo '1';
} else {
if (!empty($lp->error)) {
echo $lp->error;
} else {
echo get_lang('LearnpathPrereqNotCompleted');
}
}
$lp->error = '';
exit;
break;
default:
echo '';
}

View File

@@ -0,0 +1,29 @@
<?php
/* For licensing terms, see /license.txt */
require_once __DIR__.'/../global.inc.php';
api_protect_admin_script();
$action = isset($_REQUEST['a']) ? $_REQUEST['a'] : null;
switch ($action) {
case 'select_option':
$id = isset($_REQUEST['id']) ? $_REQUEST['id'] : null;
if (!empty($id)) {
$mail = new MailTemplateManager();
$item = $mail->get($id);
echo $item['template'];
} else {
$templateName = isset($_REQUEST['template_name']) ? $_REQUEST['template_name'] : null;
if (!empty($templateName)) {
$templatePath = api_get_path(SYS_CODE_PATH).'template/default/mail/';
if (Security::check_abs_path($templatePath.$templateName, $templatePath)) {
if (file_exists($templatePath.$templateName)) {
echo file_get_contents($templatePath.$templateName);
}
}
}
}
break;
}

View File

@@ -0,0 +1,170 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\UserBundle\Entity\User;
$_dont_save_user_course_access = true;
/**
* Responses to AJAX calls.
*/
require_once __DIR__.'/../global.inc.php';
$action = $_GET['a'];
switch ($action) {
case 'get_count_notifications':
if (api_get_configuration_value('notification_event')) {
$notificationManager = new NotificationEvent();
$notifications = $notificationManager->getNotificationsByUser(api_get_user_id());
echo count($notifications);
}
break;
case 'get_notifications':
if (api_get_configuration_value('notification_event')) {
$notificationManager = new NotificationEvent();
$notifications = $notificationManager->getNotificationsByUser(api_get_user_id());
echo json_encode($notifications);
}
break;
case 'mark_notification_as_read':
if (api_get_configuration_value('notification_event')) {
$id = $_REQUEST['id'] ?? 0;
$notificationManager = new NotificationEvent();
$notificationManager->markAsRead($id);
echo 1;
}
break;
case 'get_count_message':
api_block_anonymous_users(false);
$userId = api_get_user_id();
$invitations = MessageManager::getMessagesCountForUser($userId);
header('Content-type:application/json');
echo json_encode($invitations);
break;
case 'send_message':
api_block_anonymous_users(false);
$subject = isset($_REQUEST['subject']) ? trim($_REQUEST['subject']) : null;
$messageContent = isset($_REQUEST['content']) ? trim($_REQUEST['content']) : null;
$messageContent = attr_on_filter($messageContent);
if (empty($subject) || empty($messageContent)) {
echo Display::return_message(get_lang('ErrorSendingMessage'), 'error');
exit;
}
$courseId = isset($_REQUEST['course_id']) ? (int) $_REQUEST['course_id'] : 0;
$sessionId = isset($_REQUEST['session_id']) ? (int) $_REQUEST['session_id'] : 0;
// Add course info
if (!empty($courseId)) {
$courseInfo = api_get_course_info_by_id($courseId);
if (!empty($courseInfo)) {
if (empty($sessionId)) {
$courseNotification = sprintf(get_lang('ThisEmailWasSentViaCourseX'), $courseInfo['title']);
} else {
$sessionInfo = api_get_session_info($sessionId);
if (!empty($sessionInfo)) {
$courseNotification = sprintf(
get_lang('ThisEmailWasSentViaCourseXInSessionX'),
$courseInfo['title'],
$sessionInfo['name']
);
}
}
$messageContent .= '<br /><br />'.$courseNotification;
}
}
$result = MessageManager::send_message($_REQUEST['user_id'], $subject, $messageContent);
if ($result) {
echo Display::return_message(get_lang('MessageHasBeenSent'), 'confirmation');
} else {
echo Display::return_message(get_lang('ErrorSendingMessage'), 'confirmation');
}
break;
case 'send_invitation':
api_block_anonymous_users(false);
$subject = isset($_REQUEST['subject']) ? trim($_REQUEST['subject']) : null;
$invitationContent = isset($_REQUEST['content']) ? trim($_REQUEST['content']) : null;
SocialManager::sendInvitationToUser($_REQUEST['user_id'], $subject, $invitationContent);
break;
case 'find_users':
if (api_is_anonymous()) {
echo '';
break;
}
$repo = UserManager::getRepository();
$users = $repo->findUsersToSendMessage(
api_get_user_id(),
$_REQUEST['q'],
$_REQUEST['page_limit']
);
$showEmail = api_get_setting('show_email_addresses') === 'true';
$return = ['items' => []];
/** @var User $user */
foreach ($users as $user) {
$userName = UserManager::formatUserFullName($user, true);
if ($showEmail) {
$userName .= " ({$user->getEmail()})";
}
$return['items'][] = [
'text' => $userName,
'id' => $user->getId(),
];
}
header('Content-type:application/json');
echo json_encode($return);
break;
case 'add_tags':
$idList = $_POST['id'] ?? [];
$tagList = $_POST['tags'] ?? [];
if (false === api_get_configuration_value('enable_message_tags')
|| api_is_anonymous()
|| api_get_setting('allow_message_tool') !== 'true'
|| empty($idList) || empty($tagList)
) {
break;
}
$em = Database::getManager();
$userId = api_get_user_id();
$extraFieldValues = new ExtraFieldValue('message');
foreach ($idList as $messageId) {
$messageInfo = MessageManager::get_message_by_id($messageId);
if ($messageInfo['msg_status'] == MESSAGE_STATUS_OUTBOX
&& $messageInfo['user_sender_id'] != $userId
) {
continue;
}
if (in_array($messageInfo['msg_status'], [MESSAGE_STATUS_UNREAD, MESSAGE_STATUS_NEW])
&& $messageInfo['user_receiver_id'] != $userId
) {
continue;
}
$extraParams = [
'item_id' => $messageInfo['id'],
'extra_tags' => $tagList,
];
$extraFieldValues->saveFieldValues($extraParams, false, false, ['tags'], [], false, false);
}
break;
default:
echo '';
}
exit;

2816
main/inc/ajax/model.ajax.php Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,232 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Responses to AJAX calls.
*/
require_once __DIR__.'/../global.inc.php';
$action = $_GET['a'];
// Access restrictions.
$is_allowedToTrack = api_is_platform_admin(true, true) ||
api_is_allowed_to_create_course() || api_is_course_tutor() || api_is_session_general_coach();
if (!$is_allowedToTrack) {
exit;
}
switch ($action) {
case 'lp_global_report':
$userId = (int) $_REQUEST['user_id'];
if (empty($userId)) {
exit;
}
$cacheAvailable = api_get_configuration_value('apc');
$table = null;
$variable = 'lp_global_report_'.$userId;
if ($cacheAvailable) {
if (apcu_exists($variable)) {
$table = apcu_fetch($variable);
}
}
if (!empty($table)) {
echo $table;
exit;
}
$sessionCategoryList = UserManager::get_sessions_by_category($userId, false);
$total = 0;
$totalAverage = 0;
$table = new HTML_Table(['class' => 'table table-hover table-striped data_table']);
$row = 0;
$col = 0;
foreach ($sessionCategoryList as $category) {
$sessionList = $category['sessions'];
foreach ($sessionList as $session) {
$courses = $session['courses'];
$sessionId = $session['session_id'];
$session['session_name'];
$totalCourse = 0;
$totalSessionAverage = 0;
foreach ($courses as &$course) {
$average = Tracking::get_avg_student_progress($userId, $course['course_code'], [], $sessionId);
$totalSessionAverage += $average;
$totalCourse++;
if (false !== $average) {
$average = $average.' %';
}
$course['average'] = $average;
}
$total++;
$totalSessionAverage = round($totalSessionAverage / count($courses), 2);
$totalAverage += $totalSessionAverage;
$row++;
$table->setCellContents($row, 0, $session['session_name']);
$table->setCellContents($row, 1, $totalSessionAverage.' %');
$table->setCellContents($row, 2, '');
$row++;
foreach ($courses as &$course) {
$table->setCellContents($row, 0, $session['session_name']);
$table->setCellContents($row, 1, $course['title']);
$table->setCellContents($row, 2, $course['average']);
$row++;
}
}
}
$table->setCellContents(0, 0, get_lang('Global'));
$table->setCellContents(0, 1, round($totalAverage / $total, 2).' %');
$result = $table->toHtml();
if ($cacheAvailable) {
apcu_store($variable, $result, 60);
}
echo $result;
break;
case 'access_detail':
// At this date : 23/02/2017, a minor review can't determine where is used this case 'access_detail'.
$user_id = (int) $_REQUEST['student'];
$course_code = Security::remove_XSS($_REQUEST['course']);
$type = Security::remove_XSS($_REQUEST['type']);
$range = Security::remove_XSS($_REQUEST['range']);
$sessionId = isset($_REQUEST['session_id']) ? $_REQUEST['session_id'] : 0;
$courseInfo = api_get_course_info($course_code);
if ($range == 1) {
$start_date = Security::remove_XSS($_REQUEST['sd']);
$end_date = Security::remove_XSS($_REQUEST['ed']);
$sql_result = MySpace::get_connections_to_course_by_date(
$user_id,
$courseInfo,
$sessionId,
$start_date,
$end_date
);
} else {
$sql_result = MySpace::get_connections_to_course(
$user_id,
$courseInfo,
$sessionId
);
}
$foo_print = MySpace::grapher($sql_result, $start_date, $end_date, $type);
echo $foo_print;
break;
case 'access_detail_by_date':
$export = isset($_REQUEST['export']) ? $_REQUEST['export'] : false;
$result = ['is_empty' => true];
$start_date = isset($_REQUEST['startDate']) ? $_REQUEST['startDate'] : '';
$end_date = isset($_REQUEST['endDate']) ? $_REQUEST['endDate'] : '';
$user_id = isset($_REQUEST['student']) ? $_REQUEST['student'] : '';
$course_code = isset($_REQUEST['course']) ? $_REQUEST['course'] : '';
$type = isset($_REQUEST['type']) ? $_REQUEST['type'] : '';
$sessionId = isset($_REQUEST['session_id']) ? $_REQUEST['session_id'] : 0;
$courseInfo = api_get_course_info($course_code);
$connections = MySpace::get_connections_to_course_by_date(
$user_id,
$courseInfo,
$sessionId,
$start_date,
$end_date,
true
);
if (is_array($connections) && count($connections) > 0) {
$result['is_empty'] = false;
$tableData = [];
foreach ($connections as $data) {
$item = [
api_get_local_time($data['login']),
api_time_to_hms(api_strtotime($data['logout']) - api_strtotime($data['login'])),
$data['user_ip'],
];
$tableData[] = $item;
}
$table = new SortableTableFromArray(
$tableData,
0,
500,
'stat_table',
null,
'stat_table'
);
$table->set_header(1, get_lang('LoginDate'), false);
$table->set_header(2, get_lang('Duration'), false);
$table->set_header(3, get_lang('IP'), false);
$result['result'] = $table->return_table();
if ($export) {
Export::arrayToXls($table->toArray());
exit;
}
$rst = MySpace::getStats(
$user_id,
$courseInfo,
$sessionId,
$start_date,
$end_date
);
$stats = '<strong>'.get_lang('Total').': </strong>'.$rst['total'].'<br />';
$stats .= '<strong>'.get_lang('Average').': </strong>'.$rst['avg'].'<br />';
$stats .= '<strong>'.get_lang('Quantity').' : </strong>'.$rst['times'].'<br />';
$result['stats'] = $stats;
$result['graph_result'] = MySpace::grapher($connections, $start_date, $end_date, $type);
} else {
$result['result'] = Display::return_message(
get_lang('NoDataAvailable'),
'warning'
);
$result['graph_result'] = Display::return_message(
get_lang('NoDataAvailable'),
'warning'
);
$result['stats'] = Display::return_message(
get_lang('NoDataAvailable'),
'warning'
);
}
header('Cache-Control: no-cache');
echo json_encode($result);
break;
case 'show_conditional_to_export_pdf':
$studentId = isset($_REQUEST['student']) ? (int) $_REQUEST['student'] : 0;
$sId = isset($_REQUEST['session_to_export']) ? (int) $_REQUEST['session_to_export'] : 0;
$form = new FormValidator(
'conditional_to_export_pdf',
'post',
api_get_path(WEB_CODE_PATH).'mySpace/session.php?'
.http_build_query(
[
'student' => $studentId,
'action' => 'export_to_pdf',
'type' => 'achievement',
'session_to_export' => $sId,
]
),
'',
[],
FormValidator::LAYOUT_INLINE
);
$form->addCheckBox('hide_connection_time', null, get_lang('HideConnectionTime'));
$form->addHtml('<br><br>');
$form->addButtonSave(get_lang('Generate'), 'submitLink');
$content = $form->returnForm();
echo $content;
break;
}
exit;

View File

@@ -0,0 +1,45 @@
<?php
/* For licensing terms, see /license.txt */
$_dont_save_user_course_access = true;
require_once __DIR__.'/../global.inc.php';
$action = isset($_GET['a']) ? $_GET['a'] : '';
switch ($action) {
case 'get_users_online':
echo returnNotificationMenu();
break;
case 'load_online_user':
$access = accessToWhoIsOnline();
if (!$access) {
exit;
}
$images_to_show = MAX_ONLINE_USERS;
$page = intval($_REQUEST['online_page_nr']);
$max_page = ceil(who_is_online_count() / $images_to_show);
$page_rows = ($page - 1) * MAX_ONLINE_USERS;
if (!empty($max_page) && $page <= $max_page) {
if (isset($_GET['cidReq']) && strlen($_GET['cidReq']) > 0) {
$user_list = who_is_online_in_this_course(
$page_rows,
$images_to_show,
api_get_user_id(),
api_get_setting('time_limit_whosonline'),
$_GET['cidReq']
);
} else {
$user_list = who_is_online($page_rows, $images_to_show);
}
if (!empty($user_list)) {
echo SocialManager::display_user_list($user_list, false);
exit;
}
}
echo 'end';
break;
default:
break;
}

View File

@@ -0,0 +1,39 @@
<?php
/* For licensing terms, see /license.txt */
use Michelf\MarkdownExtra;
/**
* Responses to AJAX calls.
*/
require_once __DIR__.'/../global.inc.php';
api_block_anonymous_users();
$action = $_REQUEST['a'];
switch ($action) {
case 'md_to_html':
$plugin = $_GET['plugin'] ?? '';
$appPlugin = new AppPlugin();
$pluginPaths = $appPlugin->read_plugins_from_path();
if (!in_array($plugin, $pluginPaths)) {
echo Display::return_message(get_lang('NotAllowed'), 'error', false);
exit;
}
$pluginInfo = $appPlugin->getPluginInfo($plugin);
$html = '';
if (!empty($pluginInfo)) {
$file = api_get_path(SYS_PLUGIN_PATH).$plugin.'/README.md';
if (file_exists($file)) {
$content = file_get_contents($file);
$html = MarkdownExtra::defaultTransform($content);
}
}
echo $html;
break;
}

View File

@@ -0,0 +1,79 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CoreBundle\Entity\Portfolio;
use Chamilo\CoreBundle\Entity\PortfolioComment;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request as HttpRequest;
use Symfony\Component\HttpFoundation\Response;
require_once __DIR__.'/../global.inc.php';
$httpRequest = HttpRequest::createFromGlobals();
$action = $httpRequest->query->has('a') ? $httpRequest->query->get('a') : $httpRequest->request->get('a');
$currentUserId = api_get_user_id();
$currentUser = api_get_user_entity($currentUserId);
$em = Database::getManager();
$item = null;
$comment = null;
if ($httpRequest->query->has('item')) {
/** @var Portfolio $item */
$item = $em->find(
Portfolio::class,
$httpRequest->query->getInt('item')
);
}
if ($httpRequest->query->has('comment')) {
$comment = $em->find(
PortfolioComment::class,
$httpRequest->query->getInt('comment')
);
}
$httpResponse = Response::create();
switch ($action) {
case 'find_template':
if (!$item) {
$httpResponse->setStatusCode(Response::HTTP_NOT_FOUND);
break;
}
if (!$item->isTemplate() || $item->getUser() !== $currentUser) {
$httpResponse->setStatusCode(Response::HTTP_FORBIDDEN);
break;
}
$httpResponse = JsonResponse::create(
[
'title' => $item->getTitle(),
'content' => $item->getContent(),
]
);
break;
case 'find_template_comment':
if (!$comment) {
$httpResponse->setStatusCode(Response::HTTP_NOT_FOUND);
break;
}
if (!$comment->isTemplate() || $comment->getAuthor() !== $currentUser) {
$httpResponse->setStatusCode(Response::HTTP_FORBIDDEN);
break;
}
$httpResponse = JsonResponse::create(
[
'content' => $comment->getContent(),
]
);
break;
}
$httpResponse->send();

View File

@@ -0,0 +1,110 @@
<?php
/* For licensing terms, see /license.txt */
use ChamiloSession as Session;
require_once __DIR__.'/../global.inc.php';
api_block_anonymous_users();
$courseInfo = api_get_course_info();
/** @var string $tool document or exercise */
$tool = isset($_REQUEST['tool']) ? $_REQUEST['tool'] : '';
$type = isset($_REQUEST['type']) ? $_REQUEST['type'] : 'document'; // can be document or message
if ($type === 'document') {
api_protect_course_script();
}
$userId = api_get_user_id();
if (!isset($_FILES['audio_blob'], $_REQUEST['audio_dir'])) {
if ($tool === 'exercise') {
header('Content-Type: application/json');
echo json_encode([
'error' => true,
'message' => Display::return_message(get_lang('UploadError'), 'error'),
]);
Display::cleanFlashMessages();
exit;
}
Display::addFlash(Display::return_message(get_lang('UploadError'), 'error'));
exit;
}
$file = isset($_FILES['audio_blob']) ? $_FILES['audio_blob'] : [];
$file['file'] = $file;
$audioDir = Security::remove_XSS($_REQUEST['audio_dir']);
switch ($type) {
case 'document':
$dirBaseDocuments = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document';
$saveDir = $dirBaseDocuments.$audioDir;
if (!is_dir($saveDir)) {
mkdir($saveDir, api_get_permissions_for_new_directories(), true);
}
if (empty($audioDir)) {
$audioDir = '/';
}
$uploadedDocument = DocumentManager::upload_document(
$file,
$audioDir,
$file['name'],
null,
0,
'overwrite',
false,
in_array($tool, ['document', 'exercise']),
'file',
true,
api_get_user_id(),
$courseInfo,
api_get_session_id(),
api_get_group_id(),
'exercise' === $tool
);
$error = empty($uploadedDocument) || !is_array($uploadedDocument);
if (!$error) {
$newDocId = $uploadedDocument['id'];
$courseId = $uploadedDocument['c_id'];
/** @var learnpath $lp */
$lp = Session::read('oLP');
$lpItemId = isset($_REQUEST['lp_item_id']) && !empty($_REQUEST['lp_item_id']) ? $_REQUEST['lp_item_id'] : null;
if (!empty($lp) && empty($lpItemId)) {
$lp->set_modified_on();
$lpItem = new learnpathItem($lpItemId);
$lpItem->add_audio_from_documents($newDocId);
}
$data = DocumentManager::get_document_data_by_id($newDocId, $courseInfo['code']);
if ($tool === 'exercise') {
header('Content-Type: application/json');
echo json_encode([
'error' => $error,
'message' => Display::getFlashToString(),
'fileUrl' => $data['document_url'],
]);
Display::cleanFlashMessages();
exit;
}
echo $data['document_url'];
}
break;
case 'message':
Session::write('current_audio_id', $file['name']);
api_upload_file('audio_message', $file, api_get_user_id());
break;
}

View File

@@ -0,0 +1,155 @@
<?php
/* For licensing terms, see /license.txt */
use ChamiloSession as Session;
require_once __DIR__.'/../global.inc.php';
// Add security from Chamilo
api_block_anonymous_users();
$_course = api_get_course_info();
// Save the audio to a URL-accessible directory for playback.
parse_str($_SERVER['QUERY_STRING'], $params);
if (isset($params['waminame']) && isset($params['wamidir']) && isset($params['wamiuserid'])) {
$waminame = $params['waminame'];
$wamidir = $params['wamidir'];
$wamiuserid = $params['wamiuserid'];
} else {
api_not_allowed();
exit();
}
if (empty($wamiuserid)) {
api_not_allowed();
exit();
}
$type = isset($_REQUEST['type']) ? $_REQUEST['type'] : 'document'; // can be document or message
if ($type === 'document') {
api_protect_course_script();
}
// Clean
$waminame = Security::remove_XSS($waminame);
$waminame = Database::escape_string($waminame);
$waminame = api_replace_dangerous_char($waminame);
$waminame = disable_dangerous_file($waminame);
$wamidir = Security::remove_XSS($wamidir);
$content = file_get_contents('php://input');
if (empty($content)) {
exit;
}
$ext = explode('.', $waminame);
$ext = strtolower($ext[sizeof($ext) - 1]);
if ($ext != 'wav') {
exit();
}
switch ($type) {
case 'document':
// Do not use here check Fileinfo method because return: text/plain
$dirBaseDocuments = api_get_path(SYS_COURSE_PATH).$_course['path'].'/document';
$saveDir = $dirBaseDocuments.$wamidir;
if (!is_dir($saveDir)) {
DocumentManager::createDefaultAudioFolder($_course);
}
// Avoid duplicates
$waminame_to_save = $waminame;
$documentPath = $saveDir.'/'.$waminame_to_save;
// Add to disk
$fh = fopen($documentPath, 'w') or exit("can't open file");
fwrite($fh, $content);
fclose($fh);
$fileInfo = pathinfo($documentPath);
$courseInfo = api_get_course_info();
$file = [
'file' => [
'name' => $fileInfo['basename'],
'tmp_name' => $documentPath,
'size' => filesize($documentPath),
'type' => 'audio/wav',
'from_file' => true,
],
];
$output = true;
ob_start();
// Strangely the file path changes with a double extension
copy($documentPath, $documentPath.'.wav');
$documentData = DocumentManager::upload_document(
$file,
$wamidir,
$fileInfo['basename'],
'wav',
0,
'overwrite',
false,
$output
);
$contents = ob_get_contents();
if (!empty($documentData)) {
$newDocId = $documentData['id'];
$documentData['comment'] = 'mp3';
$newMp3DocumentId = DocumentManager::addAndConvertWavToMp3(
$documentData,
$courseInfo,
api_get_session_id(),
api_get_user_id(),
'overwrite',
true
);
if ($newMp3DocumentId) {
$newDocId = $newMp3DocumentId;
}
if (isset($_REQUEST['lp_item_id']) && !empty($_REQUEST['lp_item_id'])) {
$lpItemId = $_REQUEST['lp_item_id'];
/** @var learnpath $lp */
$lp = Session::read('oLP');
if (!empty($lp)) {
$lp->set_modified_on();
$lpItem = new learnpathItem($lpItemId);
$lpItem->add_audio_from_documents($newDocId);
echo Display::return_message(get_lang('Updated'), 'info');
}
}
// Strangely the file path changes with a double extension
// Remove file with one extension
unlink($documentPath);
} else {
echo $contents;
}
break;
case 'message':
$tempFile = api_get_path(SYS_ARCHIVE_PATH).$waminame;
file_put_contents($tempFile, $content);
Session::write('current_audio_id', $waminame);
$file = [
'name' => basename($tempFile),
'tmp_name' => $tempFile,
'size' => filesize($tempFile),
'type' => 'audio/wav',
'move_file' => true,
];
api_upload_file('audio_message', $file, api_get_user_id());
break;
}

View File

@@ -0,0 +1,474 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CoreBundle\Entity\Repository\SequenceRepository;
use Chamilo\CoreBundle\Entity\Repository\SequenceResourceRepository;
use Chamilo\CoreBundle\Entity\Sequence;
use Chamilo\CoreBundle\Entity\SequenceResource;
use ChamiloSession as Session;
use Fhaculty\Graph\Graph;
use Fhaculty\Graph\Vertex;
use Graphp\GraphViz\GraphViz;
/**
* Responses to AJAX calls.
*/
require_once __DIR__.'/../global.inc.php';
$action = $_REQUEST['a'] ?? null;
$id = (int) ($_REQUEST['id'] ?? null);
$type = (int) ($_REQUEST['type'] ?? null);
$sequenceId = $_REQUEST['sequence_id'] ?? 0;
$em = Database::getManager();
/** @var SequenceRepository $sequenceRepository */
$sequenceRepository = $em->getRepository(Sequence::class);
/** @var SequenceResourceRepository $sequenceResourceRepository */
$sequenceResourceRepository = $em->getRepository(SequenceResource::class);
switch ($action) {
case 'graph':
api_block_anonymous_users();
/** @var Sequence $sequence */
$sequence = $sequenceRepository->find($sequenceId);
if (null === $sequence) {
exit;
}
if ($sequence->hasGraph()) {
$graph = $sequence->getUnSerializeGraph();
$graph->setAttribute('graphviz.node.fontname', 'arial');
$graphviz = new GraphViz();
$graphImage = '';
try {
$graphImage = $graphviz->createImageSrc($graph);
echo Display::img(
$graphImage,
get_lang('GraphDependencyTree'),
['class' => 'center-block img-responsive'],
false
);
} catch (UnexpectedValueException $e) {
error_log(
$e->getMessage()
.' - Graph could not be rendered in resources sequence'
.' because GraphViz command "dot" could not be executed '
.'- Make sure graphviz is installed.'
);
echo '<p class="text-center"><small>'.get_lang('MissingChartLibraryPleaseCheckLog')
.'</small></p>';
}
}
break;
case 'get_icon':
api_block_anonymous_users();
api_protect_admin_script();
$showDelete = $_REQUEST['show_delete'] ?? false;
$image = Display::return_icon('item-sequence.png', null, null, ICON_SIZE_LARGE);
if (empty($id)) {
exit;
}
$link = '';
$linkDelete = $linkUndo = '';
$resourceName = '';
switch ($type) {
case SequenceResource::SESSION_TYPE:
$resourceData = api_get_session_info($id);
if ($resourceData) {
$resourceName = $resourceData['name'];
}
break;
case SequenceResource::COURSE_TYPE:
$resourceData = api_get_course_info_by_id($id);
if ($resourceData) {
$resourceName = $resourceData['name'];
}
break;
}
if (empty($resourceData)) {
exit;
}
if ($showDelete) {
$linkDelete = Display::toolbarButton(
get_lang('Delete'),
'#',
'trash',
'default',
[
'class' => 'delete_vertex btn btn-block btn-xs',
'data-id' => $id,
]
);
$linkUndo = Display::toolbarButton(
get_lang('Undo'),
'#',
'undo',
'default',
[
'class' => 'undo_delete btn btn-block btn-xs',
'style' => 'display: none;',
'data-id' => $id,
]
);
}
$link = '<div class="parent" data-id="'.$id.'">';
$link .= '<div class="big-icon">';
$link .= $image;
$link .= '<div class="sequence-course">'.$resourceName.'</div>';
$link .= Display::tag(
'button',
$resourceName,
[
'class' => 'sequence-id',
'title' => get_lang('UseAsReference'),
'type' => 'button',
]
);
$link .= $linkDelete;
$link .= $linkUndo;
$link .= '</div></div>';
echo $link;
break;
case 'delete_vertex':
api_block_anonymous_users();
api_protect_admin_script();
$vertexId = $_REQUEST['vertex_id'] ?? null;
/** @var Sequence $sequence */
$sequence = $sequenceRepository->find($sequenceId);
if (null === $sequence) {
exit;
}
/** @var SequenceResource $sequenceResource */
$sequenceResource = $sequenceResourceRepository->findOneBy(
['resourceId' => $id, 'type' => $type, 'sequence' => $sequence]
);
if (null === $sequenceResource) {
exit;
}
if ($sequenceResource->getSequence()->hasGraph()) {
$graph = $sequenceResource->getSequence()->getUnSerializeGraph();
if ($graph->hasVertex($vertexId)) {
$edgeIterator = $graph->getEdges()->getIterator();
$edgeToDelete = null;
foreach ($edgeIterator as $edge) {
if ($edge->getVertexStart()->getId() == $vertexId && $edge->getVertexEnd()->getId() == $id) {
$edgeToDelete = $edge;
$vertexFromTo = null;
$vertexToFrom = null;
foreach ($edgeIterator as $edges) {
if ((int) $edges->getVertexEnd()->getId() === (int) $id) {
$vertexFromTo = $edges;
}
if ((int) $edges->getVertexStart()->getId() === (int) $vertexId) {
$vertexToFrom = $edges;
}
}
if ($vertexFromTo && !$vertexToFrom) {
Session::write('sr_vertex', true);
$vertex = $graph->getVertex($id);
$vertex->destroy();
$em->remove($sequenceResource);
}
if ($vertexToFrom && $vertexFromTo) {
$vertex = $graph->getVertex($vertexId);
$edgeToDelete->destroy();
}
if ($vertexToFrom && !$vertexFromTo) {
$vertex = $graph->getVertex($vertexId);
$vertex->destroy();
$sequenceResourceToDelete = $sequenceResourceRepository->findOneBy(
[
'resourceId' => $vertexId,
'type' => $type,
'sequence' => $sequence,
]
);
$em->remove($sequenceResourceToDelete);
}
if (!$vertexToFrom && !$vertexFromTo) {
Session::write('sr_vertex', true);
$vertexTo = $graph->getVertex($id);
$vertexFrom = $graph->getVertex($vertexId);
if ($vertexTo->getVerticesEdgeFrom()->count() > 1) {
$vertexFrom->destroy();
$sequenceResourceToDelete = $sequenceResourceRepository->findOneBy(
[
'resourceId' => $vertexId,
'type' => $type,
'sequence' => $sequence,
]
);
$em->remove($sequenceResourceToDelete);
} else {
$vertexTo->destroy();
$vertexFrom->destroy();
$sequenceResourceToDelete = $sequenceResourceRepository->findOneBy(
[
'resourceId' => $vertexId,
'type' => $type,
'sequence' => $sequence,
]
);
$em->remove($sequenceResource);
$em->remove($sequenceResourceToDelete);
}
}
}
}
$sequence->setGraphAndSerialize($graph);
$em->merge($sequence);
$em->flush();
}
}
break;
case 'load_resource':
api_block_anonymous_users();
api_protect_admin_script();
// children or parent
$loadResourceType = $_REQUEST['load_resource_type'] ?? null;
/** @var Sequence $sequence */
$sequence = $sequenceRepository->find($sequenceId);
if (empty($sequence)) {
exit;
}
/** @var SequenceResource $sequenceResource */
$sequenceResource = $sequenceResourceRepository->findOneBy(
['resourceId' => $id, 'type' => $type, 'sequence' => $sequence]
);
if (null === $sequenceResource) {
exit;
}
if ($sequenceResource->hasGraph()) {
$graph = $sequenceResource->getSequence()->getUnSerializeGraph();
/** @var Vertex $mainVertice */
if ($graph->hasVertex($id)) {
$mainVertex = $graph->getVertex($id);
if (!empty($mainVertex)) {
$vertexList = null;
switch ($loadResourceType) {
case 'parent':
$vertexList = $mainVertex->getVerticesEdgeFrom();
break;
case 'children':
$vertexList = $mainVertex->getVerticesEdgeTo();
break;
}
$list = [];
if (!empty($vertexList)) {
foreach ($vertexList as $vertex) {
$list[] = $vertex->getId();
}
}
if (!empty($list)) {
echo implode(',', $list);
}
}
}
}
break;
case 'save_resource':
api_block_anonymous_users();
api_protect_admin_script();
$parents = $_REQUEST['parents'] ?? '';
if (empty($parents) || empty($sequenceId) || empty($type)) {
exit;
}
/** @var Sequence $sequence */
$sequence = $sequenceRepository->find($sequenceId);
if (null === $sequence) {
exit;
}
/*$vertexFromSession = Session::read('sr_vertex');
if ($vertexFromSession) {
Session::erase('sr_vertex');
echo Display::return_message(get_lang('Saved'), 'success');
break;
}*/
$parents = str_replace($id, '', $parents);
$parents = explode(',', $parents);
$parents = array_filter($parents);
if ($sequence->hasGraph()) {
$graph = $sequence->getUnSerializeGraph();
} else {
$graph = new Graph();
}
if ($graph->hasVertex($id)) {
$main = $graph->getVertex($id);
} else {
$main = $graph->createVertex($id);
}
$item = $sequenceRepository->getItem($id, $type);
$main->setAttribute('graphviz.shape', 'record');
$main->setAttribute('graphviz.label', $item->getName());
foreach ($parents as $parentId) {
$item = $sequenceRepository->getItem($parentId, $type);
if ($graph->hasVertex($parentId)) {
$parent = $graph->getVertex($parentId);
if (!$parent->hasEdgeTo($main)) {
$newEdge = $parent->createEdgeTo($main);
}
} else {
$parent = $graph->createVertex($parentId);
$newEdge = $parent->createEdgeTo($main);
}
$parent->setAttribute('graphviz.shape', 'record');
$parent->setAttribute('graphviz.label', $item->getName());
}
foreach ($parents as $parentId) {
$sequenceResourceParent = $sequenceResourceRepository->findOneBy(
['resourceId' => $parentId, 'type' => $type, 'sequence' => $sequence]
);
if (empty($sequenceResourceParent)) {
$sequenceResourceParent = new SequenceResource();
$sequenceResourceParent
->setSequence($sequence)
->setType($type)
->setResourceId($parentId);
$em->persist($sequenceResourceParent);
}
}
/** @var SequenceResource $sequenceResource */
$sequenceResource = $sequenceResourceRepository->findOneBy(
['resourceId' => $id, 'type' => $type, 'sequence' => $sequence]
);
if (null === $sequenceResource) {
// Create
$sequence->setGraphAndSerialize($graph);
$sequenceResource = new SequenceResource();
$sequenceResource
->setSequence($sequence)
->setType($type)
->setResourceId($id);
} else {
// Update
$sequenceResource->getSequence()->setGraphAndSerialize($graph);
}
$em->persist($sequenceResource);
$em->flush();
echo Display::return_message(get_lang('Saved'), 'success');
break;
case 'get_requirements':
case 'get_dependents':
$sessionId = isset($_REQUEST['sid']) ? (int) $_REQUEST['sid'] : 0;
$userId = api_get_user_id();
$resourceName = '';
$template = '';
switch ($type) {
case SequenceResource::SESSION_TYPE:
$resourceData = api_get_session_info($id);
$resourceName = $resourceData['name'];
$template = 'session_requirements.tpl';
break;
case SequenceResource::COURSE_TYPE:
$resourceData = api_get_course_info_by_id($id);
$resourceName = $resourceData['title'];
$template = 'course_requirements.tpl';
break;
}
if (empty($resourceData) || empty($template)) {
exit;
}
if ('get_requirements' === $action) {
$sequences = $sequenceResourceRepository->getRequirements($id, $type);
$sequenceList = $sequenceResourceRepository->checkRequirementsForUser($sequences, $type, $userId, $sessionId);
$allowSubscription = $sequenceResourceRepository->checkSequenceAreCompleted($sequenceList);
} else {
$sequences = $sequenceResourceRepository->getDependents($id, $type);
$sequenceList = $sequenceResourceRepository->checkDependentsForUser($sequences, $type, $userId, $sessionId);
$allowSubscription = $sequenceResourceRepository->checkSequenceAreCompleted(
$sequenceList,
SequenceResourceRepository::VERTICES_TYPE_DEP
);
}
$view = new Template(null, false, false, false, false, false);
$view->assign('sequences', $sequenceList);
$view->assign('sequence_type', $type);
$view->assign('allow_subscription', $allowSubscription);
$view->assign(
'item_type',
'get_requirements' === $action
? SequenceResourceRepository::VERTICES_TYPE_REQ
: SequenceResourceRepository::VERTICES_TYPE_DEP
);
$course = api_get_course_entity();
if ($course) {
$view->assign(
'current_requirement_is_completed',
$sequenceResourceRepository->checkCourseRequirements($userId, $course, $sessionId)
);
}
if ($allowSubscription) {
$view->assign(
'subscribe_button',
CoursesAndSessionsCatalog::getRegisteredInSessionButton(
$id,
$resourceName,
false
)
);
}
$view->display($view->get_template('sequence_resource/'.$template));
break;
}

View File

@@ -0,0 +1,471 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\UserBundle\Entity\User;
/**
* Responses to AJAX calls.
*/
require_once __DIR__.'/../global.inc.php';
$action = $_REQUEST['a'];
switch ($action) {
case 'get_user_sessions':
if (api_is_platform_admin() || api_is_session_admin()) {
$user_id = (int) $_POST['user_id'];
$list_sessions = SessionManager::get_sessions_by_user($user_id, true);
if (!empty($list_sessions)) {
foreach ($list_sessions as $session_item) {
echo $session_item['session_name'].'<br />';
}
} else {
echo get_lang('NoSessionsForThisUser');
}
unset($list_sessions);
}
break;
case 'order':
api_protect_admin_script();
$allowOrder = api_get_configuration_value('session_list_order');
if ($allowOrder) {
$order = isset($_GET['order']) ? $_GET['order'] : [];
$order = json_decode($order);
if (!empty($order)) {
$table = Database::get_main_table(TABLE_MAIN_SESSION);
foreach ($order as $data) {
if (isset($data->order) && isset($data->id)) {
$orderId = (int) $data->order;
$sessionId = (int) $data->id;
$sql = "UPDATE $table SET position = $orderId WHERE id = $sessionId ";
Database::query($sql);
}
}
}
}
break;
case 'search_session':
if (api_is_platform_admin()) {
$sessions = SessionManager::get_sessions_list(
[
's.name' => [
'operator' => 'LIKE',
'value' => "%".$_REQUEST['q']."%",
],
]
);
$list = [
'items' => [],
];
if (empty($sessions)) {
echo json_encode([]);
break;
}
foreach ($sessions as $session) {
$list['items'][] = [
'id' => $session['id'],
'text' => $session['name'],
];
}
echo json_encode($list);
}
break;
case 'search_session_all':
if (api_is_platform_admin()) {
$results = SessionManager::get_sessions_list(
[
's.name' => ['operator' => 'like', 'value' => "%".$_REQUEST['q']."%"],
'c.id' => ['operator' => '=', 'value' => $_REQUEST['course_id']],
]
);
$results2 = [];
if (!empty($results)) {
foreach ($results as $item) {
$item2 = [];
foreach ($item as $id => $internal) {
if ($id == 'id') {
$item2[$id] = $internal;
}
if ($id == 'name') {
$item2['text'] = $internal;
}
}
$results2[] = $item2;
}
$results2[] = ['T', 'text' => 'TODOS', 'id' => 'T'];
echo json_encode($results2);
} else {
echo json_encode([['T', 'text' => 'TODOS', 'id' => 'T']]);
}
}
break;
case 'search_session_by_course':
if (api_is_platform_admin()) {
$results = SessionManager::get_sessions_list(
[
's.name' => ['operator' => 'like', 'value' => "%".$_REQUEST['q']."%"],
'c.id' => ['operator' => '=', 'value' => $_REQUEST['course_id']],
]
);
$json = [
'items' => [
['id' => 'T', 'text' => get_lang('All')],
],
];
if (!empty($results)) {
foreach ($results as $item) {
$item2 = [];
foreach ($item as $id => $internal) {
if ($id == 'id') {
$item2[$id] = $internal;
}
if ($id == 'name') {
$item2['text'] = $internal;
}
}
$json['items'][] = $item2;
}
}
echo json_encode($json);
}
break;
case 'session_info':
$sessionId = isset($_GET['session_id']) ? $_GET['session_id'] : '';
$sessionInfo = api_get_session_info($sessionId);
$extraFieldValues = new ExtraFieldValue('session');
$extraField = new ExtraField('session');
$values = $extraFieldValues->getAllValuesByItem($sessionId);
$load = isset($_GET['load_empty_extra_fields']) ? true : false;
if ($load) {
$allExtraFields = $extraField->get_all();
$valueList = array_column($values, 'id');
foreach ($allExtraFields as $extra) {
if (!in_array($extra['id'], $valueList)) {
$values[] = [
'id' => $extra['id'],
'variable' => $extra['variable'],
'value' => '',
'field_type' => $extra['field_type'],
];
}
}
}
$sessionInfo['extra_fields'] = $values;
if (!empty($sessionInfo)) {
echo json_encode($sessionInfo);
}
break;
case 'get_description':
if (isset($_GET['session'])) {
$sessionInfo = api_get_session_info($_GET['session']);
echo '<h2>'.$sessionInfo['name'].'</h2>';
echo '<div class="home-course-intro"><div class="page-course"><div class="page-course-intro">';
echo $sessionInfo['show_description'] == 1 ? $sessionInfo['description'] : get_lang('None');
echo '</div></div></div>';
}
break;
case 'search_general_coach':
SessionManager::protectSession(null, false);
api_protect_limit_for_session_admin();
if (api_is_anonymous()) {
echo '';
break;
}
$list = [
'items' => [],
];
$usersRepo = UserManager::getRepository();
$users = $usersRepo->searchUsersByStatus($_GET['q'], COURSEMANAGER, api_get_current_access_url_id());
/** @var User $user */
foreach ($users as $user) {
$list['items'][] = [
'id' => $user->getId(),
'text' => UserManager::formatUserFullName($user),
];
}
header('Content-Type: application/json');
echo json_encode($list);
break;
case 'get_courses_inside_session':
$userId = api_get_user_id();
$isAdmin = api_is_platform_admin();
if ($isAdmin) {
$sessionList = SessionManager::get_sessions_list();
$sessionIdList = array_column($sessionList, 'id');
} else {
$sessionList = SessionManager::get_sessions_by_user($userId);
$sessionIdList = array_column($sessionList, 'session_id');
}
$sessionId = isset($_GET['session_id']) ? (int) $_GET['session_id'] : 0;
$courseList = [];
if (empty($sessionId)) {
$preCourseList = CourseManager::get_courses_list_by_user_id(
$userId,
false,
true
);
$courseList = array_column($preCourseList, 'real_id');
} else {
if ($isAdmin) {
$courseList = SessionManager::getCoursesInSession($sessionId);
} else {
if (in_array($sessionId, $sessionIdList)) {
$courseList = SessionManager::getCoursesInSession($sessionId);
}
}
}
$courseListToSelect = [];
if (!empty($courseList)) {
// Course List
foreach ($courseList as $courseId) {
$courseInfo = api_get_course_info_by_id($courseId);
$courseListToSelect[] = [
'id' => $courseInfo['real_id'],
'name' => $courseInfo['title'],
];
}
}
echo json_encode($courseListToSelect);
break;
case 'get_basic_course_documents_list':
case 'get_basic_course_documents_form':
$courseId = isset($_GET['course']) ? (int) $_GET['course'] : 0;
$sessionId = isset($_GET['session']) ? (int) $_GET['session'] : 0;
$currentUserId = api_get_user_id();
$em = Database::getManager();
$course = $em->find('ChamiloCoreBundle:Course', $courseId);
$session = $em->find('ChamiloCoreBundle:Session', $sessionId);
if (!$course || !$session) {
break;
}
if (!api_is_platform_admin(true) || $session->getSessionAdminId() != $currentUserId) {
break;
}
$folderName = '/basic-course-documents__'.$session->getId().'__0';
if ('get_basic_course_documents_list' === $action) {
$courseInfo = api_get_course_info_by_id($course->getId());
$exists = DocumentManager::folderExists('/basic-course-documents', $courseInfo, $session->getId(), 0);
if (!$exists) {
$courseDir = $courseInfo['directory'].'/document';
$baseWorkDir = api_get_path(SYS_COURSE_PATH).$courseDir;
$newFolderData = create_unexisting_directory(
$courseInfo,
$currentUserId,
$session->getId(),
0,
0,
$baseWorkDir,
'/basic-course-documents',
get_lang('BasicCourseDocuments'),
1
);
$id = (int) $newFolderData['iid'];
} else {
$id = DocumentManager::get_document_id($courseInfo, $folderName, $session->getId());
}
$http_www = api_get_path(WEB_COURSE_PATH).$courseInfo['directory'].'/document';
$documentAndFolders = DocumentManager::getAllDocumentData(
$courseInfo,
$folderName,
0,
0,
false,
false,
$session->getId()
);
$documentAndFolders = array_filter(
$documentAndFolders,
function (array $documentData) {
return $documentData['filetype'] != 'folder';
}
);
$documentAndFolders = array_map(
function (array $documentData) use ($course, $session, $folderName) {
$downloadUrl = api_get_path(WEB_CODE_PATH).'document/document.php?'
.api_get_cidreq_params($course->getCode(), $session->getId()).'&'
.http_build_query(['action' => 'download', 'id' => $documentData['id']]);
$deleteUrl = api_get_path(WEB_AJAX_PATH).'session.ajax.php?'
.http_build_query(
[
'a' => 'delete_basic_course_documents',
'deleteid' => $documentData['id'],
'curdirpath' => $folderName,
'course' => $course->getId(),
'session' => $session->getId(),
]
);
$row = [];
$row[] = DocumentManager::build_document_icon_tag($documentData['filetype'], $documentData['path']);
$row[] = Display::url($documentData['title'], $downloadUrl);
$row[] = format_file_size($documentData['size']);
$row[] = date_to_str_ago($documentData['lastedit_date']).PHP_EOL
.'<div class="muted"><small>'
.api_get_local_time($documentData['lastedit_date'])
."</small></div>";
$row[] = Display::url(
Display::return_icon('save.png', get_lang('Download')),
$downloadUrl
)
.PHP_EOL
.Display::url(
Display::return_icon('delete.png', get_lang('Delete')),
$deleteUrl,
[
'class' => 'delete_document',
'data-course' => $course->getId(),
'data-session' => $session->getId(),
]
);
return $row;
},
$documentAndFolders
);
$table = new SortableTableFromArray($documentAndFolders, 1, 20, $folderName);
$table->set_header(0, get_lang('Type'), false, [], ['class' => 'text-center', 'width' => '60px']);
$table->set_header(1, get_lang('Name'), false);
$table->set_header(2, get_lang('Size'), false, [], ['class' => 'text-right', 'style' => 'width: 80px;']);
$table->set_header(3, get_lang('Date'), false, [], ['class' => 'text-center', 'style' => 'width: 200px;']);
$table->set_header(4, get_lang('Actions'), false, [], ['class' => 'text-center']);
$table->display();
}
if ('get_basic_course_documents_form' === $action) {
$form = new FormValidator('get_basic_course_documents_form_'.$session->getId());
$form->addMultipleUpload(
api_get_path(WEB_AJAX_PATH).'document.ajax.php?'
.api_get_cidreq_params($course->getCode(), $session->getId())
.'&a=upload_file&curdirpath='.$folderName,
''
);
$form->display();
}
break;
case 'delete_basic_course_documents':
$curdirpath = isset($_GET['curdirpath']) ? Security::remove_XSS($_GET['curdirpath']) : null;
$docId = isset($_GET['deleteid']) ? (int) $_GET['deleteid'] : 0;
$courseId = isset($_GET['course']) ? (int) $_GET['course'] : 0;
$sessionId = isset($_GET['session']) ? (int) $_GET['session'] : 0;
if (empty($curdirpath) || empty($docId) || empty($courseId) || empty($sessionId)) {
break;
}
$em = Database::getManager();
$courseInfo = api_get_course_info_by_id($courseId);
$session = $em->find('ChamiloCoreBundle:Session', $sessionId);
$currentUserId = api_get_user_id();
if (empty($courseInfo) || !$session) {
break;
}
if (!api_is_platform_admin(true) || $session->getSessionAdminId() != $currentUserId) {
break;
}
$sysCoursePath = api_get_path(SYS_COURSE_PATH);
$courseDir = $courseInfo['directory'].'/document';
$baseWorkDir = $sysCoursePath.$courseDir;
$documentInfo = DocumentManager::get_document_data_by_id(
$docId,
$courseInfo['code'],
false,
$session->getId()
);
if (empty($documentInfo)) {
break;
}
if ($documentInfo['filetype'] != 'link') {
$deletedDocument = DocumentManager::delete_document(
$courseInfo,
null,
$baseWorkDir,
$session->getId(),
$docId
);
} else {
$deletedDocument = DocumentManager::deleteCloudLink(
$courseInfo,
$docId
);
}
if (!$deletedDocument) {
break;
}
echo true;
break;
case 'search_template_session':
SessionManager::protectSession(null, false);
api_protect_limit_for_session_admin();
if (empty($_GET['q'])) {
break;
}
$q = strtolower(trim($_GET['q']));
$list = array_map(
function ($session) {
return [
'id' => $session['id'],
'text' => strip_tags($session['name']),
];
},
SessionManager::formatSessionsAdminForGrid()
);
$list = array_filter(
$list,
function ($session) use ($q) {
$name = strtolower($session['text']);
return strpos($name, $q) !== false;
}
);
header('Content-Type: application/json');
echo json_encode(['items' => array_values($list)]);
break;
default:
echo '';
}
exit;

View File

@@ -0,0 +1,74 @@
<?php
require_once __DIR__.'/../../../vendor/autoload.php';
require_once __DIR__.'/../../../app/AppKernel.php';
$kernel = new AppKernel('', '');
// Check for 'action' parameter in the GET request
if (isset($_GET['action'])) {
$action = $_GET['action'];
if ($action == 'time') {
// Load the Chamilo configuration
$alreadyInstalled = false;
if (file_exists($kernel->getConfigurationFile())) {
require_once $kernel->getConfigurationFile();
$alreadyInstalled = true;
}
// Load the API library BEFORE loading the Chamilo configuration
require_once $_configuration['root_sys'].'main/inc/lib/api.lib.php';
if (api_get_configuration_value('session_lifetime_controller')) {
// Get the session
session_name('ch_sid');
session_start();
$session = new ChamiloSession();
$endTime = 0;
$isExpired = false;
$timeLeft = -1;
$currentTime = time();
// Existing code for time action
if ($alreadyInstalled && api_get_user_id()) {
$endTime = $session->end_time();
$isExpired = $session->is_expired();
} else {
// Chamilo not installed or user not logged in
$endTime = $currentTime + 315360000; // This sets a default end time far in the future
$isExpired = false;
}
$timeLeft = $endTime - $currentTime;
} else {
$endTime = 999999;
$isExpired = false;
$timeLeft = 999999;
}
if ($endTime > 0) {
echo json_encode(['sessionEndDate' => $endTime, 'sessionTimeLeft' => $timeLeft, 'sessionExpired' => $isExpired]);
} else {
http_response_code(500);
echo json_encode(['error' => 'Error retrieving data from the current session']);
}
} elseif ($action == 'logout') {
require_once __DIR__.'/../../../main/inc/global-min.inc.php';
$userId = api_get_user_id();
online_logout($userId, false);
echo json_encode(['message' => 'Logged out successfully']);
} else {
// Handle unexpected action value
http_response_code(400);
echo json_encode(['error' => 'Invalid action parameter']);
}
} else {
// No action provided
http_response_code(400);
echo json_encode(['error' => 'No action parameter provided']);
}

View File

@@ -0,0 +1,530 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Responses to AJAX calls.
*/
use Chamilo\SkillBundle\Entity\SkillRelCourse;
use Chamilo\SkillBundle\Entity\SkillRelItem;
require_once __DIR__.'/../global.inc.php';
$action = $_REQUEST['a'] ?? null;
api_block_anonymous_users();
Skill::isAllowed(api_get_user_id());
$skill = new Skill();
$gradebook = new Gradebook();
$skillGradeBook = new SkillRelGradebook();
$userId = api_get_user_id();
switch ($action) {
case 'add':
if (api_is_platform_admin() || api_is_drh()) {
if (!empty($_REQUEST['id'])) {
$skillId = $skill->edit($_REQUEST);
} else {
$skillId = $skill->add($_REQUEST);
}
}
echo $skillId;
break;
case 'delete_skill':
if (api_is_platform_admin() || api_is_drh()) {
echo $skill->delete($_REQUEST['skill_id']);
}
break;
case 'find_skills':
$returnSkills = [[
'items' => [],
]];
if (!empty($_REQUEST['q'])) {
$skills = $skill->find('all', ['where' => ['name LIKE %?% ' => $_REQUEST['q']]]);
foreach ($skills as $skill) {
$returnSkills['items'][] = [
'id' => $skill['id'],
'text' => $skill['name'],
];
}
}
header('Content-Type: application/json');
echo json_encode($returnSkills);
break;
case 'get_gradebooks':
$gradebooks = $gradebook_list = $gradebook->get_all();
$gradebook_list = [];
//Only course gradebook with certificate
if (!empty($gradebooks)) {
foreach ($gradebooks as $gradebook) {
if ($gradebook['parent_id'] == 0 &&
!empty($gradebook['certif_min_score']) &&
!empty($gradebook['document_id'])
) {
$gradebook_list[] = $gradebook;
}
}
}
echo json_encode($gradebook_list);
break;
case 'find_gradebooks':
$return = [];
if (!empty($_REQUEST['tag'])) {
$gradebooks = $gradebook->find('all', ['where' => ['name LIKE %?% ' => $_REQUEST['tag']]]);
foreach ($gradebooks as $item) {
$item['key'] = $item['name'];
$item['value'] = $item['id'];
$return[] = $item;
}
}
echo json_encode($return);
break;
case 'get_course_info_popup':
$courseInfo = api_get_course_info($_REQUEST['code']);
$courses = CourseManager::processHotCourseItem(
[
['c_id' => $courseInfo['real_id']],
]
);
Display::display_no_header();
Display::$global_template->assign('hot_courses', $courses);
$template = Display::$global_template->get_template('layout/hot_course_item_popup.tpl');
echo Display::$global_template->fetch($template);
break;
case 'gradebook_exists':
$data = $gradebook->get($_REQUEST['gradebook_id']);
if (!empty($data)) {
echo 1;
} else {
echo 0;
}
break;
case 'get_skills_by_profile':
$skillRelProfile = new SkillRelProfile();
$profile_id = $_REQUEST['profile_id'] ?? null;
$skills = $skillRelProfile->getSkillsByProfile($profile_id);
echo json_encode($skills);
break;
case 'get_saved_profiles':
$skillProfile = new SkillProfile();
$profiles = $skillProfile->get_all();
Display::display_no_header();
Display::$global_template->assign('profiles', $profiles);
$template = Display::$global_template->get_template('skill/profile_item.tpl');
echo Display::$global_template->fetch($template);
break;
case 'get_skills':
$loadUserData = $_REQUEST['load_user_data'] ?? null;
$id = intval($_REQUEST['id']);
$skills = $skill->get_all($loadUserData, false, $id);
echo json_encode($skills);
break;
case 'get_skill_info':
$id = $_REQUEST['id'] ?? null;
$skillInfo = $skill->getSkillInfo($id);
echo json_encode($skillInfo);
break;
case 'get_skill_course_info':
$id = $_REQUEST['id'] ?? null;
$skillInfo = $skill->getSkillInfo($id);
$courses = $skill->getCoursesBySkill($id);
$sessions = $skill->getSessionsBySkill($id);
$html = '';
if (!empty($courses) || !empty($sessions)) {
Display::display_no_header();
Display::$global_template->assign('skill', $skillInfo);
Display::$global_template->assign('courses', $courses);
Display::$global_template->assign('sessions', $sessions);
$template = Display::$global_template->get_template('skill/skill_info.tpl');
$html = Display::$global_template->fetch($template);
}
echo $html;
break;
case 'get_skills_tree_json':
header('Content-Type: application/json');
$userId = isset($_REQUEST['load_user']) && $_REQUEST['load_user'] == 1 ? api_get_user_id() : 0;
$skill_id = isset($_REQUEST['skill_id']) ? intval($_REQUEST['skill_id']) : 0;
$depth = isset($_REQUEST['main_depth']) ? intval($_REQUEST['main_depth']) : 2;
$all = $skill->getSkillsTreeToJson($userId, $skill_id, false, $depth);
echo $all;
break;
case 'get_user_skill':
$skillId = isset($_REQUEST['profile_id']) ? intval($_REQUEST['profile_id']) : 0;
$skill = $skill->userHasSkill($userId, $skillId);
if ($skill) {
echo 1;
} else {
echo 0;
}
break;
case 'get_all_user_skills':
if (strpos($_SERVER['HTTP_REFERER'], "/main/admin/skills_wheel.php") !== false) {
$userId = 0;
}
$skills = $skill->getUserSkills($userId, true);
echo json_encode($skills);
break;
case 'get_user_skills':
$skills = $skill->getUserSkills($userId, true);
Display::display_no_header();
Display::$global_template->assign('skills', $skills);
$template = Display::$global_template->get_template('skill/user_skills.tpl');
echo Display::$global_template->fetch($template);
break;
case 'get_gradebook_info':
$id = isset($_REQUEST['id']) ? intval($_REQUEST['id']) : null;
$info = $gradebook->get($id);
echo json_encode($info);
break;
case 'load_children':
$id = isset($_REQUEST['id']) ? intval($_REQUEST['id']) : null;
$load_user_data = $_REQUEST['load_user_data'] ?? null;
$skills = $skill->getChildren($id, $load_user_data);
$return = [];
foreach ($skills as $skill) {
if (!empty($skill['data'])) {
$return[$skill['data']['id']] = [
'id' => $skill['data']['id'],
'name' => $skill['data']['name'],
'passed' => $skill['data']['passed'],
];
}
}
$success = true;
if (empty($return)) {
$success = false;
}
$result = [
'success' => $success,
'data' => $return,
];
echo json_encode($result);
break;
case 'load_direct_parents':
$id = isset($_REQUEST['id']) ? intval($_REQUEST['id']) : null;
$skills = $skill->getDirectParents($id);
$return = [];
foreach ($skills as $skill) {
$return[$skill['data']['id']] = [
'id' => $skill['data']['id'],
'parent_id' => $skill['data']['parent_id'],
'name' => $skill['data']['name'],
];
}
echo json_encode($return);
break;
case 'profile_matches':
$skill_rel_user = new SkillRelUser();
$skills = !empty($_REQUEST['skill_id']) ? $_REQUEST['skill_id'] : [];
$total_skills_to_search = $skills;
$users = $skill_rel_user->getUserBySkills($skills);
$user_list = [];
$count_skills = count($skills);
$ordered_user_list = null;
if (!empty($users)) {
foreach ($users as $user) {
$user_info = api_get_user_info($user['user_id']);
$user_list[$user['user_id']]['user'] = $user_info;
$my_user_skills = $skill_rel_user->getUserSkills($user['user_id']);
$user_skill_list = [];
foreach ($my_user_skills as $skill_item) {
$user_skill_list[] = $skill_item['skill_id'];
}
$user_skills = [];
$found_counts = 0;
foreach ($skills as $skill_id) {
$found = false;
if (in_array($skill_id, $user_skill_list)) {
$found = true;
$found_counts++;
$user_skills[$skill_id] = ['skill_id' => $skill_id, 'found' => $found];
}
}
foreach ($my_user_skills as $my_skill) {
if (!isset($user_skills[$my_skill['skill_id']])) {
$user_skills[$my_skill['skill_id']] = [
'skill_id' => $my_skill['skill_id'],
'found' => false,
];
}
$total_skills_to_search[$my_skill['skill_id']] = $my_skill['skill_id'];
}
$user_list[$user['user_id']]['skills'] = $user_skills;
$user_list[$user['user_id']]['total_found_skills'] = $found_counts;
}
foreach ($user_list as $user_id => $user_data) {
$ordered_user_list[$user_data['total_found_skills']][] = $user_data;
}
if (!empty($ordered_user_list)) {
krsort($ordered_user_list);
}
}
Display::display_no_header();
Display::$global_template->assign('order_user_list', $ordered_user_list);
Display::$global_template->assign('total_search_skills', $count_skills);
$skill_list = [];
if (!empty($total_skills_to_search)) {
$total_skills_to_search = $skill->getSkillsInfo($total_skills_to_search);
foreach ($total_skills_to_search as $skill_info) {
$skill_list[$skill_info['id']] = $skill_info;
}
}
Display::$global_template->assign('skill_list', $skill_list);
$template = Display::$global_template->get_template('skill/profile.tpl');
echo Display::$global_template->fetch($template);
break;
case 'delete_gradebook_from_skill':
case 'remove_skill':
if (api_is_platform_admin() || api_is_drh()) {
if (!empty($_REQUEST['skill_id']) && !empty($_REQUEST['gradebook_id'])) {
$skill_item = $skillGradeBook->getSkillInfo(
$_REQUEST['skill_id'],
$_REQUEST['gradebook_id']
);
if (!empty($skill_item)) {
$skillGradeBook->delete($skill_item['id']);
echo 1;
} else {
echo 0;
}
} else {
echo 0;
}
}
break;
case 'get_profile':
$skillRelProfile = new SkillRelProfile();
$profileId = isset($_REQUEST['profile_id']) ? intval($_REQUEST['profile_id']) : null;
$profile = $skillRelProfile->getProfileInfo($profileId);
echo json_encode($profile);
break;
case 'save_profile':
if (api_is_platform_admin() || api_is_drh()) {
$skill_profile = new SkillProfile();
$params = $_REQUEST;
$params['skills'] = $params['skill_id'] ?? null;
$profileId = isset($_REQUEST['profile']) ? intval($_REQUEST['profile']) : null;
if ($profileId > 0) {
$skill_profile->updateProfileInfo(
$profileId,
$params['name'],
$params['description']
);
$skill_data = 1;
} else {
$skill_data = $skill_profile->save($params);
}
if (!empty($skill_data)) {
echo 1;
} else {
echo 0;
}
}
break;
case 'delete_profile':
if (api_is_platform_admin() || api_is_drh()) {
$profileId = $_REQUEST['profile'];
$skillProfile = new SkillProfile();
$isDeleted = $skillProfile->delete($profileId);
echo json_encode([
'status' => $isDeleted,
]);
}
break;
case 'skill_exists':
$skill_data = $skill->get($_REQUEST['skill_id']);
if (!empty($skill_data)) {
echo 1;
} else {
echo 0;
}
break;
case 'search_skills':
$returnSkills = [];
if (!empty($_REQUEST['q'])) {
$skills = $skill->find(
'all',
[
'where' => ['name LIKE %?% ' => $_REQUEST['q']],
]
);
foreach ($skills as $skill) {
$returnSkills[] = [
'id' => $skill['id'],
'text' => $skill['name'],
];
}
}
echo json_encode(['items' => $returnSkills]);
break;
case 'search_skills_in_course':
$courseId = isset($_REQUEST['course_id']) ? (int) $_REQUEST['course_id'] : 0;
$sessionId = isset($_REQUEST['session_id']) ? (int) $_REQUEST['session_id'] : null;
if (empty($courseId)) {
exit;
}
$em = Database::getManager();
$skills = $em->getRepository('ChamiloSkillBundle:SkillRelCourse')->findBy(
['course' => $courseId, 'session' => $sessionId]
);
$returnSkills = [];
/** @var SkillRelCourse $skill */
foreach ($skills as $skill) {
$returnSkills[] = [
'id' => $skill->getSkill()->getId(),
'text' => $skill->getSkill()->getName(),
];
}
echo json_encode([
'items' => $returnSkills,
]);
break;
case 'update_skill_rel_user':
$allowSkillInTools = api_get_configuration_value('allow_skill_rel_items');
if (empty($allowSkillInTools)) {
exit;
}
if (!api_is_allowed_to_edit()) {
exit;
}
$creatorId = api_get_user_id();
$typeId = isset($_REQUEST['type_id']) ? (int) $_REQUEST['type_id'] : 0;
$itemId = isset($_REQUEST['item_id']) ? (int) $_REQUEST['item_id'] : 0;
$skillId = isset($_REQUEST['skill_id']) ? (int) $_REQUEST['skill_id'] : 0;
$userId = isset($_REQUEST['user_id']) ? (int) $_REQUEST['user_id'] : 0;
$courseId = isset($_REQUEST['course_id']) ? (int) $_REQUEST['course_id'] : 0;
$sessionId = isset($_REQUEST['session_id']) ? (int) $_REQUEST['session_id'] : 0;
$resultId = isset($_REQUEST['result_id']) ? (int) $_REQUEST['result_id'] : 0;
if (!empty($typeId) && !empty($itemId) && !empty($skillId) && !empty($userId) && !empty($courseId)) {
$em = Database::getManager();
$user = api_get_user_entity($userId);
$skill = $em->getRepository('ChamiloCoreBundle:Skill')->find($skillId);
if (empty($user) || empty($skill)) {
exit;
}
$course = api_get_course_entity($courseId);
if (empty($course)) {
exit;
}
$session = $em->getRepository('ChamiloCoreBundle:Session')->find($sessionId);
/** @var SkillRelItem $skillRelItem */
$skillRelItem = $em->getRepository('ChamiloSkillBundle:SkillRelItem')->findOneBy(
['itemId' => $itemId, 'itemType' => $typeId, 'skill' => $skillId]
);
if ($skillRelItem) {
$criteria = [
'user' => $userId,
'skillRelItem' => $skillRelItem,
];
$skillRelItemRelUser = $em->getRepository('ChamiloSkillBundle:SkillRelItemRelUser')->findOneBy($criteria);
if ($skillRelItemRelUser) {
$em->remove($skillRelItemRelUser);
$em->flush();
$skillRelItemRelUser = null;
} else {
$skillRelItemRelUser = new Chamilo\SkillBundle\Entity\SkillRelItemRelUser();
$skillRelItemRelUser
->setUser($user)
->setSkillRelItem($skillRelItem)
->setResultId($resultId)
->setCreatedBy($creatorId)
->setUpdatedBy($creatorId);
$em->persist($skillRelItemRelUser);
$em->flush();
}
}
echo Skill::getUserSkillStatusLabel($skillRelItem, $skillRelItemRelUser, false, $userId);
}
break;
case 'assign_user_to_skill':
$allowSkillInTools = api_get_configuration_value('allow_skill_rel_items');
if (empty($allowSkillInTools)) {
exit;
}
if (!api_is_allowed_to_edit()) {
exit;
}
$skillId = isset($_REQUEST['skill_id']) ? (int) $_REQUEST['skill_id'] : 0;
$userId = isset($_REQUEST['user_id']) ? (int) $_REQUEST['user_id'] : 0;
$courseId = isset($_REQUEST['course_id']) ? (int) $_REQUEST['course_id'] : 0;
$sessionId = isset($_REQUEST['session_id']) ? (int) $_REQUEST['session_id'] : null;
if (empty($skillId) || empty($userId)) {
exit;
}
$em = Database::getManager();
$skillRepo = $em->getRepository('ChamiloCoreBundle:Skill');
$skill = $skillRepo->find($skillId);
$user = api_get_user_entity($userId);
if (empty($skill) || empty($user)) {
exit;
}
$skillUserRepo = $em->getRepository('ChamiloCoreBundle:SkillRelUser');
$criteria = [
'user' => $user,
'skill' => $skill,
];
$skillRelUsers = $skillUserRepo->findBy($criteria);
if (empty($skillRelUsers)) {
$skillUser = new \Chamilo\CoreBundle\Entity\SkillRelUser();
$skillUser->setUser($user);
$skillUser->setSkill($skill);
/*if ($showLevels) {
$level = $skillLevelRepo->find(intval($values['acquired_level']));
$skillUser->setAcquiredLevel($level);
}*/
$course = api_get_course_entity($courseId);
$skillUser->setCourse($course);
if (!empty($sessionId)) {
$session = $em->getRepository('ChamiloCoreBundle:Session')->find($sessionId);
$skillUser->setSession($session);
}
$skillUser->setArgumentation('');
$skillUser->setArgumentationAuthorId(api_get_user_id());
$skillUser->setAcquiredSkillAt(new DateTime());
$skillUser->setAssignedBy(0);
$em->persist($skillUser);
$em->flush();
$result = 'success';
} else {
foreach ($skillRelUsers as $skillRelUser) {
$em->remove($skillRelUser);
}
$em->flush();
$result = 'danger';
}
echo $result;
break;
default:
echo '';
}
exit;

View File

@@ -0,0 +1,465 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CoreBundle\Entity\Message;
use Chamilo\CoreBundle\Entity\MessageFeedback;
use ChamiloSession as Session;
use Symfony\Component\HttpFoundation\JsonResponse;
/**
* Responses to AJAX calls.
*/
require_once __DIR__.'/../global.inc.php';
$action = isset($_GET['a']) ? $_GET['a'] : null;
$current_user_id = api_get_user_id();
switch ($action) {
case 'add_friend':
if (api_is_anonymous()) {
echo '';
break;
}
if (Security::check_token('get', null, 'invitation')) {
$relation_type = USER_RELATION_TYPE_UNKNOWN; //Unknown contact
if (isset($_GET['is_my_friend'])) {
$relation_type = USER_RELATION_TYPE_FRIEND; //My friend
}
if (isset($_GET['friend_id'])) {
$my_current_friend = (int) $_GET['friend_id'];
if (SocialManager::hasInvitationByUser($current_user_id, $my_current_friend)) {
UserManager::relate_users($current_user_id, $my_current_friend, $relation_type);
UserManager::relate_users($my_current_friend, $current_user_id, $relation_type);
SocialManager::invitation_accepted($my_current_friend, $current_user_id);
Display::addFlash(
Display::return_message(get_lang('AddedContactToList'), 'success')
);
}
}
}
header('Location: '.api_get_path(WEB_CODE_PATH).'social/invitations.php');
exit;
case 'deny_friend':
if (api_is_anonymous()) {
echo '';
break;
}
if (Security::check_token('get', null, 'invitation')) {
$relation_type = USER_RELATION_TYPE_UNKNOWN; //Contact unknown
if (isset($_GET['is_my_friend'])) {
$relation_type = USER_RELATION_TYPE_FRIEND; //my friend
}
if (isset($_GET['denied_friend_id'])) {
SocialManager::invitation_denied($_GET['denied_friend_id'], $current_user_id);
Display::addFlash(
Display::return_message(get_lang('InvitationDenied'), 'success')
);
}
}
header('Location: '.api_get_path(WEB_CODE_PATH).'social/invitations.php');
exit;
case 'delete_friend':
if (api_is_anonymous()) {
echo '';
break;
}
if (!Security::check_token('post', null, 'social')) {
exit;
}
if (isset($_POST['delete_friend_id'])) {
$my_delete_friend = (int) $_POST['delete_friend_id'];
SocialManager::remove_user_rel_user($my_delete_friend);
JsonResponse::create([
'secToken' => Security::get_token('social'),
])->send();
break;
}
break;
case 'show_my_friends':
if (api_is_anonymous()) {
echo '';
break;
}
$user_id = api_get_user_id();
$name_search = Security::remove_XSS($_POST['search_name_q']);
if (isset($name_search) && $name_search != 'undefined') {
$friends = SocialManager::get_friends($user_id, null, $name_search);
} else {
$friends = SocialManager::get_friends($user_id);
}
$friend_html = '';
$number_of_images = 8;
$number_friends = count($friends);
if ($number_friends != 0) {
$number_loop = $number_friends / $number_of_images;
$loop_friends = ceil($number_loop);
$j = 0;
for ($k = 0; $k < $loop_friends; $k++) {
if ($j == $number_of_images) {
$number_of_images = $number_of_images * 2;
}
while ($j < $number_of_images) {
if (isset($friends[$j])) {
$friend = $friends[$j];
$user_name = api_xml_http_response_encode($friend['firstName'].' '.$friend['lastName']);
$userPicture = UserManager::getUserPicture($friend['friend_user_id']);
$friend_html .= '
<div class="col-md-3">
<div class="thumbnail text-center" id="div_'.$friends[$j]['friend_user_id'].'">
<img src="'.$userPicture.'" class="img-responsive" id="imgfriend_'.$friend['friend_user_id'].'" title="$user_name">
<div class="caption">
<h3>
<a href="profile.php?u='.$friend['friend_user_id'].'">'.$user_name.'</a>
</h3>
<p>
<button class="btn btn-danger" onclick="delete_friend(this)" id=img_'.$friend['friend_user_id'].'>
'.get_lang('Delete').'
</button>
</p>
</div>
</div>
</div>
';
}
$j++;
}
}
}
echo $friend_html;
break;
case 'toogle_course':
if (api_is_anonymous()) {
echo '';
break;
}
require_once api_get_path(SYS_CODE_PATH).'forum/forumfunction.inc.php';
$user_id = Session::read('social_user_id');
if ($_POST['action']) {
$action = $_POST['action'];
}
switch ($action) {
case 'load_course':
$course_id = intval($_POST['course_code']); // the int course id
$course_info = api_get_course_info_by_id($course_id);
$course_code = $course_info['code'];
if (api_is_user_of_course($course_id, api_get_user_id())) {
//------Forum messages
$forum_result = get_all_post_from_user($user_id, $course_code);
$all_result_data = 0;
if ($forum_result != '') {
echo '<div id="social-forum-main-title">';
echo api_xml_http_response_encode(get_lang('Forum'));
echo '</div>';
echo '<div style="background:#FAF9F6; padding:0px;" >';
echo api_xml_http_response_encode($forum_result);
echo '</div>';
echo '<br />';
$all_result_data++;
}
//------Blog posts
$result = Blog::getBlogPostFromUser($course_id, $user_id, $course_code);
if (!empty($result)) {
api_display_tool_title(api_xml_http_response_encode(get_lang('Blog')));
echo '<div style="background:#FAF9F6; padding:0px;">';
echo api_xml_http_response_encode($result);
echo '</div>';
echo '<br />';
$all_result_data++;
}
//------Blog comments
$result = Blog::getBlogCommentsFromUser($course_id, $user_id, $course_code);
if (!empty($result)) {
echo '<div style="background:#FAF9F6; padding-left:10px;">';
api_display_tool_title(api_xml_http_response_encode(get_lang('BlogComments')));
echo api_xml_http_response_encode($result);
echo '</div>';
echo '<br />';
$all_result_data++;
}
if ($all_result_data == 0) {
echo api_xml_http_response_encode(get_lang('NoDataAvailable'));
}
} else {
echo '<div class="clear"></div><br />';
api_display_tool_title(api_xml_http_response_encode(get_lang('Details')));
echo '<div style="background:#FAF9F6; padding:0px;">';
echo api_xml_http_response_encode(get_lang('UserNonRegisteredAtTheCourse'));
echo '<div class="clear"></div><br />';
echo '</div>';
echo '<div class="clear"></div><br />';
}
break;
case 'unload_course':
default:
break;
}
break;
case 'send_comment':
if (api_is_anonymous()) {
exit;
}
if (api_get_setting('allow_social_tool') !== 'true') {
exit;
}
if (!Security::check_token('get', null, 'wall')) {
exit;
}
$messageId = isset($_GET['id']) ? (int) $_GET['id'] : 0;
if (empty($messageId)) {
exit;
}
$userId = api_get_user_id();
$messageInfo = MessageManager::get_message_by_id($messageId);
if (!empty($messageInfo)) {
$comment = isset($_REQUEST['comment']) ? $_REQUEST['comment'] : '';
if (!empty($comment)) {
$messageId = SocialManager::sendWallMessage(
$userId,
$messageInfo['user_receiver_id'],
$comment,
$messageId,
MESSAGE_STATUS_WALL
);
if ($messageId) {
$messageInfo = MessageManager::get_message_by_id($messageId);
JsonResponse::create([
'secToken' => Security::get_token('wall'),
'postHTML' => SocialManager::processPostComment($messageInfo),
])->send();
}
}
}
break;
case 'delete_message':
if (api_is_anonymous()) {
exit;
}
if (api_get_setting('allow_social_tool') !== 'true') {
exit;
}
$messageId = isset($_GET['id']) ? (int) $_GET['id'] : 0;
if (empty($messageId)) {
exit;
}
if (!Security::check_token('get', null, 'social')) {
exit;
}
$userId = api_get_user_id();
$messageInfo = MessageManager::get_message_by_id($messageId);
if (!empty($messageInfo)) {
$canDelete = ($messageInfo['user_receiver_id'] == $userId || $messageInfo['user_sender_id'] == $userId) &&
empty($messageInfo['group_id']);
if ($canDelete || api_is_platform_admin()) {
SocialManager::deleteMessage($messageId);
echo json_encode([
'message' => Display::return_message(get_lang('MessageDeleted')),
'secToken' => Security::get_token('social'),
]);
break;
}
}
break;
case 'list_wall_message':
if (api_is_anonymous()) {
break;
}
$start = isset($_REQUEST['start']) ? (int) $_REQUEST['start'] : 0;
$userId = isset($_REQUEST['u']) ? (int) $_REQUEST['u'] : api_get_user_id();
$html = '';
if ($userId == api_get_user_id()) {
$threadList = SocialManager::getThreadList($userId);
$threadIdList = [];
if (!empty($threadList)) {
$threadIdList = array_column($threadList, 'id');
}
$html = SocialManager::getMyWallMessages(
$userId,
$start,
SocialManager::DEFAULT_SCROLL_NEW_POST,
$threadIdList
);
$html = $html['posts'];
} else {
$messages = SocialManager::getWallMessages(
$userId,
null,
0,
0,
'',
$start,
SocialManager::DEFAULT_SCROLL_NEW_POST
);
$messages = SocialManager::formatWallMessages($messages);
if (!empty($messages)) {
ksort($messages);
foreach ($messages as $message) {
$post = $message['html'];
$comments = SocialManager::getWallPostComments($userId, $message);
$html .= SocialManager::wrapPost($message, $post.$comments);
}
}
}
if (!empty($html)) {
$html .= Display::div(
Display::url(
get_lang('SeeMore'),
api_get_self().'?u='.$userId.'&a=list_wall_message&start='.
($start + SocialManager::DEFAULT_SCROLL_NEW_POST).'&length='.SocialManager::DEFAULT_SCROLL_NEW_POST,
[
'class' => 'nextPage',
]
),
[
'class' => 'next',
]
);
}
echo $html;
break;
// Read the Url using OpenGraph and returns the hyperlinks content
case 'read_url_with_open_graph':
api_block_anonymous_users(false);
$url = $_POST['social_wall_new_msg_main'] ?? '';
$url = trim($url);
$html = '';
if (SocialManager::verifyUrl($url)) {
$html = Security::remove_XSS(
SocialManager::readContentWithOpenGraph($url)
);
}
echo $html;
break;
case 'like_message':
header('Content-Type: application/json');
if (
api_is_anonymous() ||
!api_get_configuration_value('social_enable_messages_feedback')
) {
echo json_encode(false);
exit;
}
$messageId = isset($_GET['id']) ? (int) $_GET['id'] : 0;
$status = isset($_GET['status']) ? $_GET['status'] : '';
$groupId = isset($_GET['group']) ? (int) $_GET['group'] : 0;
if (empty($messageId) || !in_array($status, ['like', 'dislike'])) {
echo json_encode(false);
exit;
}
$em = Database::getManager();
$messageRepo = $em->getRepository('ChamiloCoreBundle:Message');
$messageLikesRepo = $em->getRepository('ChamiloCoreBundle:MessageFeedback');
/** @var Message $message */
$message = $messageRepo->find($messageId);
if (empty($message)) {
echo json_encode(false);
exit;
}
if ((int) $message->getGroupId() !== $groupId) {
echo json_encode(false);
exit;
}
if (!empty($message->getGroupId())) {
$usergroup = new UserGroup();
$groupInfo = $usergroup->get($groupId);
if (empty($groupInfo)) {
echo json_encode(false);
exit;
}
$isMember = $usergroup->is_group_member($groupId, $current_user_id);
if (GROUP_PERMISSION_CLOSED == $groupInfo['visibility'] && !$isMember) {
echo json_encode(false);
exit;
}
}
$user = api_get_user_entity($current_user_id);
$userLike = $messageLikesRepo->findOneBy(['message' => $message, 'user' => $user]);
if (empty($userLike)) {
$userLike = new MessageFeedback();
$userLike
->setMessage($message)
->setUser($user);
}
if ('like' === $status) {
if ($userLike->isLiked()) {
echo json_encode(false);
exit;
}
$userLike
->setLiked(true)
->setDisliked(false);
} elseif ('dislike' === $status) {
if ($userLike->isDisliked()) {
echo json_encode(false);
exit;
}
$userLike
->setLiked(false)
->setDisliked(true);
}
$userLike
->setUpdatedAt(
api_get_utc_datetime(null, false, true)
);
$em->persist($userLike);
$em->flush();
echo json_encode(true);
break;
default:
echo '';
}
exit;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,133 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CourseBundle\Entity\CLp;
use Chamilo\CourseBundle\Entity\CLpView;
use Symfony\Component\HttpFoundation\Request as HttpRequest;
require_once __DIR__.'/../global.inc.php';
$httpRequest = HttpRequest::createFromGlobals();
$isAllowedToEdit = api_is_allowed_to_edit();
switch ($httpRequest->get('a')) {
case 'form_adquisition':
displayForm(
$httpRequest->query->getInt('lp_view')
);
break;
case 'views_invisible':
processViewsInvisible(
$httpRequest->request->get('chkb_view') ?: [],
$httpRequest->request->getBoolean('state')
);
break;
}
function displayForm(int $lpViewId)
{
$em = Database::getManager();
$lpView = $em->find(CLpView::class, $lpViewId);
if (null === $lpView) {
return;
}
$lp = $em->find(CLp::class, $lpView->getLpId());
$extraField = new ExtraField('lp_view');
$field = $extraField->get_handler_field_info_by_field_variable(StudentFollowPage::VARIABLE_ACQUISITION);
$extraFieldValue = new ExtraFieldValue('lp_view');
$value = $extraFieldValue->get_values_by_handler_and_field_variable(
$lpViewId,
StudentFollowPage::VARIABLE_ACQUISITION
);
$options = [];
foreach ($field['options'] as $option) {
$options[$option['option_value']] = ExtraFieldOption::translateDisplayName($option['display_text']);
}
$frmId = 'frm_lp_acquisition_'.$lpView->getLpId();
$frmAction = api_get_self().'?'.http_build_query(['lp_view' => $lpViewId, 'a' => 'form_adquisition']);
$form = new FormValidator($frmId, 'post', $frmAction);
$form->addRadio(StudentFollowPage::VARIABLE_ACQUISITION, get_lang('Acquisition'), $options);
$form->addHidden('lp_view', $lpViewId);
$form->addButtonSave(get_lang('Save'));
if ($form->validate()) {
$values = $form->exportValues();
$extraFieldValue = new ExtraFieldValue('lp_view');
$extraFieldValue->save(
[
'variable' => StudentFollowPage::VARIABLE_ACQUISITION,
'item_id' => $lpViewId,
'comment' => json_encode(['user' => api_get_user_id(), 'datetime' => api_get_utc_datetime()]),
'value' => $values[StudentFollowPage::VARIABLE_ACQUISITION],
]
);
echo StudentFollowPage::getLpAcquisition(
[
'iid' => $lp->getIid(),
'lp_name' => $lp->getName(),
],
$lpView->getUserId(),
$lpView->getCId(),
$lpView->getSessionId(),
true
);
exit;
}
if (!empty($value)) {
$form->setDefaults([StudentFollowPage::VARIABLE_ACQUISITION => $value['value']]);
}
echo $form->returnForm()
."<script>$(function () {
$('#$frmId').on('submit', function (e) {
e.preventDefault();
var self = $(this);
self.find(':submit').prop('disabled', true);
$.post(this.action, self.serialize()).done(function (response) {
$('#acquisition-$lpViewId').html(response);
$('#global-modal').modal('hide');
self.find(':submit').prop('disabled', false);
});
})
})</script>";
}
function processViewsInvisible(array $lpViews, bool $state)
{
foreach ($lpViews as $lpViewData) {
$parts = explode('_', $lpViewData);
[$lpId, $userId, $courseId, $sessionId] = array_map('intval', $parts);
$lpView = learnpath::findLastView($lpId, $userId, $courseId, $sessionId, true);
$extraFieldValue = new ExtraFieldValue('lp_view');
$extraFieldValue->save(
[
'variable' => StudentFollowPage::VARIABLE_INVISIBLE,
'item_id' => $lpView['iid'],
'comment' => json_encode(['user' => api_get_user_id(), 'datetime' => api_get_utc_datetime()]),
'value' => $state,
]
);
}
}

View File

@@ -0,0 +1,59 @@
<?php
/* For licensing terms, see /license.txt */
require_once __DIR__.'/../global.inc.php';
$current_user_id = api_get_user_id();
$courseId = api_get_course_int_id();
$action = isset($_GET['a']) ? $_GET['a'] : null;
$surveyId = isset($_REQUEST['survey_id']) ? $_REQUEST['survey_id'] : 0;
$questionId = isset($_REQUEST['question_id']) ? $_REQUEST['question_id'] : 0;
switch ($action) {
case 'load_question_options':
if (!api_is_allowed_to_edit(false, true)) {
exit;
}
$question = SurveyManager::get_question($questionId);
if (!empty($question) && !empty($question['answer_data'])) {
$optionList = [];
foreach ($question['answer_data'] as $answer) {
$optionList[$answer['iid']] = strip_tags($answer['data']);
}
echo json_encode($optionList);
}
break;
case 'save_question':
if (api_is_anonymous()) {
echo '';
break;
}
$status = isset($_GET['status']) ? (int) $_GET['status'] : null;
$userId = api_get_user_id();
$surveyData = SurveyManager::get_survey($surveyId);
if (empty($surveyData)) {
exit;
}
SurveyUtil::remove_answer(
$userId,
$surveyId,
$questionId,
$courseId
);
SurveyUtil::store_answer(
$userId,
$surveyId,
$questionId,
1,
$status,
$surveyData
);
break;
}
exit;

View File

@@ -0,0 +1,161 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Responses to AJAX calls for thematic.
*/
require_once __DIR__.'/../global.inc.php';
api_protect_course_script(true);
$action = $_GET['a'];
$thematic = new Thematic();
switch ($action) {
case 'save_thematic_plan':
/*$title_list = $_REQUEST['title'];
$description_list = $_REQUEST['desc'];
//$description_list = $_REQUEST['description'];
$description_type = $_REQUEST['description_type'];
if (api_is_allowed_to_edit(null, true)) {
for($i=1;$i<count($title_list)+1; $i++) {
$thematic->set_thematic_plan_attributes($_REQUEST['thematic_id'], $title_list[$i], $description_list[$i], $description_type[$i]);
$affected_rows = $thematic->thematic_plan_save();
}
}
$thematic_plan_data = $thematic->get_thematic_plan_data();
$return = $thematic->get_thematic_plan_div($thematic_plan_data);
echo $return[$_REQUEST['thematic_id']];*/
break;
case 'save_thematic_advance':
if (!api_is_allowed_to_edit(null, true)) {
echo '';
exit;
}
/*
if (($_REQUEST['start_date_type'] == 1 && empty($_REQUEST['start_date_by_attendance'])) || (!empty($_REQUEST['duration_in_hours']) && !is_numeric($_REQUEST['duration_in_hours'])) ) {
if ($_REQUEST['start_date_type'] == 1 && empty($_REQUEST['start_date_by_attendance'])) {
$start_date_error = true;
$data['start_date_error'] = $start_date_error;
}
if (!empty($_REQUEST['duration_in_hours']) && !is_numeric($_REQUEST['duration_in_hours'])) {
$duration_error = true;
$data['duration_error'] = $duration_error;
}
$data['action'] = $_REQUEST['action'];
$data['thematic_id'] = $_REQUEST['thematic_id'];
$data['attendance_select'] = $attendance_select;
if (isset($_REQUEST['thematic_advance_id'])) {
$data['thematic_advance_id'] = $_REQUEST['thematic_advance_id'];
$thematic_advance_data = $thematic->get_thematic_advance_list($_REQUEST['thematic_advance_id']);
$data['thematic_advance_data'] = $thematic_advance_data;
}
} else {
if ($_REQUEST['thematic_advance_token'] == $_SESSION['thematic_advance_token'] && api_is_allowed_to_edit(null, true)) {
$thematic_advance_id = $_REQUEST['thematic_advance_id'];
$thematic_id = $_REQUEST['thematic_id'];
$content = $_REQUEST['real_content'];
$duration = $_REQUEST['duration_in_hours'];
if (isset($_REQUEST['start_date_type']) && $_REQUEST['start_date_type'] == 2) {
$start_date = $thematic->build_datetime_from_array($_REQUEST['custom_start_date']);
$attendance_id = 0;
} else {
$start_date = $_REQUEST['start_date_by_attendance'];
$attendance_id = $_REQUEST['attendance_select'];
}
$thematic->set_thematic_advance_attributes($thematic_advance_id, $thematic_id, $attendance_id, $content, $start_date, $duration);
$affected_rows = $thematic->thematic_advance_save();
if ($affected_rows) {
// get last done thematic advance before move thematic list
$last_done_thematic_advance = $thematic->get_last_done_thematic_advance();
// update done advances with de current thematic list
if (!empty($last_done_thematic_advance)) {
$update_done_advances = $thematic->update_done_thematic_advances($last_done_thematic_advance);
}
}
}
}
$thematic_advance_data = $thematic->get_thematic_advance_list(null, null, true);
$return = $thematic->get_thematic_advance_div($thematic_advance_data);
echo $return[$_REQUEST['thematic_id']][$_REQUEST['thematic_advance_id']];*/
break;
case 'get_datetime_by_attendance':
$attendance_id = intval($_REQUEST['attendance_id']);
$thematic_advance_id = intval($_REQUEST['thematic_advance_id']);
$label = '';
$input_select = '';
if (!empty($attendance_id)) {
$attendance = new Attendance();
$thematic = new Thematic();
$thematic_list = $thematic->get_thematic_list();
$my_list = $thematic_list_temp = [];
foreach ($thematic_list as $item) {
$my_list = $thematic->get_thematic_advance_by_thematic_id($item['id']);
$thematic_list_temp = array_merge($my_list, $thematic_list_temp);
}
$new_thematic_list = [];
foreach ($thematic_list_temp as $item) {
if (!empty($item['attendance_id'])) {
$new_thematic_list[$item['id']] = [
'attendance_id' => $item['attendance_id'],
'start_date' => $item['start_date'],
];
}
}
$attendance_calendar = $attendance->get_attendance_calendar($attendance_id);
$label = get_lang('StartDate');
if (!empty($attendance_calendar)) {
$input_select .= '<select id="start_date_select_calendar" name="start_date_by_attendance" size="7" class="form-control">';
foreach ($attendance_calendar as $calendar) {
$selected = null;
$insert = true;
//checking if was already taken
foreach ($new_thematic_list as $key => $thematic_item) {
if ($calendar['db_date_time'] == $thematic_item['start_date']) {
$insert = false;
if ($thematic_advance_id == $key) {
$insert = true;
$selected = 'selected';
}
break;
}
}
if ($insert == true) {
$input_select .= '<option '.$selected.' value="'.$calendar['date_time'].'">'.$calendar['date_time'].'</option>';
}
}
$input_select .= '</select>';
} else {
$input_select .= '<em>'.get_lang('ThereAreNoRegisteredDatetimeYet').'</em>';
}
}
?>
<div class="form-group">
<label class="col-sm-2 control-label"><?php echo $label; ?></label>
<div class="col-sm-8"><?php echo $input_select; ?></div>
</div>
<?php
break;
case 'update_done_thematic_advance':
$thematic_advance_id = intval($_GET['thematic_advance_id']);
$total_average = 0;
if (!empty($thematic_advance_id)) {
$thematic = new Thematic();
$affected_rows = $thematic->update_done_thematic_advances($thematic_advance_id);
$total_average = $thematic->get_total_average_of_thematic_advances(
api_get_course_id(),
api_get_session_id()
);
}
echo $total_average;
break;
default:
echo '';
}
exit;

View File

@@ -0,0 +1,15 @@
<?php
/* For licensing terms, see /license.txt */
require_once __DIR__.'/../global.inc.php';
$timeline = new Timeline();
$action = $_GET['a'];
switch ($action) {
case 'get_timeline_content':
$items = $timeline->get_timeline_content($_GET['id']);
echo json_encode($items);
break;
}

View File

@@ -0,0 +1,549 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\UserBundle\Entity\User;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\Query\Expr\Join;
use Symfony\Component\HttpFoundation\Request as HttpRequest;
/**
* Responses to AJAX calls.
*/
require_once __DIR__.'/../global.inc.php';
$request = HttpRequest::createFromGlobals();
$isRequestByAjax = $request->isXmlHttpRequest();
$action = $_REQUEST['a'];
switch ($action) {
case 'comment_attendance':
$selected = $_REQUEST['selected'];
$comment = $_REQUEST['comment'];
$attendanceId = (int) $_REQUEST['attendance_id'];
if (!empty($selected)) {
list($prefix, $userId, $attendanceCalendarId) = explode('-', $selected);
$attendance = new Attendance();
$attendance->saveComment(
(int) $userId,
(int) $attendanceCalendarId,
$comment,
$attendanceId
);
echo 1;
exit;
}
echo 0;
break;
case 'get_attendance_comment':
$selected = $_REQUEST['selected'];
if (!empty($selected)) {
list($prefix, $userId, $attendanceCalendarId) = explode('-', $selected);
$attendance = new Attendance();
$commentInfo = $attendance->getComment(
(int) $userId,
(int) $attendanceCalendarId
);
echo json_encode(
[
'comment' => $commentInfo['comment'],
'author' => !empty($commentInfo['author']) ? get_lang('Author').': '.$commentInfo['author'] : '',
]
);
}
break;
case 'block_attendance_calendar':
$calendarId = (int) $_REQUEST['calendar_id'];
$attendance = new Attendance();
$attendance->updateCalendarBlocked($calendarId);
echo (int) $attendance->isCalendarBlocked($calendarId);
break;
case 'get_attendance_sign':
$selected = $_REQUEST['selected'];
if (!empty($selected)) {
list($prefix, $userId, $attendanceCalendarId) = explode('-', $selected);
$attendance = new Attendance();
$signature = $attendance->getSignature($userId, $attendanceCalendarId);
echo $signature;
}
break;
case 'remove_attendance_sign':
$selected = $_REQUEST['selected'];
$attendanceId = (int) $_REQUEST['attendance_id'];
if (!empty($selected)) {
list($prefix, $userId, $attendanceCalendarId) = explode('-', $selected);
$attendance = new Attendance();
$attendance->deleteSignature($userId, $attendanceCalendarId, $attendanceId);
}
break;
case 'sign_attendance':
$selected = $_REQUEST['selected'];
$file = isset($_REQUEST['file']) ? $_REQUEST['file'] : '';
$file = str_replace(' ', '+', $file);
$attendanceId = $_REQUEST['attendance_id'];
if (!empty($selected)) {
list($prefix, $userId, $attendanceCalendarId, $courseId) = explode('-', $selected);
$attendance = new Attendance();
$attendance->saveSignature($userId, $attendanceCalendarId, $file, $attendanceId, $courseId);
echo 1;
exit;
}
echo 0;
break;
case 'set_expiration_date':
$status = (int) $_REQUEST['status'];
$dates = UserManager::getExpirationDateByRole($status);
echo json_encode($dates);
break;
case 'get_user_like':
if (api_is_platform_admin() || api_is_drh() || api_is_session_admin()) {
$query = $_REQUEST['q'];
$conditions = [
'username' => $query,
'firstname' => $query,
'lastname' => $query,
];
$users = UserManager::getUserListLike($conditions, [], false, 'OR');
$result = [];
if (!empty($users)) {
foreach ($users as $user) {
$result[] = ['id' => $user['id'], 'text' => $user['complete_name'].' ('.$user['username'].')'];
}
$result['items'] = $result;
}
echo json_encode($result);
}
break;
case 'get_user_popup':
if (!$isRequestByAjax) {
break;
}
$courseId = (int) $request->get('course_id');
$sessionId = (int) $request->get('session_id');
$hash = (string) $request->get('hash');
$userId = (int) UserManager::decryptUserHash($hash);
$user_info = api_get_user_info($userId);
if (empty($user_info)) {
break;
}
if ($courseId) {
$courseInfo = api_get_course_info_by_id($courseId);
if (empty($courseInfo)) {
break;
}
}
if ($sessionId) {
$sessionInfo = api_get_session_info($sessionId);
if (empty($sessionInfo)) {
break;
}
}
$isAnonymous = api_is_anonymous();
if ($isAnonymous && empty($courseId)) {
break;
}
if ($isAnonymous && $courseId) {
if ('false' === api_get_setting('course_catalog_published')) {
break;
}
$coursesNotInCatalog = CoursesAndSessionsCatalog::getCoursesToAvoid();
if (in_array($courseId, $coursesNotInCatalog)) {
break;
}
}
echo '<div class="row">';
echo '<div class="col-sm-5">';
echo '<div class="thumbnail">';
echo Display::img($user_info['avatar'], $user_info['complete_name']);
echo '</div>';
echo '</div>';
echo '<div class="col-sm-7">';
if ($isAnonymous || api_get_setting('show_email_addresses') == 'false') {
$user_info['mail'] = '';
}
$userData = '<h3>'.$user_info['complete_name'].'</h3>'
.PHP_EOL
.$user_info['mail']
.PHP_EOL
.$user_info['official_code'];
if ($isAnonymous) {
// Only allow anonymous users to see user popup if the popup user
// is a teacher (which might be necessary to illustrate a course)
if ((int) $user_info['status'] === COURSEMANAGER) {
echo $userData;
}
} else {
echo Display::url(
$userData,
api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_info['user_id']
);
}
echo '</div>';
echo '</div>';
$url = api_get_path(WEB_AJAX_PATH).'message.ajax.php?'
.http_build_query(
[
'a' => 'send_message',
'user_id' => $user_info['user_id'],
'course_id' => $courseId,
'session_id' => $sessionId,
]
);
if ($isAnonymous === false &&
api_get_setting('allow_message_tool') == 'true'
) {
echo '<script>';
echo '
$("#send_message_link").on("click", function() {
var url = "'.$url.'";
var params = $("#send_message").serialize();
$.ajax({
url: url+"&"+params,
success:function(data) {
$("#subject_id").val("");
$("#content_id").val("");
$("#send_message").html(data);
$("#send_message_link").hide();
}
});
});';
echo '</script>';
echo MessageManager::generate_message_form();
echo '
<div class="row">
<div class="col-sm-10 col-sm-offset-2">
<a class="btn btn-primary" id="send_message_link">
<em class="fa fa-envelope"></em> '.get_lang('Send').'
</a>
</div>
</div>
';
}
break;
case 'user_id_exists':
if (api_is_anonymous()) {
echo '';
} else {
if (UserManager::is_user_id_valid($_GET['user_id'])) {
echo 1;
} else {
echo 0;
}
}
break;
case 'search_tags':
header('Content-Type: application/json');
$result = ['items' => []];
if (api_is_anonymous()) {
echo json_encode($result);
break;
}
if (!isset($_GET['q'], $_GET['field_id'])) {
echo json_encode($result);
break;
}
$result['items'] = UserManager::get_tags($_GET['q'], $_GET['field_id'], null, '10');
echo json_encode($result);
break;
case 'generate_api_key':
if (api_is_anonymous()) {
echo '';
} else {
$array_list_key = [];
$user_id = api_get_user_id();
$api_service = 'dokeos';
$num = UserManager::update_api_key($user_id, $api_service);
$array_list_key = UserManager::get_api_keys($user_id, $api_service); ?>
<div class="form-group">
<label class="col-sm-2 control-label"><?php echo get_lang('MyApiKey'); ?></label>
<div class="col-sm-8">
<input type="text" name="api_key_generate" id="id_api_key_generate" class="form-control" value="<?php echo $array_list_key[$num]; ?>"/>
</div>
</div>
<?php
}
break;
case 'active_user':
$allow = api_get_configuration_value('allow_disable_user_for_session_admin');
if ((api_is_platform_admin() && api_global_admin_can_edit_admin($_GET['user_id'])) ||
(
$allow &&
api_is_session_admin() &&
api_global_admin_can_edit_admin($_GET['user_id'], null, true)
)
) {
$user_id = intval($_GET['user_id']);
$status = intval($_GET['status']);
if (!empty($user_id)) {
$user_table = Database::get_main_table(TABLE_MAIN_USER);
$sql = "UPDATE $user_table
SET active = '".$status."'
WHERE user_id = '".$user_id."'";
$result = Database::query($sql);
// Send and email if account is active
if ($status == 1) {
$user_info = api_get_user_info($user_id);
$recipientName = api_get_person_name(
$user_info['firstname'],
$user_info['lastname'],
null,
PERSON_NAME_EMAIL_ADDRESS
);
$subject = '['.api_get_setting('siteName').'] '.get_lang('YourReg').' '.api_get_setting('siteName');
$emailAdmin = api_get_setting('emailAdministrator');
$sender_name = api_get_person_name(
api_get_setting('administratorName'),
api_get_setting('administratorSurname'),
null,
PERSON_NAME_EMAIL_ADDRESS
);
$body = get_lang('Dear')." ".stripslashes($recipientName).",\n\n";
$body .= sprintf(
get_lang('YourAccountOnXHasJustBeenApprovedByOneOfOurAdministrators'),
api_get_setting('siteName')
)."\n";
$body .= sprintf(
get_lang('YouCanNowLoginAtXUsingTheLoginAndThePasswordYouHaveProvided'),
api_get_path(WEB_PATH)
).",\n\n";
$body .= get_lang('HaveFun')."\n\n";
//$body.=get_lang('Problem'). "\n\n". get_lang('SignatureFormula');
$body .= api_get_person_name(
api_get_setting('administratorName'),
api_get_setting('administratorSurname')
)."\n".
get_lang('Manager')." ".
api_get_setting('siteName')."\nT. ".api_get_setting('administratorTelephone')."\n".
get_lang('Email')." : ".api_get_setting('emailAdministrator');
$additionalParameters = [
'smsType' => SmsPlugin::ACCOUNT_APPROVED_CONNECT,
'userId' => $user_id,
];
MessageManager::send_message_simple(
$user_id,
$subject,
$body,
null,
false,
false,
$additionalParameters
);
Event::addEvent(LOG_USER_ENABLE, LOG_USER_ID, $user_id);
} else {
Event::addEvent(LOG_USER_DISABLE, LOG_USER_ID, $user_id);
}
echo $status;
}
} else {
echo '-1';
}
break;
case 'user_by_role':
if (!api_is_platform_admin()) {
api_not_allowed(false, null, 403);
}
$status = isset($_REQUEST['status']) ? (int) $_REQUEST['status'] : DRH;
$active = isset($_REQUEST['active']) ? (int) $_REQUEST['active'] : null;
$criteria = new Criteria();
$criteria
->where(
Criteria::expr()->orX(
Criteria::expr()->contains('username', $_REQUEST['q']),
Criteria::expr()->contains('firstname', $_REQUEST['q']),
Criteria::expr()->contains('lastname', $_REQUEST['q'])
)
)
->andWhere(
Criteria::expr()->eq('status', $status)
);
if (null !== $active) {
$criteria->andWhere(Criteria::expr()->eq('active', $active));
}
$users = UserManager::getRepository()->matching($criteria);
if (!$users->count()) {
echo json_encode([]);
break;
}
$items = [];
/** @var User $user */
foreach ($users as $user) {
$items[] = [
'id' => $user->getId(),
'text' => UserManager::formatUserFullName($user, true),
];
}
header('Content-Type: application/json');
echo json_encode(['items' => $items]);
break;
case 'teacher_to_basis_course':
api_block_anonymous_users(false);
$sortByFirstName = api_sort_by_first_name();
$urlId = api_get_current_access_url_id();
$qb = UserManager::getRepository()->createQueryBuilder('u');
$qb->where(
$qb->expr()->orX(
$qb->expr()->like('u.username', ':q'),
$qb->expr()->like('u.firstname', ':q'),
$qb->expr()->like('u.lastname', ':q')
)
);
if (api_is_multiple_url_enabled()) {
$qb
->innerJoin('ChamiloCoreBundle:AccessUrlRelUser', 'uru', Join::WITH, 'u.userId = uru.userId')
->andWhere('uru.accessUrlId = '.$urlId);
}
$qb
->andWhere(
$qb->expr()->in('u.status', UserManager::getAllowedRolesAsTeacher())
)
->orderBy(
$sortByFirstName
? 'u.firstname, u.lastname'
: 'u.lastname, u.firstname'
)
->setParameter('q', '%'.$_REQUEST['q'].'%');
$users = $qb->getQuery()->getResult();
if (!$users) {
echo json_encode([]);
break;
}
$items = [];
/** @var User $user */
foreach ($users as $user) {
$items[] = [
'id' => $user->getId(),
'text' => UserManager::formatUserFullName($user, true),
];
}
header('Content-Type: application/json');
echo json_encode(['items' => $items]);
break;
case 'update_users':
$usersData = json_decode($_POST['users'], true);
$updatedCount = 0;
foreach ($usersData as $userData) {
if (empty($userData['user_id'])) {
continue;
}
$userId = (int) $userData['user_id'];
$currentUserData = api_get_user_info($userId);
if (!$currentUserData) {
continue;
}
$updatedData = [
'firstname' => $userData['firstname'] ?? $currentUserData['firstname'],
'lastname' => $userData['lastname'] ?? $currentUserData['lastname'],
'email' => $userData['email'] ?? $currentUserData['email'],
'phone' => $userData['phone'] ?? $currentUserData['phone'],
'official_code' => $userData['official_code'] ?? $currentUserData['official_code'],
'status' => isset($userData['status']) ? (int) $userData['status'] : $currentUserData['status'],
'active' => isset($userData['active']) ? (int) $userData['active'] : $currentUserData['active'],
];
if (!empty($userData['password'])) {
$updatedData['password'] = $userData['password'];
}
$extraFieldHandler = new ExtraField('user');
$extraFieldValue = new ExtraFieldValue('user');
$extraFields = [];
foreach ($userData as $key => &$value) {
if (strpos($key, 'extra_') === 0) {
$fieldName = str_replace('extra_', '', $key);
$fieldInfo = $extraFieldHandler->get_handler_field_info_by_field_variable($fieldName);
if ($fieldInfo) {
if ($fieldInfo['field_type'] == 10 && is_string($value) && strpos($value, ',') !== false) {
$value = explode(',', $value);
}
}
}
}
UserManager::update_user(
$userId,
$updatedData['firstname'],
$updatedData['lastname'],
$currentUserData['username'],
$updatedData['password'] ?? null,
$currentUserData['auth_source'],
$updatedData['email'],
$updatedData['status'],
$updatedData['official_code'],
$updatedData['phone'],
$currentUserData['picture_uri'],
null,
$updatedData['active'],
null,
null,
null,
$currentUserData['language']
);
$userData['item_id'] = $userId;
$extraFieldValue->saveFieldValues(
$userData,
false,
false,
[],
[],
true
);
$updatedCount++;
}
echo json_encode(['message' => get_lang('Saved').' '.$updatedCount]);
break;
default:
echo '';
}
exit;

View File

@@ -0,0 +1,57 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Responses to AJAX calls.
*/
use Symfony\Component\HttpFoundation\Request as HttpRequest;
require_once __DIR__.'/../global.inc.php';
$httpRequest = HttpRequest::createFromGlobals();
$action = $httpRequest->query->has('a') ? $httpRequest->query->get('a') : $httpRequest->request->get('a');
$isAllowedToEdit = api_is_allowed_to_edit();
switch ($action) {
case 'get_class_by_keyword':
$keyword = $httpRequest->query->has('q') ? $httpRequest->query->get('q') : $httpRequest->request->get('q');
$allow = api_is_platform_admin() || api_is_session_admin();
if ($allow && !empty($keyword)) {
$userGroup = new UserGroup();
$where = ['where' => ['name like ?' => "%$keyword%"], 'order' => 'name '];
$items = [];
$list = $userGroup->get_all($where);
foreach ($list as $class) {
$items[] = [
'id' => $class['id'],
'text' => $class['name'],
];
}
echo json_encode(['items' => $items]);
}
break;
case 'delete_user_in_usergroup':
if ($isAllowedToEdit) {
$userGroup = new UserGroup();
$userId = $httpRequest->query->has('id')
? $httpRequest->query->getInt('id')
: $httpRequest->request->getInt('id');
$userIdList = explode(',', $userId);
$groupId = $httpRequest->query->has('group_id')
? $httpRequest->query->getInt('group_id')
: $httpRequest->request->getInt('group_id');
foreach ($userIdList as $userId) {
$userGroup->delete_user_rel_group($userId, $groupId);
}
}
break;
default:
echo '';
break;
}
exit;

253
main/inc/ajax/work.ajax.php Normal file
View File

@@ -0,0 +1,253 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Responses to AJAX calls.
*/
require_once __DIR__.'/../global.inc.php';
require_once api_get_path(SYS_CODE_PATH).'work/work.lib.php';
$action = isset($_REQUEST['a']) ? $_REQUEST['a'] : null;
$isAllowedToEdit = api_is_allowed_to_edit();
$courseInfo = api_get_course_info();
switch ($action) {
case 'show_student_work':
api_protect_course_script(true);
if ($isAllowedToEdit) {
$itemList = isset($_REQUEST['item_list']) ? $_REQUEST['item_list'] : [];
$itemList = explode(',', $itemList);
if (!empty($itemList)) {
foreach ($itemList as $itemId) {
makeVisible($itemId, $courseInfo);
}
echo '1';
exit;
}
}
echo '0';
break;
case 'hide_student_work':
api_protect_course_script(true);
if ($isAllowedToEdit) {
$itemList = isset($_REQUEST['item_list']) ? $_REQUEST['item_list'] : [];
$itemList = explode(',', $itemList);
if (!empty($itemList)) {
foreach ($itemList as $itemId) {
makeInvisible($itemId, $courseInfo);
}
echo '1';
exit;
}
}
echo '0';
break;
case 'delete_student_work':
api_protect_course_script(true);
if ($isAllowedToEdit) {
if (empty($_REQUEST['id'])) {
return false;
}
$itemList = explode(',', $_REQUEST['id']);
foreach ($itemList as $itemId) {
deleteWorkItem($itemId, $courseInfo);
}
echo '1';
exit;
}
echo '0';
break;
case 'upload_file':
api_protect_course_script(true);
if (isset($_REQUEST['chunkAction']) && 'send' === $_REQUEST['chunkAction']) {
// It uploads the files in chunks
if (!empty($_FILES)) {
$tempDirectory = api_get_path(SYS_ARCHIVE_PATH);
$files = $_FILES['files'];
$fileList = [];
foreach ($files as $name => $array) {
$counter = 0;
foreach ($array as $data) {
$fileList[$counter][$name] = $data;
$counter++;
}
}
if (!empty($fileList)) {
foreach ($fileList as $n => $file) {
$tmpFile = disable_dangerous_file(
api_replace_dangerous_char($file['name'])
);
file_put_contents(
$tempDirectory.$tmpFile,
fopen($file['tmp_name'], 'r'),
FILE_APPEND
);
}
}
}
echo json_encode([
'files' => $_FILES,
'errorStatus' => 0,
]);
exit;
} else {
$workId = isset($_REQUEST['id']) ? $_REQUEST['id'] : '';
$workInfo = get_work_data_by_id($workId);
$sessionId = api_get_session_id();
$userId = api_get_user_id();
$groupId = api_get_group_id();
$onlyOnePublication = api_get_configuration_value('allow_only_one_student_publication_per_user');
if ($onlyOnePublication) {
$count = get_work_count_by_student($userId, $workId);
if ($count >= 1) {
exit;
}
}
if (!empty($_FILES)) {
$files = $_FILES['files'];
$fileList = [];
foreach ($files as $name => $array) {
$counter = 0;
foreach ($array as $data) {
$fileList[$counter][$name] = $data;
$counter++;
}
}
$resultList = [];
foreach ($fileList as $fileInfo) {
$file = processChunkedFile($fileInfo);
$globalFile = [];
$globalFile['files'] = $file;
$values = [
'contains_file' => 1,
'title' => $file['name'],
'description' => '',
];
$result = processWorkForm(
$workInfo,
$values,
$courseInfo,
$sessionId,
$groupId,
$userId,
$file,
api_get_configuration_value('assignment_prevent_duplicate_upload'),
false
);
$json = [];
if (!empty($result) && is_array($result) && empty($result['error'])) {
$json['name'] = api_htmlentities($result['title']);
$json['link'] = Display::url(
api_htmlentities($result['title']),
api_htmlentities($result['view_url']),
['target' => '_blank']
);
$json['url'] = $result['view_url'];
$json['size'] = '';
$json['type'] = api_htmlentities($result['filetype']);
$json['result'] = Display::return_icon(
'accept.png',
get_lang('Uploaded')
);
} else {
$json['url'] = '';
$json['error'] = isset($result['error']) ? $result['error'] : get_lang('Error');
}
$resultList[] = $json;
}
echo json_encode(['files' => $resultList]);
exit;
}
}
break;
case 'delete_work':
if ($isAllowedToEdit) {
if (empty($_REQUEST['id'])) {
return false;
}
$workList = explode(',', $_REQUEST['id']);
foreach ($workList as $workId) {
deleteDirWork($workId);
}
}
break;
case 'upload_correction_file':
api_protect_course_script(true);
// User access same as upload.php
$is_allowed_to_edit = api_is_allowed_to_edit(null, true);
$itemId = isset($_GET['item_id']) ? (int) $_GET['item_id'] : '';
$result = [];
if (!empty($_FILES) && !empty($itemId)) {
$file = $_FILES['file'];
$courseInfo = api_get_course_info();
$workInfo = get_work_data_by_id($itemId);
$workInfoParent = get_work_data_by_id($workInfo['parent_id']);
$resultUpload = uploadWork($workInfoParent, $courseInfo, true, $workInfo);
if (!$resultUpload) {
echo 'false';
break;
}
$work_table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
if (isset($resultUpload['url']) && !empty($resultUpload['url'])) {
$title = isset($resultUpload['filename']) && !empty($resultUpload['filename']) ? $resultUpload['filename'] : get_lang('Untitled');
$url = Database::escape_string($resultUpload['url']);
$title = Database::escape_string($title);
$sql = "UPDATE $work_table SET
url_correction = '".$url."',
title_correction = '".$title."'
WHERE iid = $itemId";
Database::query($sql);
$result['title'] = $resultUpload['filename'];
$result['url'] = 'view.php?'.api_get_cidreq().'&id='.$itemId;
$json = [];
$json['name'] = Display::url(
api_htmlentities($result['title']),
api_htmlentities($result['url']),
['target' => '_blank']
);
$json['type'] = api_htmlentities($file['type']);
$json['size'] = format_file_size($file['size']);
}
if (isset($result['url'])) {
$json['result'] = Display::return_icon(
'accept.png',
get_lang('Uploaded'),
[],
ICON_SIZE_TINY
);
} else {
$json['result'] = Display::return_icon(
'exclamation.png',
get_lang('Error'),
[],
ICON_SIZE_TINY
);
}
header('Content-Type: application/json');
echo json_encode($json);
}
break;
default:
echo '';
break;
}
exit;

119
main/inc/email_editor.php Normal file
View File

@@ -0,0 +1,119 @@
<?php
/* For licensing terms, see /license.txt */
use ChamiloSession as Session;
/**
* This script contains the code to edit and send an e-mail to one of
* the platform's users.
* It can be called from the JavaScript library email_links.lib.php which
* overtakes the mailto: links to use the internal interface instead.
*
* @author Yannick Warnier <ywarnier@beeznest.org>
* @author Julio Montoya <gugli100@gmail.com> Updating form with formvalidator
*/
require_once __DIR__.'/../inc/global.inc.php';
if (empty(api_get_user_id()) || ("true" !== api_get_setting('allow_email_editor'))) {
api_not_allowed(true);
}
$_user = api_get_user_info();
$originUrl = Session::read('origin_url');
if (empty($originUrl)) {
Session::write('origin_url', $_SERVER['HTTP_REFERER']);
}
$action = isset($_GET['action']) ? $_GET['action'] : null;
$form = new FormValidator('email_editor', 'post');
$form->addElement('hidden', 'dest');
$form->addElement('text', 'email_address', get_lang('EmailDestination'));
$form->addElement('text', 'email_title', get_lang('EmailTitle'));
$form->freeze('email_address');
$form->addElement('textarea', 'email_text', get_lang('EmailText'), ['rows' => '6']);
$form->addRule('email_address', get_lang('ThisFieldIsRequired'), 'required');
$form->addRule('email_title', get_lang('ThisFieldIsRequired'), 'required');
$form->addRule('email_text', get_lang('ThisFieldIsRequired'), 'required');
$form->addRule('email_address', get_lang('EmailWrong'), 'email');
$form->addButtonSend(get_lang('SendMail'));
switch ($action) {
case 'subscribe_me_to_session':
$sessionName = isset($_GET['session']) ? Security::remove_XSS($_GET['session']) : null;
$objTemplate = new Template();
$objTemplate->assign('session_name', $sessionName);
$objTemplate->assign('user', api_get_user_info(api_get_user_id(), false, false, true));
$mailTemplate = $objTemplate->get_template('mail/subscribe_me_to_session.tpl');
$emailDest = api_get_setting('emailAdministrator');
$emailTitle = get_lang('SubscribeToSessionRequest');
$emailText = $objTemplate->fetch($mailTemplate);
break;
default:
$emailDest = isset($_REQUEST['dest']) ? Security::remove_XSS($_REQUEST['dest']) : '';
$emailTitle = isset($_REQUEST['subject']) ? Security::remove_XSS($_REQUEST['subject']) : '';
$emailText = isset($_REQUEST['body']) ? Security::remove_XSS($_REQUEST['body']) : '';
break;
}
$defaults = [
'dest' => $emailDest,
'email_address' => $emailDest,
'email_title' => $emailTitle,
'email_text' => $emailText,
];
$form->setDefaults($defaults);
if ($form->validate()) {
$check = Security::check_token();
Security::clear_token();
if ($check) {
Security::clear_token();
$values = $form->getSubmitValues();
$text = nl2br($values['email_text']).'<br /><br /><br />'.get_lang('EmailSentFromLMS').' '.api_get_path(
WEB_PATH
);
$email_administrator = $values['dest'];
$title = $values['email_title'];
if (!empty($_user['mail'])) {
api_mail_html(
'',
$email_administrator,
$title,
$text,
api_get_person_name($_user['firstname'], $_user['lastname']),
$_user['mail'],
[
'reply_to' => [
'mail' => $_user['mail'],
'name' => api_get_person_name($_user['firstname'], $_user['lastname']),
],
]
);
} else {
api_mail_html(
'',
$email_administrator,
$title,
$text,
get_lang('Anonymous')
);
}
Display::addFlash(Display::return_message(get_lang('MessageSent')));
$orig = Session::read('origin_url');
Session::erase('origin_url');
header('Location:'.$orig);
exit;
}
}
$form->addHidden('sec_token', Security::get_token());
Display::display_header(get_lang('SendEmail'));
$form->display();
Display::display_footer();

View File

@@ -0,0 +1,72 @@
<?php
/* For licensing terms, see /license.txt */
use ChamiloSession as Session;
/**
* This script contains the code to send an e-mail to the portal admin.
*/
require_once __DIR__.'/../inc/global.inc.php';
if (false === api_get_configuration_value('allow_email_editor_for_anonymous')) {
api_not_allowed(true);
}
$originUrl = Session::read('origin_url');
if (empty($originUrl) && isset($_SERVER['HTTP_REFERER'])) {
Session::write('origin_url', $_SERVER['HTTP_REFERER']);
}
$action = isset($_GET['action']) ? $_GET['action'] : null;
$form = new FormValidator('email_editor', 'post');
$form->addText('email', get_lang('Email'));
$form->addRule('email', get_lang('EmailWrong'), 'email');
$form->addText('email_title', get_lang('EmailTitle'));
$form->addTextarea('email_text', get_lang('Message'), ['rows' => '6'], true);
$form->addCaptcha();
$form->addButtonSend(get_lang('SendMail'));
$emailTitle = isset($_REQUEST['subject']) ? Security::remove_XSS($_REQUEST['subject']) : '';
$emailText = isset($_REQUEST['body']) ? Security::remove_XSS($_REQUEST['body']) : '';
$defaults = [
'email_title' => $emailTitle,
'email_text' => $emailText,
];
if (isset($_POST)) {
$defaults = [
'email' => $_REQUEST['email'] ?? null,
'email_title' => $_REQUEST['email_title'] ?? null,
'email_text' => $_REQUEST['email_text'] ?? null,
];
}
$form->setDefaults($defaults);
if ($form->validate()) {
$values = $form->getSubmitValues();
$message =
get_lang('Sender').': '.$values['email'].'<br /><br />'.
nl2br($values['email_text']).
'<br /><br /><br />'.get_lang('EmailSentFromLMS').' '.api_get_path(WEB_PATH);
api_mail_html(
'',
api_get_setting('emailAdministrator'),
$values['email_title'],
$message,
get_lang('Anonymous')
);
Display::addFlash(Display::return_message(get_lang('MessageSent')));
$orig = Session::read('origin_url');
Session::erase('origin_url');
header('Location:'.$orig);
exit;
}
Display::display_header(get_lang('SendEmail'));
$form->display();
Display::display_footer();

336
main/inc/global-min.inc.php Normal file
View File

@@ -0,0 +1,336 @@
<?php
/* For licensing terms, see /license.txt */
/**
* This is a minified version of global.inc.php meant *only* for download.php
* to check permissions and deliver the file.
*/
// Include the libraries that are necessary everywhere
require_once __DIR__.'/../../vendor/autoload.php';
require_once __DIR__.'/../../app/AppKernel.php';
$kernel = new AppKernel('', '');
// Determine the directory path where this current file lies.
// This path will be useful to include the other initialisation files.
$includePath = __DIR__;
// Include the main Chamilo platform configuration file.
$_configuration = [];
$alreadyInstalled = false;
if (file_exists($kernel->getConfigurationFile())) {
require_once $kernel->getConfigurationFile();
$alreadyInstalled = true;
// Recalculate a system absolute path symlinks insensible.
$includePath = $_configuration['root_sys'].'main/inc/';
} else {
//Redirects to the main/install/ page
if (!$alreadyInstalled) {
$global_error_code = 2;
// The system has not been installed yet.
require_once __DIR__.'/../inc/global_error_message.inc.php';
exit();
}
}
$kernel->setApi($_configuration);
// Ensure that _configuration is in the global scope before loading
// main_api.lib.php. This is particularly helpful for unit tests
if (!isset($GLOBALS['_configuration'])) {
$GLOBALS['_configuration'] = $_configuration;
}
// Include the main Chamilo platform library file.
require_once $_configuration['root_sys'].'main/inc/lib/api.lib.php';
// Fix bug in IIS that doesn't fill the $_SERVER['REQUEST_URI'].
api_request_uri();
// Do not over-use this variable. It is only for this script's local use.
$libraryPath = __DIR__.'/lib/';
// @todo convert this libs in classes
require_once $libraryPath.'database.constants.inc.php';
require_once $libraryPath.'text.lib.php';
require_once $libraryPath.'array.lib.php';
require_once $libraryPath.'online.inc.php';
require_once $libraryPath.'banner.lib.php';
// Doctrine ORM configuration
$dbParams = [
'driver' => 'pdo_mysql',
'host' => $_configuration['db_host'],
'user' => $_configuration['db_user'],
'password' => $_configuration['db_password'],
'dbname' => $_configuration['main_database'],
// Only relevant for pdo_sqlite, specifies the path to the SQLite database.
'path' => isset($_configuration['db_path']) ? $_configuration['db_path'] : '',
// Only relevant for pdo_mysql, pdo_pgsql, and pdo_oci/oci8,
'port' => isset($_configuration['db_port']) ? $_configuration['db_port'] : '',
];
try {
$database = new \Database();
$database->connect($dbParams);
} catch (Exception $e) {
$global_error_code = 3;
// The database server is not available or credentials are invalid.
require $includePath.'/global_error_message.inc.php';
exit();
}
/* RETRIEVING ALL THE CHAMILO CONFIG SETTINGS FOR MULTIPLE URLs FEATURE*/
if (!empty($_configuration['multiple_access_urls'])) {
$_configuration['access_url'] = 1;
$access_urls = api_get_access_urls();
$root_rel = api_get_self();
$root_rel = substr($root_rel, 1);
$pos = strpos($root_rel, '/');
$root_rel = substr($root_rel, 0, $pos);
$protocol = 'http://';
if (!empty($_SERVER['HTTPS']) && strtoupper($_SERVER['HTTPS']) != 'OFF') {
$protocol = 'https://';
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
$protocol = 'https://';
}
//urls with subdomains (HTTP_HOST is preferred - see #6764)
$request_url_root = '';
if (empty($_SERVER['HTTP_HOST'])) {
if (empty($_SERVER['SERVER_NAME'])) {
$request_url_root = $protocol.'localhost/';
} else {
$request_url_root = $protocol.$_SERVER['SERVER_NAME'].'/';
}
} else {
$request_url_root = $protocol.$_SERVER['HTTP_HOST'].'/';
}
//urls with subdirs
$request_url_sub = $request_url_root.$root_rel.'/';
// You can use subdirs as multi-urls, but in this case none of them can be
// the root dir. The admin portal should be something like https://host/adm/
// At this time, subdirs will still hold a share cookie, so not ideal yet
// see #6510
foreach ($access_urls as $details) {
if ($request_url_sub == $details['url']) {
$_configuration['access_url'] = $details['id'];
break; //found one match with subdir, get out of foreach
}
// Didn't find any? Now try without subdirs
if ($request_url_root == $details['url']) {
$_configuration['access_url'] = $details['id'];
break; //found one match, get out of foreach
}
}
} else {
$_configuration['access_url'] = 1;
}
// Check if APCu is available. If so, store the value in $_configuration
if (extension_loaded('apcu')) {
$apcEnabled = ini_get('apc.enabled');
if (!empty($apcEnabled) && $apcEnabled != 'Off' && $apcEnabled != 'off') {
$_configuration['apc'] = true;
$_configuration['apc_prefix'] = $_configuration['main_database'].'_'.$_configuration['access_url'].'_';
}
}
$charset = 'UTF-8';
// Enables the portability layer and configures PHP for UTF-8
\Patchwork\Utf8\Bootup::initAll();
// Start session after the internationalization library has been initialized.
ChamiloSession::start($alreadyInstalled);
// access_url == 1 is the default chamilo location
if ($_configuration['access_url'] != 1) {
$url_info = api_get_access_url($_configuration['access_url']);
if ($url_info['active'] == 1) {
$settings_by_access = api_get_settings(null, 'list', $_configuration['access_url'], 1);
foreach ($settings_by_access as &$row) {
if (empty($row['variable'])) {
$row['variable'] = 0;
}
if (empty($row['subkey'])) {
$row['subkey'] = 0;
}
if (empty($row['category'])) {
$row['category'] = 0;
}
$settings_by_access_list[$row['variable']][$row['subkey']][$row['category']] = $row;
}
}
}
$result = api_get_settings(null, 'list', 1);
foreach ($result as &$row) {
if ($_configuration['access_url'] != 1) {
if ($url_info['active'] == 1) {
$var = empty($row['variable']) ? 0 : $row['variable'];
$subkey = empty($row['subkey']) ? 0 : $row['subkey'];
$category = empty($row['category']) ? 0 : $row['category'];
}
if ($row['access_url_changeable'] == 1 && $url_info['active'] == 1) {
if (isset($settings_by_access_list[$var]) &&
isset($settings_by_access_list[$var][$subkey]) &&
$settings_by_access_list[$var][$subkey][$category]['selected_value'] != '') {
if ($row['subkey'] == null) {
$_setting[$row['variable']] = $settings_by_access_list[$var][$subkey][$category]['selected_value'];
} else {
$_setting[$row['variable']][$row['subkey']] = $settings_by_access_list[$var][$subkey][$category]['selected_value'];
}
} else {
if ($row['subkey'] == null) {
$_setting[$row['variable']] = $row['selected_value'];
} else {
$_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
}
}
} else {
if ($row['subkey'] == null) {
$_setting[$row['variable']] = $row['selected_value'];
} else {
$_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
}
}
} else {
if ($row['subkey'] == null) {
$_setting[$row['variable']] = $row['selected_value'];
} else {
$_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
}
}
}
$result = api_get_settings('Plugins', 'list', $_configuration['access_url']);
$_plugins = [];
foreach ($result as &$row) {
$key = &$row['variable'];
if (isset($_setting[$key]) && is_string($_setting[$key])) {
$_setting[$key] = [];
}
if ($row['subkey'] == null) {
$_setting[$key][] = $row['selected_value'];
$_plugins[$key][] = $row['selected_value'];
} else {
$_setting[$key][$row['subkey']] = $row['selected_value'];
$_plugins[$key][$row['subkey']] = $row['selected_value'];
}
}
ini_set('log_errors', '1');
/**
* Include the trad4all language file.
*/
// if we use the javascript version (without go button) we receive a get
// if we use the non-javascript version (with the go button) we receive a post
$user_language = '';
$browser_language = '';
// see #8149
if (!empty($_SESSION['user_language_choice'])) {
$user_language = $_SESSION['user_language_choice'];
}
if (!empty($_GET['language'])) {
$user_language = $_GET['language'];
}
if (!empty($_POST['language_list'])) {
$user_language = preg_replace('/index\.php\?language=/', '', $_POST['language_list']);
}
if (empty($user_language) && !empty($_SERVER['HTTP_ACCEPT_LANGUAGE']) && !isset($_SESSION['_user'])) {
$l = SubLanguageManager::getLanguageFromBrowserPreference($_SERVER['HTTP_ACCEPT_LANGUAGE']);
if (!empty($l)) {
$user_language = $browser_language = $l;
}
}
// Checking if we have a valid language. If not we set it to the platform language.
$valid_languages = api_get_languages();
if (!empty($valid_languages)) {
if (!in_array($user_language, $valid_languages['folder'])) {
$user_language = api_get_setting('platformLanguage');
}
$language_priority1 = api_get_setting('languagePriority1');
$language_priority2 = api_get_setting('languagePriority2');
$language_priority3 = api_get_setting('languagePriority3');
$language_priority4 = api_get_setting('languagePriority4');
if (isset($_GET['language']) ||
(isset($_POST['language_list']) && !empty($_POST['language_list'])) ||
!empty($browser_language)
) {
$user_selected_language = $user_language; // $_GET['language']; or HTTP_ACCEPT_LANGUAGE
$_SESSION['user_language_choice'] = $user_selected_language;
$platformLanguage = $user_selected_language;
}
if (!empty($language_priority4) && api_get_language_from_type($language_priority4) !== false) {
$language_interface = api_get_language_from_type($language_priority4);
} else {
$language_interface = api_get_setting('platformLanguage');
}
if (!empty($language_priority3) && api_get_language_from_type($language_priority3) !== false) {
$language_interface = api_get_language_from_type($language_priority3);
} else {
if (isset($_SESSION['user_language_choice'])) {
$language_interface = $_SESSION['user_language_choice'];
}
}
if (!empty($language_priority2) && api_get_language_from_type($language_priority2) !== false) {
$language_interface = api_get_language_from_type($language_priority2);
} else {
if (isset($_user['language'])) {
$language_interface = $_user['language'];
}
}
if (!empty($language_priority1) && api_get_language_from_type($language_priority1) !== false) {
$language_interface = api_get_language_from_type($language_priority1);
} else {
if (isset($_course['language'])) {
$language_interface = $_course['language'];
}
}
// If language is set via browser ignore the priority
if (isset($_GET['language'])) {
$language_interface = $user_language;
}
}
$language_interface_initial_value = $language_interface;
$langPath = api_get_path(SYS_LANG_PATH);
$languageFilesToLoad = [
$langPath.'english/trad4all.inc.php',
$langPath.$language_interface.'/trad4all.inc.php',
];
foreach ($languageFilesToLoad as $languageFile) {
if (is_file($languageFile)) {
require $languageFile;
}
}
// include the local (contextual) parameters of this course or section
require $includePath.'/local.inc.php';
// Update of the logout_date field in the table track_e_login
// (needed for the calculation of the total connection time)
if (!isset($_SESSION['login_as']) && isset($_user) && isset($_user["user_id"])) {
// if $_SESSION['login_as'] is set, then the user is an admin logged as the user
Tracking::updateUserLastLogin($_user["user_id"]);
}

641
main/inc/global.inc.php Normal file
View File

@@ -0,0 +1,641 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CoreBundle\Component\Utils\ChamiloApi;
/**
* It is recommended that ALL Chamilo scripts include this important file.
* This script manages
* - include of /app/config/configuration.php;
* - include of several libraries: api, database, display, text, security;
* - selecting the main database;
* - include of language files.
*
* @package chamilo.include
*
* @todo remove the code that displays the button that links to the install page
* but use a redirect immediately. By doing so the $alreadyInstalled variable can be removed.
*/
define('SHOW_ERROR_CODES', false);
// Include the libraries that are necessary everywhere
require_once __DIR__.'/../../vendor/autoload.php';
require_once __DIR__.'/../../app/AppKernel.php';
$kernel = new AppKernel('', '');
// Determine the directory path where this current file lies.
// This path will be useful to include the other initialisation files.
$includePath = __DIR__;
// Include the main Chamilo platform configuration file.
$alreadyInstalled = false;
if (file_exists($kernel->getConfigurationFile())) {
require_once $kernel->getConfigurationFile();
$alreadyInstalled = true;
// Recalculate a system absolute path symlinks insensible.
$includePath = $_configuration['root_sys'].'main/inc/';
} else {
$_configuration = [];
//Redirects to the main/install/ page
if (!$alreadyInstalled) {
$global_error_code = 2;
// The system has not been installed yet.
require_once __DIR__.'/../inc/global_error_message.inc.php';
exit();
}
}
$kernel->setApi($_configuration);
// Ensure that _configuration is in the global scope before loading
// main_api.lib.php. This is particularly helpful for unit tests
if (!isset($GLOBALS['_configuration'])) {
$GLOBALS['_configuration'] = $_configuration;
}
// Include the main Chamilo platform library file.
require_once $_configuration['root_sys'].'main/inc/lib/api.lib.php';
$passwordEncryption = api_get_configuration_value('password_encryption');
if ($passwordEncryption === 'bcrypt') {
require_once __DIR__.'/../../vendor/ircmaxell/password-compat/lib/password.php';
}
// Check the PHP version
api_check_php_version($includePath.'/');
// Fix bug in IIS that doesn't fill the $_SERVER['REQUEST_URI'].
api_request_uri();
// Set web proxy environment variables
foreach ([
'proxy_settings/stream_context_create/https/proxy',
'proxy_settings/stream_context_create/http/proxy',
'proxy_settings/curl_setopt_array/CURLOPT_PROXY',
] as $path) {
$value = api_get_configuration_sub_value($path);
if (!empty($value) && is_string($value)) {
// libcurl reads environment variable https_proxy: https://curl.haxx.se/libcurl/c/libcurl-env.html
// \GuzzleHttp\Client::configureDefaults reads environment variable HTTPS_PROXY
foreach (['https_proxy', 'http_proxy', 'HTTPS_PROXY', 'HTTP_PROXY'] as $envVar) {
if (false === getenv($envVar)) {
putenv("$envVar=$value");
}
}
break;
}
}
define('_MPDF_TEMP_PATH', __DIR__.'/../../app/cache/mpdf/');
define('_MPDF_TTFONTDATAPATH', __DIR__.'/../../app/cache/mpdf/');
// Include the libraries that are necessary everywhere
require_once __DIR__.'/../../vendor/autoload.php';
// Do not over-use this variable. It is only for this script's local use.
$libraryPath = __DIR__.'/lib/';
// @todo convert this libs in classes
require_once $libraryPath.'database.constants.inc.php';
require_once $libraryPath.'formvalidator/FormValidator.class.php';
require_once $libraryPath.'text.lib.php';
require_once $libraryPath.'array.lib.php';
require_once $libraryPath.'online.inc.php';
require_once $libraryPath.'banner.lib.php';
require_once $libraryPath.'fileManage.lib.php';
require_once $libraryPath.'fileUpload.lib.php';
require_once $libraryPath.'fileDisplay.lib.php';
require_once $libraryPath.'course_category.lib.php';
if (!is_dir(_MPDF_TEMP_PATH)) {
mkdir(_MPDF_TEMP_PATH, api_get_permissions_for_new_directories(), true);
}
// Connect to the server database and select the main chamilo database.
// When $_configuration['db_persistent_connection'] is set, it is expected to be a boolean type.
/*$dbPersistConnection = api_get_configuration_value('db_persistent_connection');
// $_configuration['db_client_flags'] can be set in configuration.php to pass
// flags to the DB connection
$dbFlags = api_get_configuration_value('db_client_flags');
$params = array(
'server' => $_configuration['db_host'],
'username' => $_configuration['db_user'],
'password' => $_configuration['db_password'],
'persistent' => $dbPersistConnection,
'client_flags' => $dbFlags,
);*/
// Doctrine ORM configuration
$dbParams = [
'driver' => 'pdo_mysql',
'host' => $_configuration['db_host'],
'user' => $_configuration['db_user'],
'password' => $_configuration['db_password'],
'dbname' => $_configuration['main_database'],
// Only relevant for pdo_sqlite, specifies the path to the SQLite database.
'path' => isset($_configuration['db_path']) ? $_configuration['db_path'] : '',
// Only relevant for pdo_mysql, pdo_pgsql, and pdo_oci/oci8,
'port' => isset($_configuration['db_port']) ? $_configuration['db_port'] : '',
'driverOptions' => isset($_configuration['db_client_flags']) && is_array($_configuration['db_client_flags']) ? $_configuration['db_client_flags'] : [],
];
try {
$database = new \Database();
$database->connect($dbParams);
} catch (Exception $e) {
$global_error_code = 3;
// The database server is not available or credentials are invalid.
require $includePath.'/global_error_message.inc.php';
exit();
}
/* RETRIEVING ALL THE CHAMILO CONFIG SETTINGS FOR MULTIPLE URLs FEATURE*/
if (!empty($_configuration['multiple_access_urls'])) {
$_configuration['access_url'] = 1;
$access_urls = api_get_access_urls();
$root_rel = api_get_self();
$root_rel = substr($root_rel, 1);
$pos = strpos($root_rel, '/');
$root_rel = substr($root_rel, 0, $pos);
$protocol = 'http://';
if (!empty($_SERVER['HTTPS']) && strtoupper($_SERVER['HTTPS']) != 'OFF') {
$protocol = 'https://';
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
$protocol = 'https://';
}
//urls with subdomains (HTTP_HOST is preferred - see #6764)
$request_url_root = '';
if (empty($_SERVER['HTTP_HOST'])) {
if (empty($_SERVER['SERVER_NAME'])) {
$request_url_root = $protocol.'localhost/';
} else {
$request_url_root = $protocol.$_SERVER['SERVER_NAME'].'/';
}
} else {
$request_url_root = $protocol.$_SERVER['HTTP_HOST'].'/';
}
//urls with subdirs
$request_url_sub = $request_url_root.$root_rel.'/';
// You can use subdirs as multi-urls, but in this case none of them can be
// the root dir. The admin portal should be something like https://host/adm/
// At this time, subdirs will still hold a share cookie, so not ideal yet
// see #6510
foreach ($access_urls as $details) {
if ($request_url_sub == $details['url']) {
$_configuration['access_url'] = $details['id'];
break; //found one match with subdir, get out of foreach
}
// Didn't find any? Now try without subdirs
if ($request_url_root == $details['url']) {
$_configuration['access_url'] = $details['id'];
break; //found one match, get out of foreach
}
}
} else {
$_configuration['access_url'] = 1;
}
// Check if APCu is available. If so, store the value in $_configuration
if (extension_loaded('apcu')) {
$apcEnabled = ini_get('apc.enabled');
if (!empty($apcEnabled) && $apcEnabled != 'Off' && $apcEnabled != 'off') {
$_configuration['apc'] = true;
$_configuration['apc_prefix'] = $_configuration['main_database'].'_'.$_configuration['access_url'].'_';
}
}
$charset = 'UTF-8';
// Enables the portability layer and configures PHP for UTF-8
\Patchwork\Utf8\Bootup::initAll();
// Start session after the internationalization library has been initialized.
ChamiloSession::start($alreadyInstalled);
// access_url == 1 is the default chamilo location
if ($_configuration['access_url'] != 1) {
$url_info = api_get_access_url($_configuration['access_url']);
if ($url_info['active'] == 1) {
$settings_by_access = api_get_settings(null, 'list', $_configuration['access_url'], 1);
foreach ($settings_by_access as &$row) {
if (empty($row['variable'])) {
$row['variable'] = 0;
}
if (empty($row['subkey'])) {
$row['subkey'] = 0;
}
if (empty($row['category'])) {
$row['category'] = 0;
}
$settings_by_access_list[$row['variable']][$row['subkey']][$row['category']] = $row;
}
}
}
$result = api_get_settings(null, 'list', 1);
foreach ($result as &$row) {
if ($_configuration['access_url'] != 1) {
if ($url_info['active'] == 1) {
$var = empty($row['variable']) ? 0 : $row['variable'];
$subkey = empty($row['subkey']) ? 0 : $row['subkey'];
$category = empty($row['category']) ? 0 : $row['category'];
}
if ($row['access_url_changeable'] == 1 && $url_info['active'] == 1) {
if (isset($settings_by_access_list[$var]) &&
isset($settings_by_access_list[$var][$subkey]) &&
$settings_by_access_list[$var][$subkey][$category]['selected_value'] != '') {
if ($row['subkey'] == null) {
$_setting[$row['variable']] = $settings_by_access_list[$var][$subkey][$category]['selected_value'];
} else {
$_setting[$row['variable']][$row['subkey']] = $settings_by_access_list[$var][$subkey][$category]['selected_value'];
}
} else {
if ($row['subkey'] == null) {
$_setting[$row['variable']] = $row['selected_value'];
} else {
$_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
}
}
} else {
if ($row['subkey'] == null) {
$_setting[$row['variable']] = $row['selected_value'];
} else {
$_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
}
}
} else {
if ($row['subkey'] == null) {
$_setting[$row['variable']] = $row['selected_value'];
} else {
$_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
}
}
}
$result = api_get_settings('Plugins', 'list', $_configuration['access_url']);
$_plugins = [];
foreach ($result as &$row) {
$key = &$row['variable'];
if (isset($_setting[$key]) && is_string($_setting[$key])) {
$_setting[$key] = [];
}
if ($row['subkey'] == null) {
$_setting[$key][] = $row['selected_value'];
$_plugins[$key][] = $row['selected_value'];
} else {
$_setting[$key][$row['subkey']] = $row['selected_value'];
$_plugins[$key][$row['subkey']] = $row['selected_value'];
}
}
// Error reporting settings.
if (api_get_setting('server_type') == 'test') {
ini_set('display_errors', '1');
ini_set('html_errors', '1');
error_reporting(-1);
if (function_exists('opcache_reset')) {
opcache_reset();
}
} else {
error_reporting(E_COMPILE_ERROR | E_ERROR | E_CORE_ERROR);
}
ini_set('log_errors', '1');
// Specification for usernames:
// 1. ASCII-letters, digits, "." (dot), "_" (underscore) are acceptable, 40 characters maximum length.
// 2. Empty username is formally valid, but it is reserved for the anonymous user.
// 3. Checking the login_is_email portal setting in order to accept 100 chars maximum
$defaultUserNameLength = 50;
if (api_get_setting('login_is_email') == 'true') {
$defaultUserNameLength = 100;
}
define('USERNAME_MAX_LENGTH', $defaultUserNameLength);
// Load allowed tag definitions for kses and/or HTMLPurifier.
require_once $libraryPath.'formvalidator/Rule/allowed_tags.inc.php';
// Before we call local.inc.php, let's define a global $this_section variable
// which will then be usable from the banner and header scripts
$this_section = SECTION_GLOBAL;
// Including configuration files
$configurationFiles = [
'mail.conf.php',
'profile.conf.php',
'course_info.conf.php',
'add_course.conf.php',
'events.conf.php',
'auth.conf.php',
];
foreach ($configurationFiles as $file) {
$file = api_get_path(CONFIGURATION_PATH).$file;
if (file_exists($file)) {
require_once $file;
}
}
/* LOAD LANGUAGE FILES SECTION */
// if we use the javascript version (without go button) we receive a get
// if we use the non-javascript version (with the go button) we receive a post
$user_language = '';
$browser_language = '';
// see #8149
if (!empty($_SESSION['user_language_choice'])) {
$user_language = $_SESSION['user_language_choice'];
}
if (!empty($_GET['language'])) {
$user_language = $_GET['language'];
}
if (!empty($_POST['language_list'])) {
$user_language = str_replace('index.php?language=', '', $_POST['language_list']);
}
if (empty($user_language) && !empty($_SERVER['HTTP_ACCEPT_LANGUAGE']) && !isset($_SESSION['_user'])) {
$l = SubLanguageManager::getLanguageFromBrowserPreference($_SERVER['HTTP_ACCEPT_LANGUAGE']);
if (!empty($l)) {
$user_language = $browser_language = $l;
}
}
// Include all files (first english and then current interface language)
$langpath = api_get_path(SYS_LANG_PATH);
/* This will only work if we are in the page to edit a sub_language */
if (isset($this_script) && $this_script == 'sub_language') {
// getting the arrays of files i.e notification, trad4all, etc
$language_files_to_load = SubLanguageManager::get_lang_folder_files_list(
api_get_path(SYS_LANG_PATH).'english',
true
);
//getting parent info
$parent_language = SubLanguageManager::get_all_information_of_language($_REQUEST['id']);
//getting sub language info
$sub_language = SubLanguageManager::get_all_information_of_language($_REQUEST['sub_language_id']);
$english_language_array = $parent_language_array = $sub_language_array = [];
foreach ($language_files_to_load as $language_file_item) {
$lang_list_pre = array_keys($GLOBALS);
//loading english
$path = $langpath.'english/'.$language_file_item.'.inc.php';
if (file_exists($path)) {
include $path;
}
$lang_list_post = array_keys($GLOBALS);
$lang_list_result = array_diff($lang_list_post, $lang_list_pre);
unset($lang_list_pre);
// english language array
$english_language_array[$language_file_item] = compact($lang_list_result);
//cleaning the variables
foreach ($lang_list_result as $item) {
unset(${$item});
}
$parent_file = $langpath.$parent_language['dokeos_folder'].'/'.$language_file_item.'.inc.php';
if (file_exists($parent_file) && is_file($parent_file)) {
include_once $parent_file;
}
// parent language array
$parent_language_array[$language_file_item] = compact($lang_list_result);
//cleaning the variables
foreach ($lang_list_result as $item) {
unset(${$item});
}
$sub_file = $langpath.$sub_language['dokeos_folder'].'/'.$language_file_item.'.inc.php';
if (file_exists($sub_file) && is_file($sub_file)) {
include $sub_file;
}
// sub language array
$sub_language_array[$language_file_item] = compact($lang_list_result);
//cleaning the variables
foreach ($lang_list_result as $item) {
unset(${$item});
}
}
}
// Checking if we have a valid language. If not we set it to the platform language.
$valid_languages = api_get_languages();
if (!empty($valid_languages)) {
if (!in_array($user_language, $valid_languages['folder'])) {
$user_language = api_get_setting('platformLanguage');
}
$language_priority1 = api_get_setting('languagePriority1');
$language_priority2 = api_get_setting('languagePriority2');
$language_priority3 = api_get_setting('languagePriority3');
$language_priority4 = api_get_setting('languagePriority4');
if (isset($_GET['language']) ||
(isset($_POST['language_list']) && !empty($_POST['language_list'])) ||
!empty($browser_language)
) {
$user_selected_language = $user_language; // $_GET['language']; or HTTP_ACCEPT_LANGUAGE
$_SESSION['user_language_choice'] = $user_selected_language;
$platformLanguage = $user_selected_language;
}
if (!empty($language_priority4) && api_get_language_from_type($language_priority4) !== false) {
$language_interface = api_get_language_from_type($language_priority4);
} else {
$language_interface = api_get_setting('platformLanguage');
}
if (!empty($language_priority3) && api_get_language_from_type($language_priority3) !== false) {
$language_interface = api_get_language_from_type($language_priority3);
} else {
if (isset($_SESSION['user_language_choice'])) {
$language_interface = $_SESSION['user_language_choice'];
}
}
if (!empty($language_priority2) && api_get_language_from_type($language_priority2) !== false) {
$language_interface = api_get_language_from_type($language_priority2);
} else {
if (isset($_user['language'])) {
$language_interface = $_user['language'];
}
}
if (!empty($language_priority1) && api_get_language_from_type($language_priority1) !== false) {
$language_interface = api_get_language_from_type($language_priority1);
} else {
if (isset($_course['language'])) {
$language_interface = $_course['language'];
}
}
// If language is set via browser ignore the priority
if (isset($_GET['language'])) {
$language_interface = $user_language;
}
// Load the user language, if user is entering in the terms and condition page
if (isset($_SESSION['term_and_condition']) && isset($_SESSION['term_and_condition']['user_id'])) {
$userTempId = $_SESSION['term_and_condition']['user_id'];
$userTempInfo = api_get_user_info($userTempId);
if (!empty($userTempInfo['language'])) {
$language_interface = $userTempInfo['language'];
}
}
$allow = api_get_configuration_value('show_language_selector_in_menu');
// Overwrite all lang configs and use the menu language
if ($allow) {
if (isset($_SESSION['user_language_choice'])) {
$userEntity = api_get_user_entity(api_get_user_id());
if ($userEntity) {
if (isset($_GET['language'])) {
$language_interface = $_SESSION['user_language_choice'];
$userEntity->setLanguage($language_interface);
Database::getManager()->merge($userEntity);
Database::getManager()->flush();
// Update cache
api_get_user_info(
api_get_user_id(),
true,
false,
true,
false,
true,
true
);
if (isset($_SESSION['_user'])) {
$_SESSION['_user']['language'] = $language_interface;
}
}
$language_interface = $_SESSION['user_language_choice'] = $userEntity->getLanguage();
}
} else {
$userInfo = api_get_user_info();
if (!empty($userInfo['language'])) {
$_SESSION['user_language_choice'] = $userInfo['language'];
$language_interface = $userInfo['language'];
}
}
}
}
// Sometimes the variable $language_interface is changed
// temporarily for achieving translation in different language.
// We need to save the genuine value of this variable and
// to use it within the function get_lang(...).
$language_interface_initial_value = $language_interface;
/**
* Include the trad4all language file.
*/
$languageFilesToLoad = api_get_language_files_to_load($language_interface);
foreach ($languageFilesToLoad as $languageFile) {
include $languageFile;
}
// include the local (contextual) parameters of this course or section
require $includePath.'/local.inc.php';
// The global variable $text_dir has been defined in the language file trad4all.inc.php.
// For determining text direction correspondent to the current language
// we use now information from the internationalization library.
$text_dir = api_get_text_direction();
// ===== "who is logged in?" module section =====
// check and modify the date of user in the track.e.online table
if (!$x = strpos($_SERVER['PHP_SELF'], 'whoisonline.php')) {
if (!empty($_user['user_id'])) {
preventMultipleLogin($_user['user_id']);
LoginCheck($_user['user_id']);
}
}
// ===== end "who is logged in?" module section =====
// Update of the logout_date field in the table track_e_login
// (needed for the calculation of the total connection time)
if (!isset($_SESSION['login_as']) && isset($_user) && isset($_user["user_id"])) {
// if $_SESSION['login_as'] is set, then the user is an admin logged as the user
Tracking::updateUserLastLogin($_user["user_id"]);
}
// Add language_measure_frequency to your main/inc/conf/configuration.php in
// order to generate language variables frequency measurements (you can then
// see them through main/cron/lang/langstats.php)
// The langstat object will then be used in the get_lang() function.
// This block can be removed to speed things up a bit as it should only ever
// be used in development versions.
if (isset($_configuration['language_measure_frequency']) &&
$_configuration['language_measure_frequency'] == 1
) {
require_once api_get_path(SYS_CODE_PATH).'/cron/lang/langstats.class.php';
$langstats = new langstats();
}
//Default quota for the course documents folder
$default_quota = api_get_setting('default_document_quotum');
//Just in case the setting is not correctly set
if (empty($default_quota)) {
$default_quota = 100000000;
}
define('DEFAULT_DOCUMENT_QUOTA', $default_quota);
// Forcing PclZip library to use a custom temporary folder.
define('PCLZIP_TEMPORARY_DIR', api_get_path(SYS_ARCHIVE_PATH));
// Create web/build/main.js
$webBuildPath = api_get_path(SYS_PUBLIC_PATH).'build/';
if (!is_dir($webBuildPath)) {
if (!mkdir($webBuildPath, api_get_permissions_for_new_directories())) {
error_log(
'Error: '.$webBuildPath.' could not be written. Please check permissions.'
);
}
}
// Load template layout/main.js.tpl and save it into web/build/main.js
$file = $webBuildPath.'main.js';
if (!empty($language_interface)) {
$file = $webBuildPath.'main.'.$language_interface.'.js';
}
// if portal is in test mode always generate the file
if (!file_exists($file) || api_get_setting('server_type') === 'test') {
$template = new Template();
$template->assign('quiz_markers_rolls_js', ChamiloApi::getQuizMarkersRollsJS());
$template->assign('is_vrview_enabled', Display::isVrViewEnabled());
// Force use of default to avoid problems
$tpl = 'default/layout/main.js.tpl';
$contents = $template->fetch($tpl);
if (is_writable($webBuildPath)) {
file_put_contents($file, $contents);
} else {
error_log(
'Error: '.$file.' could not be written. Please check permissions. The web server must be able to write there.'
);
}
}

View File

@@ -0,0 +1,324 @@
<?php
/* For licensing terms, see /license.txt */
/**
* This script displays error messages on fatal errors during initialization.
*
* @package chamilo.include
*
* @author Ivan Tcholakov, 2009-2010
*/
$Organisation = '<a href="http://www.chamilo.org" target="_blank">Chamilo Homepage</a>';
$PoweredBy = 'Powered by <a href="http://www.chamilo.org" target="_blank"> Chamilo </a> &copy; '.date('Y');
/**
* English language variables.
*/
// Sections.
$SectionSystemRequirementsProblem = 'System requirements problem';
$SectionInstallation = 'Installation';
$SectionDatabaseUnavailable = 'Database is unavailable';
$SectionTechnicalIssues = 'Technical issues';
$SectionProtection = 'Protection measure';
// Error code.
$ErrorCode = 'Error code';
// Error code 1.
$IncorrectPhpVersionTitle = 'Incorrect PHP version';
$IncorrectPhpVersionDescription = 'Warning: we have detected that your version of PHP is %s1. To install Chamilo, you need to have PHP %s2 or superior. If you don\'t know what we\'re talking about, please contact your hosting provider or your support team.
%s3 Read the installation guide.';
// Error code 2.
$InstallationTitle = 'Chamilo has not been installed';
$InstallationDescription = 'Click to INSTALL Chamilo %s or read the installation guide';
// Error code 3.
// Error code 4.
// Error code 5.
$DatabaseUnavailableTitle = 'Database is unavailable';
$DatabaseUnavailableDescription = 'This portal is currently experiencing database issues. Please report this to the portal administrator. Thank you for your help.';
// Error code 6.
$AlreadyInstalledTitle = 'Chamilo has already been installed';
$AlreadyInstalledDescription = 'The system has already been installed. In order to protect its contents, we have to prevent you from starting the installation script again. Please return to the main page.';
// Unspecified error.
$TechnicalIssuesTitle = 'Technical issues';
$TechnicalIssuesDescription = 'This portal is currently experiencing technical issues. Please report this to the portal administrator. Thank you for your help.';
if (is_int($global_error_code) && $global_error_code > 0) {
if (class_exists('Template') && function_exists('api_get_configuration_value')) {
$theme = Template::getThemeFallback().'/';
} else {
$theme = 'chamilo';
}
$root_rel = '';
$installation_guide_url = $root_rel.'documentation/installation_guide.html';
$css_path = 'app/Resources/public/css/';
$css_web_assets = 'web/assets/';
$css_web_path = 'web/css/';
$themePath = $css_path.'themes/'.$theme.'/default.css';
$bootstrap_file = $css_web_assets.'bootstrap/dist/css/bootstrap.min.css';
$css_base_file = $css_web_path.'base.css';
$css_list = [$bootstrap_file, $css_base_file, $themePath];
$web_img = 'main/img';
$root_sys = str_replace('\\', '/', realpath(__DIR__.'/../../')).'/';
$css_def = '';
foreach ($css_list as $cssFile) {
$cssFile = $root_sys.$cssFile;
if (file_exists($cssFile)) {
$css_def .= file_get_contents($cssFile);
}
}
$css_def = str_replace("themes/$theme/", $css_web_path."themes/$theme/", $css_def);
$global_error_message = [];
switch ($global_error_code) {
case 1:
$global_error_message['section'] = $SectionSystemRequirementsProblem;
$global_error_message['title'] = $IncorrectPhpVersionTitle;
$php_version = function_exists('phpversion') ? phpversion() : (defined('PHP_VERSION') ? PHP_VERSION : '');
$php_version = empty($php_version) ? '' : '(PHP '.$php_version.')';
$IncorrectPhpVersionDescription = str_replace('%s1', $php_version, $IncorrectPhpVersionDescription);
$IncorrectPhpVersionDescription = str_replace('%s2', REQUIRED_PHP_VERSION, $IncorrectPhpVersionDescription);
$pos = strpos($IncorrectPhpVersionDescription, '%s3');
if ($pos !== false) {
$length = strlen($IncorrectPhpVersionDescription);
$read_installation_guide = substr($IncorrectPhpVersionDescription, $pos + 3, $length);
$IncorrectPhpVersionDescription = substr($IncorrectPhpVersionDescription, 0, $pos);
$IncorrectPhpVersionDescription .= '<br /><a class="btn btn-default" href="'.$installation_guide_url.'" target="_blank">'.$read_installation_guide.'</a>';
}
$global_error_message['description'] = $IncorrectPhpVersionDescription;
break;
case 2:
require __DIR__.'/../install/version.php';
$global_error_message['section'] = $SectionInstallation;
$global_error_message['title'] = $InstallationTitle;
if (($pos = strpos($InstallationDescription, '%s')) === false) {
$InstallationDescription = 'Click to INSTALL Chamilo %s or read the installation guide';
}
$read_installation_guide = substr($InstallationDescription, $pos + 2);
$versionStatus = (!empty($new_version_status) && $new_version_status != 'stable' ? $new_version_status : '');
$InstallationDescription = '<form action="'.$root_rel.'main/install/index.php" method="get">
<div class="row">
<div class="col-md-12">
<div class="office">
<h2 class="title">Welcome to the Chamilo '.$new_version.' '.$new_version_status.' installation wizard</h2>
<p class="text">Let\'s start hunting skills down with Chamilo LMS! This wizard will guide you through the Chamilo installation and configuration process.</p>
<p class="download-info">
<button class="btn btn-primary btn-lg" type="submit" value="INSTALL Chamilo" ><i class="fa fa-download" aria-hidden="true"></i> Install Chamilo</button>
<a class="btn btn-success btn-lg" href="'.$installation_guide_url.'" target="_blank"> '.$read_installation_guide.'</a>
</p>
</div>
</div>
</div>
</form>';
$global_error_message['description'] = $InstallationDescription;
break;
case 3:
case 4:
case 5:
$global_error_message['section'] = $SectionDatabaseUnavailable;
$global_error_message['title'] = $DatabaseUnavailableTitle;
$global_error_message['description'] = $DatabaseUnavailableDescription;
break;
case 6:
$global_error_message['section'] = $SectionProtection;
$global_error_message['title'] = $AlreadyInstalledTitle;
$global_error_message['description'] = $AlreadyInstalledDescription;
break;
default:
$global_error_message['section'] = $SectionTechnicalIssues;
$global_error_message['title'] = $TechnicalIssuesTitle;
$global_error_message['description'] = $TechnicalIssuesDescription;
break;
}
$show_error_codes = defined('SHOW_ERROR_CODES') && SHOW_ERROR_CODES && $global_error_code != 2;
$global_error_message['code'] = $show_error_codes ? $ErrorCode.': '.$global_error_code.'<br /><br />' : '';
$global_error_message['details'] = empty($global_error_message['details']) ? '' : ($show_error_codes ? ': '.$global_error_message['details'] : $global_error_message['details']);
$global_error_message['organisation'] = $Organisation;
$global_error_message['powered_by'] = $PoweredBy;
$global_error_message['encoding'] = 'UTF-8';
$global_error_message['chamilo_logo'] = "data:image/png;base64,".base64_encode(file_get_contents($root_sys.'web/css/themes/'.$theme.'/images/header-logo.png'));
$bgImage = base64_encode(file_get_contents("$root_sys/main/img/bg_space.png"));
$bgMoon = base64_encode(file_get_contents("$root_sys/main/img/bg_moon_two.png"));
$installChamiloImage = "data:image/png;base64,".base64_encode(file_get_contents("$root_sys/main/img/mr_chamilo_install.png"));
$global_error_message['mr_chamilo'] = $installChamiloImage;
if ($global_error_code == 2) {
$global_error_message_page =
<<<EOM
<!DOCTYPE html>
<html>
<head>
<title>{TITLE}</title>
<meta charset="{ENCODING}" />
<style>
$css_def
html, body {min-height:100%; padding:0; margin:0;}
#wrapper {padding:0; position:absolute; top:0; bottom:0; left:0; right:0;}
@keyframes animatedBackground {
from { background-position: 0 0; }
to { background-position: 100% 0; }
}
@-webkit-keyframes animatedBackground {
from { background-position: 0 0; }
to { background-position: 100% 0; }
}
@-ms-keyframes animatedBackground {
from { background-position: 0 0; }
to { background-position: 100% 0; }
}
@-moz-keyframes animatedBackground {
from { background-position: 0 0; }
to { background-position: 100% 0; }
}
.install-home{
background-image: url("data:image/png;base64,$bgImage");
background-position: 0px 0px;
background-repeat: repeat;
animation: animatedBackground 40s linear infinite;
-ms-animation: animatedBackground 40s linear infinite;
-moz-animation: animatedBackground 40s linear infinite;
-webkit-animation: animatedBackground 40s linear infinite;
}
.installer{
background: url("data:image/png;base64,$bgMoon") no-repeat center 390px;
}
.avatar{
text-align: center;
}
.avatar .img-responsive{
display: initial;
}
.office{
padding: 10px 20px;
//background-color: rgba(35, 40, 56, 0.7);
background-color: rgba(0, 22, 48, 0.8);
border-radius: 5px;
}
@media (max-width: 480px) {
.download-info .btn-success{
margin-top: 10px;
}
}
</style>
</head>
<body class="install-home">
<div id="wrapper" class="installer">
<header>
<div class="container">
<div class="row">
<div class="col-md-12">
<div class="logo">
<img src="{CHAMILO_LOGO}"/>
</div>
</div>
</div>
</div>
</header>
<div id="content">
<div class="container">
<div class="welcome-install">
<div class="avatar">
<img class="img-responsive" src="{MR_CHAMILO}"/>
</div>
<div class="row">
<div class="col-md-12">
<div class="office">
<p class="text">
{DESCRIPTION}
{CODE}
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
EOM;
} else {
$global_error_message_page =
<<<EOM
<!DOCTYPE html>
<html>
<head>
<title>{TITLE}</title>
<meta charset="{ENCODING}" />
<style>
$css_def
</style>
</head>
<body>
<div id="page-error">
<div class="page-wrap">
<header>
<div class="container">
<div class="row">
<div class="col-md-12">
<div class="logo">
<img src="{CHAMILO_LOGO}"/>
</div>
</div>
</div>
</div>
</header>
<section id="menu-bar">
<nav class="navbar navbar-default">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#menuone" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<div class="collapse navbar-collapse" id="menuone">
<ul class="nav navbar-nav">
<li id="current" class="active tab-homepage"><a href="#" target="_self">Homepage</a></li>
</ul>
</div>
</div>
</nav>
</section>
<section id="content-error">
<div class="container">
<div class="panel panel-default">
<div class="panel-body">
<div class="alert alert-danger" role="alert">
{DESCRIPTION}
{CODE}
</div>
</div>
</div>
</div>
</section>
</div>
</div>
</body>
</html>
EOM;
}
foreach ($global_error_message as $key => $value) {
$global_error_message_page = str_replace('{'.strtoupper($key).'}', $value, $global_error_message_page);
}
header('Content-Type: text/html; charset='.$global_error_message['encoding']);
exit($global_error_message_page);
}

6
main/inc/index.html Normal file
View File

@@ -0,0 +1,6 @@
<html>
<head>
</head>
<body>
</body>
</html>

View File

@@ -0,0 +1,423 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CoreBundle\Entity\SequenceResource;
use Chamilo\CourseBundle\Entity\CToolIntro;
/**
* The INTRODUCTION MICRO MODULE is used to insert and edit
* an introduction section on a Chamilo module or on the course homepage.
* It can be inserted on any Chamilo module, provided the corresponding setting
* is enabled in the administration section.
*
* The introduction content are stored in a table called "tool_intro"
* in the course Database. Each module introduction has an Id stored in
* the table, which matches a specific module.
*
* '(c_)tool_intro' table description
* c_id: int
* id : int
* intro_text :text
* session_id: int
*
* usage :
*
* $moduleId = 'XX'; // specifying the module tool (string value)
* include(introductionSection.inc.php);
*
* This script is also used since Chamilo 1.9 to show course progress (from the
* course_progress module)
*/
$em = Database::getManager();
$intro_editAllowed = $is_allowed_to_edit = api_is_allowed_to_edit();
$session_id = api_get_session_id();
$blogParam = isset($_GET['blog_id']) ? ('&blog_id='.(int) $_GET['blog_id']) : '';
$cidReq = api_get_cidreq();
$introduction_section = '';
global $charset;
$intro_cmdEdit = empty($_GET['intro_cmdEdit']) ? '' : $_GET['intro_cmdEdit'];
$intro_cmdUpdate = isset($_POST['intro_cmdUpdate']);
$intro_cmdDel = empty($_GET['intro_cmdDel']) ? '' : $_GET['intro_cmdDel'];
$intro_cmdAdd = empty($_GET['intro_cmdAdd']) ? '' : $_GET['intro_cmdAdd'];
$courseId = api_get_course_id();
if (!empty($courseId)) {
$form = new FormValidator(
'introduction_text',
'post',
api_get_self().'?'.$cidReq.$blogParam
);
} else {
$form = new FormValidator('introduction_text');
}
$config = [
'ToolbarSet' => 'IntroductionSection',
'Width' => '100%',
'Height' => '300',
];
$form->addHtmlEditor('intro_content', null, false, false, $config);
$form->addButtonSave(get_lang('SaveIntroText'), 'intro_cmdUpdate');
/* INTRODUCTION MICRO MODULE - COMMANDS SECTION (IF ALLOWED) */
$course_id = api_get_course_int_id();
if ($intro_editAllowed) {
/** @var CToolIntro $toolIntro */
$toolIntro = $em
->getRepository('ChamiloCourseBundle:CToolIntro')
->findOneBy(['cId' => $course_id, 'id' => $moduleId, 'sessionId' => $session_id]);
/* Replace command */
if ($intro_cmdUpdate) {
if ($form->validate()) {
$form_values = $form->exportValues();
$intro_content = $form_values['intro_content'];
if (!empty($intro_content)) {
if (!$toolIntro) {
$toolIntro = new CToolIntro();
$toolIntro
->setSessionId($session_id)
->setCId($course_id)
->setId($moduleId);
}
$toolIntro->setIntroText($intro_content);
$em->persist($toolIntro);
$em->flush();
Display::addFlash(Display::return_message(get_lang('IntroductionTextUpdated'), 'confirmation', false));
} else {
// got to the delete command
$intro_cmdDel = true;
}
} else {
$intro_cmdEdit = true;
}
}
/* Delete Command */
if ($intro_cmdDel && $toolIntro) {
$em->remove($toolIntro);
$em->flush();
Display::addFlash(Display::return_message(get_lang('IntroductionTextDeleted'), 'confirmation'));
}
}
/* INTRODUCTION MICRO MODULE - DISPLAY SECTION */
/* Retrieves the module introduction text, if exist */
// Getting course intro
/** @var CToolIntro $toolIntro */
$toolIntro = $em
->getRepository('ChamiloCourseBundle:CToolIntro')
->findOneBy(['cId' => $course_id, 'id' => $moduleId, 'sessionId' => 0]);
$intro_content = $toolIntro ? $toolIntro->getIntroText() : '';
if ($session_id) {
/** @var CToolIntro $toolIntro */
$toolIntro = $em
->getRepository('ChamiloCourseBundle:CToolIntro')
->findOneBy(['cId' => $course_id, 'id' => $moduleId, 'sessionId' => $session_id]);
$introSessionContent = $toolIntro && $toolIntro->getIntroText() ? $toolIntro->getIntroText() : '';
$intro_content = $introSessionContent ?: $intro_content;
}
// Default behaviour show iframes.
$userStatus = COURSEMANAGERLOWSECURITY;
// Allows to do a remove_XSS in course introduction with user status COURSEMANAGERLOWSECURITY
// Block embed type videos (like vimeo, wistia, etc) - see BT#12244 BT#12556
if (api_get_configuration_value('course_introduction_html_strict_filtering')) {
$userStatus = COURSEMANAGER;
}
// Ignore editor.css
$cssEditor = api_get_path(WEB_CSS_PATH).'editor.css';
$linkToReplace = [
'<link href="'.$cssEditor.'" rel="stylesheet" type="text/css" />',
'<link href="'.$cssEditor.'" media="screen" rel="stylesheet" type="text/css" />',
];
$intro_content = str_replace($linkToReplace, '', $intro_content);
$intro_content = Security::remove_XSS($intro_content, $userStatus);
/* Determines the correct display */
if ($intro_cmdEdit || $intro_cmdAdd) {
$intro_dispDefault = false;
$intro_dispForm = true;
$intro_dispCommand = false;
} else {
$intro_dispDefault = true;
$intro_dispForm = false;
if ($intro_editAllowed) {
$intro_dispCommand = true;
} else {
$intro_dispCommand = false;
}
}
/* Executes the display */
// display thematic advance inside a postit
if ($intro_dispForm) {
$default['intro_content'] = $intro_content;
$form->setDefaults($default);
$introduction_section .= '<div id="courseintro" style="width: 98%">';
$introduction_section .= $form->returnForm();
$introduction_section .= '</div>';
}
$thematic_description_html = '';
$thematicItemTwo = '';
if ($tool == TOOL_COURSE_HOMEPAGE && !isset($_GET['intro_cmdEdit'])) {
// Only show this if we're on the course homepage, and we're not currently editing
$thematic = new Thematic();
$displayMode = api_get_course_setting('display_info_advance_inside_homecourse');
$class1 = '';
if ($displayMode == '1') {
// Show only the current course progress step
$last_done_advance = $thematic->get_last_done_thematic_advance();
$thematic_advance_info = $thematic->get_thematic_advance_list($last_done_advance);
$subTitle1 = get_lang('CurrentTopic');
$class1 = ' current';
} elseif ($displayMode == '2') {
// Show only the two next course progress steps
$last_done_advance = $thematic->get_next_thematic_advance_not_done();
$next_advance_not_done = $thematic->get_next_thematic_advance_not_done(2);
$thematic_advance_info = $thematic->get_thematic_advance_list($last_done_advance);
$thematic_advance_info2 = $thematic->get_thematic_advance_list($next_advance_not_done);
$subTitle1 = $subTitle2 = get_lang('NextTopic');
} elseif ($displayMode == '3') {
// Show the current and next course progress steps
$last_done_advance = $thematic->get_last_done_thematic_advance();
$next_advance_not_done = $thematic->get_next_thematic_advance_not_done();
$thematic_advance_info = $thematic->get_thematic_advance_list($last_done_advance);
$thematic_advance_info2 = $thematic->get_thematic_advance_list($next_advance_not_done);
$subTitle1 = get_lang('CurrentTopic');
$subTitle2 = get_lang('NextTopic');
$class1 = ' current';
}
if (!empty($thematic_advance_info)) {
$thematic_advance = get_lang('CourseThematicAdvance');
$thematicScore = $thematic->get_total_average_of_thematic_advances().'%';
$thematicUrl = api_get_path(WEB_CODE_PATH).'course_progress/index.php?action=thematic_details&'.$cidReq;
$thematic_advance_info['thematic_id'] = $thematic_advance_info['thematic_id'] ?? 0;
$thematic_advance_info['start_date'] = $thematic_advance_info['start_date'] ?? null;
$thematic_advance_info['content'] = $thematic_advance_info['content'] ?? '';
$thematic_advance_info['duration'] = $thematic_advance_info['duration'] ?? 0;
$thematic_info = $thematic->get_thematic_list($thematic_advance_info['thematic_id']);
$thematic_info['title'] = $thematic_info['title'] ?? '';
if (!empty($thematic_advance_info['start_date'])) {
$thematic_advance_info['start_date'] = api_get_local_time(
$thematic_advance_info['start_date']
);
}
$thematic_advance_info['start_date'] = api_format_date(
$thematic_advance_info['start_date'],
DATE_TIME_FORMAT_LONG
);
$userInfo = api_get_user_info();
$courseInfo = api_get_course_info();
$titleThematic = $thematic_advance.' : '.$courseInfo['name'].' <b>( '.$thematicScore.' )</b>';
$infoUser = '<div class="thematic-avatar"><img src="'.$userInfo['avatar'].'" class="img-circle img-responsive"></div>';
$infoUser .= '<div class="progress">
<div class="progress-bar progress-bar-primary" role="progressbar" style="width: '.$thematicScore.';">
'.$thematicScore.'
</div>
</div>';
$thematicItemOne = '
<div class="col-md-6 items-progress">
<div class="thematic-cont '.$class1.'">
<div class="topics">'.$subTitle1.'</div>
<h4 class="title-topics">'.Display::returnFontAwesomeIcon('book').strip_tags($thematic_info['title']).'</h4>
<p class="date">'.Display::returnFontAwesomeIcon('calendar-o').$thematic_advance_info['start_date'].'</p>
<div class="views">'.Display::returnFontAwesomeIcon('file-text-o').strip_tags($thematic_advance_info['content']).'</div>
<p class="time">'.Display::returnFontAwesomeIcon('clock-o').get_lang('DurationInHours').' : '.$thematic_advance_info['duration'].' - <a href="'.$thematicUrl.'">'.get_lang('SeeDetail').'</a></p>
</div>
</div>';
if (!empty($thematic_advance_info2)) {
$thematic_info2 = $thematic->get_thematic_list($thematic_advance_info2['thematic_id']);
$thematic_advance_info2['start_date'] = api_get_local_time($thematic_advance_info2['start_date']);
$thematic_advance_info2['start_date'] = api_format_date($thematic_advance_info2['start_date'], DATE_TIME_FORMAT_LONG);
$thematicItemTwo = '
<div class="col-md-6 items-progress">
<div class="thematic-cont">
<div class="topics">'.$subTitle2.'</div>
<h4 class="title-topics">'.Display::returnFontAwesomeIcon('book').$thematic_info2['title'].'</h4>
<p class="date">'.Display::returnFontAwesomeIcon('calendar-o').$thematic_advance_info2['start_date'].'</p>
<div class="views">'.Display::returnFontAwesomeIcon('file-text-o').strip_tags($thematic_advance_info2['content']).'</div>
<p class="time">'.Display::returnFontAwesomeIcon('clock-o').get_lang('DurationInHours').' : '.$thematic_advance_info2['duration'].' - <a href="'.$thematicUrl.'">'.get_lang('SeeDetail').'</a></p>
</div>
</div>';
}
$thematicPanel = '<div class="row">';
$thematicPanel .= '<div class="col-md-2">'.$infoUser.'</div>';
$thematicPanel .= '<div class="col-md-10"><div class="row">'.$thematicItemOne.$thematicItemTwo.'</div></div>';
$thematicPanel .= '</div>';
$thematicPanel .= '<div class="separate">
<a href="'.$thematicUrl.'" class="btn btn-default btn-block">'.get_lang('ShowFullCourseAdvance').'</a>
</div>';
$thematicProgress = Display::panelCollapse(
$titleThematic,
$thematicPanel,
'thematic',
null,
'accordion-thematic',
'collapse-thematic',
false
);
}
}
$introduction_section .= '<div class="row">';
if (!empty($thematic_advance_info)) {
$introduction_section .= '<div class="col-md-12">';
$introduction_section .= $thematic_description_html;
$introduction_section .= $thematicProgress;
$introduction_section .= '</div>';
}
$editIconButton = '';
if (api_is_allowed_to_edit() && empty($session_id)) {
$editIconButton = Display::url(
'<em class="fa fa-wrench"></em> ',
api_get_path(WEB_CODE_PATH).'course_info/tools.php?'.$cidReq,
['class' => 'btn btn-default', 'title' => get_lang('CustomizeIcons')]
);
}
/* Tool to show /hide all tools on course */
$toolAllShowHide = '';
if (api_is_allowed_to_edit() && empty($session_id)) {
$toolAllShowHide = '<button class="btn btn-default hidden visible-all show-hide-all-tools" title="'.get_lang('Activate', '').'"><em class="fa fa-eye"></em></button>';
$toolAllShowHide .= '<button class="btn btn-default hidden invisible-all show-hide-all-tools" title="'.get_lang('Deactivate', '').'"><em class="fa fa-eye-slash"></em></button>';
}
$toolbar = '';
$textIntro = '';
if ($intro_dispCommand) {
$toolbar .= '<div class="toolbar-edit">';
$toolbar .= '<div class="btn-group pull-right" role="group">';
if (empty($intro_content)) {
// Displays "Add intro" commands
if (!empty($courseId)) {
$textIntro = '<a class="btn btn-default" title="'.addslashes(get_lang('AddIntro')).'" href="'.api_get_self().'?'.$cidReq.$blogParam.'&intro_cmdAdd=1">';
$textIntro .= '<em class="fa fa-file-text"></em> ';
$textIntro .= "</a>";
$toolbar .= $textIntro.$editIconButton.$toolAllShowHide;
} else {
$toolbar .= '<a class="btn btn-default" href="'.api_get_self().'?intro_cmdAdd=1">'.get_lang('AddIntro').'</a>';
$toolbar .= $editIconButton.$toolAllShowHide;
}
} else {
// Displays "edit intro && delete intro" commands
if (!empty($courseId)) {
$toolbar .=
'<a class="btn btn-default" href="'.api_get_self().'?'.$cidReq.$blogParam.'&intro_cmdEdit=1" title="'.get_lang('Modify').'">
<em class="fa fa-pencil"></em></a>';
$toolbar .= $editIconButton.$toolAllShowHide;
$toolbar .= "<a class=\"btn btn-default\"
href=\"".api_get_self()."?".$cidReq.$blogParam."&intro_cmdDel=1\"
onclick=\"if(!confirm('".addslashes(api_htmlentities(get_lang('ConfirmYourChoice'), ENT_QUOTES, $charset))."')) return false;\"
><em class=\"fa fa-trash-o\"></em></a>";
} else {
$toolbar .=
'<a class="btn btn-default" href="'.api_get_self().'?intro_cmdEdit=1" title="'.get_lang('Modify').'">
<em class="fa fa-pencil"></em>
</a>"';
$toolbar .= $editIconButton.$toolAllShowHide;
$toolbar .= "<a class=\"btn btn-default\"
href=\"".api_get_self()."?".$cidReq."&intro_cmdDel=1\"
onclick=\"if(!confirm('".addslashes(api_htmlentities(get_lang('ConfirmYourChoice'), ENT_QUOTES, $charset))."')) return false;\"
><em class=\"fa fa-trash-o\"></em></a>";
}
// Fix for chrome XSS filter for videos in iframes - BT#7930
$browser = api_get_navigator();
if (strpos($introduction_section, '<iframe') !== false && $browser['name'] == 'Chrome') {
header('X-XSS-Protection: 0');
}
}
$toolbar .= '</div></div>';
}
$nameSection = get_lang('AddCustomCourseIntro');
if ($moduleId !== 'course_homepage') {
$nameSection = get_lang('AddCustomToolsIntro');
}
if (!api_is_anonymous()) {
$intro_content = AnnouncementManager::parseContent(api_get_user_id(), $intro_content, api_get_course_id());
}
$showSequencesBlock = false;
if (api_get_configuration_value('resource_sequence_show_dependency_in_course_intro' && $tool == TOOL_COURSE_HOMEPAGE)) {
$sequenceResourceRepo = $em->getRepository(SequenceResource::class);
$sequences = $sequenceResourceRepo->getDependents($course_id, SequenceResource::COURSE_TYPE);
$firstSequence = current($sequences);
$showSequencesBlock = !empty($firstSequence['dependents']);
}
$introduction_section .= $showSequencesBlock ? '<div class="col-md-10">' : '<div class="col-md-12">';
if ($intro_dispDefault) {
if (!empty($intro_content)) {
$introduction_section .= '<div class="page-course">';
$introduction_section .= $intro_content;
$introduction_section .= '</div>';
} else {
if (api_is_allowed_to_edit()) {
$introduction_section .= '<div class="help-course">';
$introduction_section .= $nameSection.' '.$textIntro;
$introduction_section .= '</div>';
}
}
}
$introduction_section .= $toolbar;
$introduction_section .= '</div>';
if ($showSequencesBlock) {
$sequenceUrl = http_build_query(
[
'a' => 'get_dependents',
'id' => $course_id,
'type' => SequenceResource::COURSE_TYPE,
'sid' => $session_id,
]
);
$introduction_section .= '<div class="col-md-2 text-center" id="resource-sequence">
<span class="fa fa-spinner fa-spin fa-fw" aria-hidden="true"></span>
</div>
<script>
$(function () {
$(\'#resource-sequence\').load(_p.web_ajax + \'sequence.ajax.php?'.$sequenceUrl.'&'.$cidReq.'\')
});
</script>
';
}
$introduction_section .= '</div>'; //div.row
$browser = api_get_navigator();
if (strpos($introduction_section, '<iframe') !== false && $browser['name'] == 'Chrome') {
header("X-XSS-Protection: 0");
}

1
main/inc/lib/.htaccess Normal file
View File

@@ -0,0 +1 @@
Options -Indexes

View File

@@ -0,0 +1,441 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Announcement Email.
*
* @author Laurent Opprecht <laurent@opprecht.info> for the Univesity of Geneva
* @author Julio Montoya <gugli100@gmail.com> Adding session support
*/
class AnnouncementEmail
{
public $session_id = null;
public $logger;
protected $course = null;
protected $announcement = null;
/**
* @param array $courseInfo
* @param int $sessionId
* @param int $announcementId
* @param \Monolog\Logger $logger
*/
public function __construct($courseInfo, $sessionId, $announcementId, $logger = null)
{
if (empty($courseInfo)) {
$courseInfo = api_get_course_info();
}
$this->course = $courseInfo;
$this->session_id = empty($sessionId) ? api_get_session_id() : (int) $sessionId;
if (is_numeric($announcementId)) {
$this->announcement = AnnouncementManager::get_by_id($courseInfo['real_id'], $announcementId);
}
$this->logger = $logger;
}
/**
* Course info.
*
* @param string $key
*
* @return string|null
*/
public function course($key = '')
{
$result = $key ? $this->course[$key] : $this->course;
$result = $key == 'id' ? intval($result) : $result;
return $result;
}
/**
* Announcement info.
*
* @param string $key
*
* @return array
*/
public function announcement($key = '')
{
$result = $key ? $this->announcement[$key] : $this->announcement;
$result = $key == 'id' ? intval($result) : $result;
return $result;
}
/**
* Returns either all course users or all session users depending on whether
* session is turned on or not.
*
* @return array
*/
public function all_users()
{
$courseCode = $this->course('code');
if (empty($this->session_id)) {
$group_id = api_get_group_id();
if (empty($group_id)) {
$userList = CourseManager::get_user_list_from_course_code($courseCode);
} else {
$userList = GroupManager::get_users($group_id);
$new_user_list = [];
foreach ($userList as $user) {
$new_user_list[] = ['user_id' => $user];
}
$userList = $new_user_list;
}
} else {
$userList = CourseManager::get_user_list_from_course_code(
$courseCode,
$this->session_id
);
}
return $userList;
}
/**
* Returns users and groups an announcement item has been sent to.
*
* @return array Array of users and groups to whom the element has been sent
*/
public function sent_to_info()
{
$result = [];
$result['groups'] = [];
$result['users'] = [];
$table = Database::get_course_table(TABLE_ITEM_PROPERTY);
$tool = TOOL_ANNOUNCEMENT;
$id = $this->announcement('id');
$course_id = $this->course('real_id');
$sessionCondition = api_get_session_condition($this->session_id);
$sql = "SELECT to_group_id, to_user_id
FROM $table
WHERE
c_id = $course_id AND
tool = '$tool' AND
ref = $id
$sessionCondition";
$rs = Database::query($sql);
while ($row = Database::fetch_array($rs, 'ASSOC')) {
// if to_user_id <> 0 then it is sent to a specific user
$user_id = $row['to_user_id'];
if (!empty($user_id)) {
$result['users'][] = (int) $user_id;
// If user is set then skip the group
continue;
}
// if to_group_id is null then it is sent to a specific user
// if to_group_id = 0 then it is sent to everybody
$group_id = $row['to_group_id'];
if (!empty($group_id)) {
$result['groups'][] = (int) $group_id;
}
}
return $result;
}
/**
* Returns the list of user info to which an announcement was sent.
* This function returns a list of actual users even when recipient
* are groups.
*
* @return array
*/
public function sent_to()
{
$sent_to = $this->sent_to_info();
$users = $sent_to['users'];
$users = $users ? $users : [];
$groups = $sent_to['groups'];
if ($users) {
$users = UserManager::get_user_list_by_ids($users, true);
}
if (!empty($groups)) {
$groupUsers = GroupManager::get_groups_users($groups);
$groupUsers = UserManager::get_user_list_by_ids($groupUsers, true);
if (!empty($groupUsers)) {
$users = array_merge($users, $groupUsers);
}
}
if (empty($users)) {
if (!empty($this->logger)) {
$this->logger->addInfo('User list is empty. No users found. Trying all_users()');
}
$users = self::all_users();
}
// Clean users just in case
$newListUsers = [];
if (!empty($users)) {
foreach ($users as $user) {
$newListUsers[$user['user_id']] = ['user_id' => $user['user_id']];
}
}
return $newListUsers;
}
/**
* Email subject.
*
* @param bool $directMessage
*
* @return string
*/
public function subject($directMessage = false)
{
if ($directMessage) {
$result = $this->announcement('title');
} else {
$result = $this->course('title').' - '.$this->announcement('title');
}
$result = stripslashes($result);
return $result;
}
/**
* Email message.
*
* @param int $receiverUserId
* @param bool $checkUrls It checks access url of user when multiple_access_urls = true
*
* @return string
*/
public function message($receiverUserId, $checkUrls = false)
{
$content = $this->announcement('content');
$session_id = $this->session_id;
$courseCode = $this->course('code');
$courseId = $this->course('real_id');
$content = AnnouncementManager::parseContent(
$receiverUserId,
$content,
$courseCode,
$session_id
);
$accessConfig = [];
$useMultipleUrl = api_get_configuration_value('multiple_access_urls');
if ($useMultipleUrl && $checkUrls) {
$accessUrls = api_get_access_url_from_user($receiverUserId, $courseId);
if (!empty($accessUrls)) {
$accessConfig['multiple_access_urls'] = true;
$accessConfig['access_url'] = (int) $accessUrls[0];
}
}
// Build the link by hand because api_get_cidreq() doesn't accept course params
$course_param = 'cidReq='.$courseCode.'&id_session='.$session_id.'&gidReq='.api_get_group_id();
$course_name = $this->course('title');
$result = "<div>$content</div>";
// Adding attachment
$attachment = $this->attachment();
if (!empty($attachment)) {
$result .= '<br />';
$result .= Display::url(
$attachment['filename'],
api_get_path(WEB_CODE_PATH, $accessConfig).
'announcements/download.php?file='.basename($attachment['path']).'&'.$course_param
);
$result .= '<br />';
}
$result .= '<hr />';
$userInfo = api_get_user_info();
if (!empty($userInfo)) {
if ('true' === api_get_setting('show_email_addresses')) {
$result .= '<a href="mailto:'.$userInfo['mail'].'">'.$userInfo['complete_name'].'</a><br/>';
} else {
$result .= '<p>'.$userInfo['complete_name'].'</p><br/>';
}
}
$result .= '<a href="'.api_get_path(WEB_CODE_PATH, $accessConfig).'announcements/announcements.php?'.$course_param.'">'.
$course_name.'</a><br/>';
return $result;
}
/**
* Returns the one file that can be attached to an announcement.
*
* @return array
*/
public function attachment()
{
$result = [];
$table = Database::get_course_table(TABLE_ANNOUNCEMENT_ATTACHMENT);
$id = $this->announcement('id');
$course_id = $this->course('real_id');
$sql = "SELECT * FROM $table
WHERE c_id = $course_id AND announcement_id = $id ";
$rs = Database::query($sql);
$course_path = $this->course('directory');
while ($row = Database::fetch_array($rs)) {
$path = api_get_path(SYS_COURSE_PATH).$course_path.'/upload/announcements/'.$row['path'];
$filename = $row['filename'];
$result[] = ['path' => $path, 'filename' => $filename];
}
$result = $result ? reset($result) : [];
return $result;
}
/**
* Send announcement by email to myself.
*/
public function sendAnnouncementEmailToMySelf()
{
$userId = api_get_user_id();
$subject = $this->subject();
$message = $this->message($userId);
MessageManager::send_message_simple(
$userId,
$subject,
$message,
api_get_user_id(),
false,
true
);
}
/**
* Send emails to users.
*
* @param bool $sendToUsersInSession
* @param bool $sendToDrhUsers send a copy of the message to the DRH users
* @param int $senderId related to the main user
* @param bool $directMessage
* @param bool $checkUrls It checks access url of user when multiple_access_urls = true
*
* @return array
*/
public function send($sendToUsersInSession = false, $sendToDrhUsers = false, $senderId = 0, $directMessage = false, $checkUrls = false)
{
$senderId = empty($senderId) ? api_get_user_id() : (int) $senderId;
$subject = $this->subject($directMessage);
$courseId = $this->course('real_id');
// Send email one by one to avoid antispam
$users = $this->sent_to();
$batchSize = 20;
$counter = 1;
$em = Database::getManager();
if (empty($users) && !empty($this->logger)) {
$this->logger->addInfo('User list is empty. No emails will be sent.');
}
$messageSentTo = [];
foreach ($users as $user) {
$message = $this->message($user['user_id'], $checkUrls);
$wasSent = MessageManager::messageWasAlreadySent($senderId, $user['user_id'], $subject, $message);
if ($wasSent === false) {
if (!empty($this->logger)) {
$this->logger->addInfo(
'Announcement: #'.$this->announcement('id').'. Send email to user: #'.$user['user_id']
);
}
$messageSentTo[] = $user['user_id'];
MessageManager::send_message_simple(
$user['user_id'],
$subject,
$message,
$senderId,
$sendToDrhUsers,
true,
[],
true,
[],
$checkUrls,
$courseId
);
} else {
if (!empty($this->logger)) {
$this->logger->addInfo(
'Message "'.$subject.'" was already sent. Announcement: #'.$this->announcement('id').'.
User: #'.$user['user_id']
);
}
}
if (($counter % $batchSize) === 0) {
$em->flush();
$em->clear();
}
$counter++;
}
if ($sendToUsersInSession) {
$sessionList = SessionManager::get_session_by_course($this->course['real_id']);
if (!empty($sessionList)) {
foreach ($sessionList as $sessionInfo) {
$sessionId = $sessionInfo['id'];
$message = $this->message(null);
$userList = CourseManager::get_user_list_from_course_code(
$this->course['code'],
$sessionId
);
if (!empty($userList)) {
foreach ($userList as $user) {
$messageSentTo[] = $user['user_id'];
MessageManager::send_message_simple(
$user['user_id'],
$subject,
$message,
$senderId,
false,
true,
[],
true,
[],
$checkUrls,
$courseId
);
}
}
}
}
}
$this->logMailSent();
$messageSentTo = array_unique($messageSentTo);
return $messageSentTo;
}
/**
* Store that emails where sent.
*/
public function logMailSent()
{
$id = $this->announcement('id');
$courseId = $this->course('real_id');
$table = Database::get_course_table(TABLE_ANNOUNCEMENT);
$sql = "UPDATE $table SET
email_sent = 1
WHERE
c_id = $courseId AND
id = $id AND
session_id = {$this->session_id}
";
Database::query($sql);
}
}

File diff suppressed because it is too large Load Diff

402
main/inc/lib/Compilatio.php Normal file
View File

@@ -0,0 +1,402 @@
<?php
/* For licensing terms, see /license.txt */
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Utils;
/**
* Build the communication with the SOAP server Compilatio.net
* call several methods for the file management in Compilatio.net.
*
* @version: 2.0
*/
class Compilatio
{
/** Identification key for the Compilatio account*/
public $key;
/**
* @var Client
*/
public $client;
/**
* @var string
*/
protected $baseUrl;
/** Webservice connection*/
private $maxFileSize;
private $proxyHost;
private $proxyPort;
/**
* Compilatio constructor.
*
* @throws Exception
*/
public function __construct()
{
$settings = $this->getSettings();
$this->maxFileSize = $settings['max_filesize'];
$this->key = $settings['key'];
$this->baseUrl = $settings['api_url'];
if (!empty($settings['proxy_host'])) {
$this->proxyHost = $settings['proxy_host'];
$this->proxyPort = $settings['proxy_port'];
}
$clientConfig = [
'base_uri' => api_remove_trailing_slash($this->baseUrl).'/',
'headers' => [
'X-Auth-Token' => $this->key,
'Accept' => 'application/json',
],
];
if ($this->proxyPort) {
$clientConfig['proxy'] = $this->proxyHost.':'.$this->proxyPort;
}
$this->client = new Client($clientConfig);
}
/**
* @return string
*/
public function getKey()
{
return $this->key;
}
/**
* @param mixed $key
*
* @return Compilatio
*/
public function setKey($key)
{
$this->key = $key;
return $this;
}
/**
* @return mixed
*/
public function getMaxFileSize()
{
return $this->maxFileSize;
}
/**
* @return mixed
*/
public function getProxyHost()
{
return $this->proxyHost;
}
/**
* @return mixed
*/
public function getProxyPort()
{
return $this->proxyPort;
}
/**
* Method for the file load.
*/
public function sendDoc(
string $title,
string $description,
string $filename,
string $filepath
) {
$user = api_get_user_entity(api_get_user_id());
$postData = [
'folder_id' => '',
'title' => $title,
'filename' => basename($filename),
'indexed' => 'true',
'user_notes' => [
'description' => $description,
],
'authors' => [
[
'firstname' => $user->getFirstname(),
'lastname' => $user->getlastname(),
'email_address' => $user->getEmail(),
],
],
'depositor' => [
'firstname' => $user->getFirstname(),
'lastname' => $user->getlastname(),
'email_address' => $user->getEmail(),
],
];
try {
$responseBody = $this->client
->post(
'private/documents',
[
'multipart' => [
[
'name' => 'postData',
'contents' => json_encode($postData),
],
[
'name' => 'file',
'contents' => Utils::tryFopen($filepath, 'r'),
],
],
]
)
->getBody()
;
} catch (Exception $e) {
throw new Exception($e->getMessage());
}
$body = json_decode((string) $responseBody, true);
return $body['data']['document']['id'];
}
/**
* Method for recover a document's information.
*
* @throws Exception
*/
public function getDoc(string $documentId): array
{
try {
$responseBody = $this->client
->get(
"private/documents/$documentId"
)
->getBody()
;
} catch (Exception $e) {
throw new Exception($e->getMessage());
}
$responseJson = json_decode((string) $responseBody, true);
$dataDocument = $responseJson['data']['document'];
$documentInfo = [
'report_url' => $dataDocument['report_url'],
];
// anasim analyse type is applied for services Magister and Copyright
// anasim-premium analyse type is applied for services Magister+ and Copyright+
$anasim = 'anasim';
if (isset($dataDocument['analyses']['anasim-premium'])) {
$anasim = 'anasim-premium';
if (isset($dataDocument['analyses']['anasim'])) {
if (isset($dataDocument['analyses']['anasim']['creation_launch_date']) && isset($dataDocument['analyses']['anasim-premium']['creation_launch_date'])) {
// if the 2 analyses type exist (which could happen technically but would be exceptional) then we present the most recent one.
if ($dataDocument['analyses']['anasim']['creation_launch_date'] > $dataDocument['analyses']['anasim-premium']['creation_launch_date']) {
$anasim = 'anasim';
}
}
}
}
if (isset($dataDocument['analyses'][$anasim]['state'])) {
$documentInfo['analysis_status'] = $dataDocument['analyses'][$anasim]['state'];
}
if (isset($dataDocument['light_reports'][$anasim]['scores']['global_score_percent'])) {
$documentInfo['report_percent'] = $dataDocument['light_reports'][$anasim]['scores']['global_score_percent'];
}
return $documentInfo;
}
/**
* Method for deleting a Compialtio's account document.
*/
public function deldoc(string $documentId)
{
}
/**
* Method for start the analysis for a document.
*
* @throws Exception
*/
public function startAnalyse(string $compilatioId): string
{
try {
$responseBody = $this->client
->post(
'private/analyses',
[
'json' => [
'doc_id' => $compilatioId,
],
]
)
->getBody()
;
} catch (Exception $e) {
throw new Exception($e->getMessage());
}
$body = json_decode((string) $responseBody, true);
return $body['data']['analysis']['state'];
}
/**
* Method for identify a file extension and the possibility that the document can be managed by Compilatio.
*/
public static function verifiFileType(string $filename): bool
{
$types = ['doc', 'docx', 'rtf', 'xls', 'xlsx', 'ppt', 'pptx', 'odt', 'pdf', 'txt', 'htm', 'html'];
$extension = substr($filename, strrpos($filename, '.') + 1);
$extension = strtolower($extension);
return in_array($extension, $types);
}
/**
* Method for display the PomprseuilmankBar (% de plagiat).
*/
public static function getPomprankBarv31(
int $index,
int $weakThreshold,
int $highThreshold
): string {
$index = round($index);
$class = 'danger';
if ($index < $weakThreshold) {
$class = 'success';
} elseif ($index < $highThreshold) {
$class = 'warning';
}
return Display::bar_progress($index, true, null, $class);
}
/**
* Function for delete a document of the compilatio table if plagiarismTool is Compilatio.
*/
public static function plagiarismDeleteDoc(int $courseId, int $itemId)
{
if (api_get_configuration_value('allow_compilatio_tool') !== false) {
$table = Database::get_course_table(TABLE_PLAGIARISM);
$params = [$courseId, $itemId];
Database::delete($table, ['c_id = ? AND document_id = ?' => $params]);
}
}
public function saveDocument(int $courseId, int $documentId, string $compilatioId)
{
$table = Database::get_course_table(TABLE_PLAGIARISM);
$params = [
'c_id' => $courseId,
'document_id' => $documentId,
'compilatio_id' => $compilatioId,
];
Database::insert($table, $params);
}
public function getCompilatioId(int $documentId, int $courseId): ?string
{
$table = Database::get_course_table(TABLE_PLAGIARISM);
$sql = "SELECT compilatio_id FROM $table
WHERE document_id = $documentId AND c_id= $courseId";
$result = Database::query($sql);
$result = Database::fetch_object($result);
return $result ? (string) $result->compilatio_id : null;
}
public function giveWorkIdState(int $workId): string
{
$courseId = api_get_course_int_id();
$compilatioId = $this->getCompilatioId($workId, $courseId);
$actionCompilatio = '';
// if the compilatio's hash is not a valide hash md5,
// we return à specific status (cf : IsInCompilatio() )
// Not used since implementation of RestAPI but there if needed later
//$actionCompilatio = get_lang('CompilatioDocumentTextNotImage').'<br/>'.
// get_lang('CompilatioDocumentNotCorrupt');
$status = '';
if (!empty($compilatioId)) {
// if compilatio_id is a hash md5, we call the function of the compilatio's
// webservice who return the document's status
$soapRes = $this->getDoc($compilatioId);
$status = $soapRes['analysis_status'] ?? '';
$spinnerIcon = Display::returnFontAwesomeIcon('spinner', null, true, 'fa-spin');
switch ($status) {
case 'finished':
$actionCompilatio .= self::getPomprankBarv31($soapRes['report_percent'], 10, 35)
.PHP_EOL
.Display::url(
get_lang('CompilatioAnalysis'),
$soapRes['report_url'],
['class' => 'btn btn-primary btn-xs', 'target' => '_blank']
);
break;
case 'running':
$actionCompilatio .= "<div style='font-weight:bold;text-align:left'>"
.get_lang('CompilatioAnalysisInProgress')
."</div>";
$actionCompilatio .= "<div style='font-size:80%;font-style:italic;margin-bottom:5px;'>"
.get_lang('CompilatioAnalysisPercentage')
."</div>";
$actionCompilatio .= $spinnerIcon.PHP_EOL.get_lang('CompilatioAnalysisEnding');
break;
case 'waiting':
$actionCompilatio .= $spinnerIcon.PHP_EOL.get_lang('CompilatioWaitingAnalysis');
break;
case 'canceled':
$actionCompilatio .= get_lang('Cancelled');
break;
case 'scheduled':
$actionCompilatio .= $spinnerIcon.PHP_EOL.get_lang('CompilatioAwaitingAnalysis');
break;
}
}
return $workId.'|'.$actionCompilatio.'|'.$status.'|';
}
/**
* @throws Exception
*/
protected function getSettings(): array
{
if (empty(api_get_configuration_value('allow_compilatio_tool')) ||
empty(api_get_configuration_value('compilatio_tool'))
) {
throw new Exception('Compilatio not available');
}
$compilatioTool = api_get_configuration_value('compilatio_tool');
if (!isset($compilatioTool['settings'])) {
throw new Exception('Compilatio config available');
}
$settings = $compilatioTool['settings'];
if (empty($settings['key'])) {
throw new Exception('API key not available');
}
if (empty($settings['api_url'])) {
throw new Exception('Api URL not available');
}
return $settings;
}
}

View File

@@ -0,0 +1,887 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CoreBundle\Entity\Course;
use Chamilo\CoreBundle\Entity\CourseRelUser;
use Chamilo\CoreBundle\Entity\Session;
use Chamilo\CoreBundle\Entity\SessionRelCourseRelUser;
use Chamilo\CourseBundle\Entity\CChatConnected;
use Chamilo\UserBundle\Entity\User;
use Doctrine\Common\Collections\Criteria;
use Michelf\MarkdownExtra;
/**
* Class CourseChat
* Manage the chat for a course.
*/
class CourseChatUtils
{
private $groupId;
private $courseId;
private $sessionId;
private $userId;
/**
* CourseChat constructor.
*
* @param int $courseId
* @param int $userId
* @param int $sessionId
* @param int $groupId
*/
public function __construct($courseId, $userId, $sessionId = 0, $groupId = 0)
{
$this->courseId = (int) $courseId;
$this->userId = (int) $userId;
$this->sessionId = (int) $sessionId;
$this->groupId = (int) $groupId;
}
/**
* Prepare a message. Clean and insert emojis.
*
* @param string $message The message to prepare
*
* @return string
*/
public static function prepareMessage($message)
{
if (empty($message)) {
return '';
}
Emojione\Emojione::$imagePathPNG = api_get_path(WEB_LIBRARY_PATH).'javascript/emojione/png/';
Emojione\Emojione::$ascii = true;
$message = trim($message);
$message = nl2br($message);
// Security XSS
$message = Security::remove_XSS($message);
//search urls
$message = preg_replace(
'@((https?://)?([-\w]+\.[-\w\.]+)+\w(:\d+)?(/([-\w/_\.]*(\?\S+)?)?)*)@',
'<a href="$1" target="_blank">$1</a>',
$message
);
// add "http://" if not set
$message = preg_replace(
'/<a\s[^>]*href\s*=\s*"((?!https?:\/\/)[^"]*)"[^>]*>/i',
'<a href="http://$1" target="_blank">',
$message
);
// Parsing emojis
$message = Emojione\Emojione::toImage($message);
// Parsing text to understand markdown (code highlight)
$message = MarkdownExtra::defaultTransform($message);
return $message;
}
/**
* Save a chat message in a HTML file.
*
* @param string $message
* @param int $friendId
*
* @return bool
*/
public function saveMessage($message, $friendId = 0)
{
if (empty($message)) {
return false;
}
$friendId = (int) $friendId;
$userInfo = api_get_user_info($this->userId);
$courseInfo = api_get_course_info_by_id($this->courseId);
$isMaster = api_is_course_admin();
$document_path = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document';
$basepath_chat = '/chat_files';
$group_info = [];
if ($this->groupId) {
$group_info = GroupManager::get_group_properties($this->groupId);
$basepath_chat = $group_info['directory'].'/chat_files';
}
$chat_path = $document_path.$basepath_chat.'/';
if (!is_dir($chat_path)) {
if (is_file($chat_path)) {
@unlink($chat_path);
}
}
$date_now = date('Y-m-d');
$timeNow = date('d/m/y H:i:s');
$basename_chat = 'messages-'.$date_now;
if ($this->groupId && !$friendId) {
$basename_chat = 'messages-'.$date_now.'_gid-'.$this->groupId;
} elseif ($this->sessionId && !$friendId) {
$basename_chat = 'messages-'.$date_now.'_sid-'.$this->sessionId;
} elseif ($friendId) {
if ($this->userId < $friendId) {
$basename_chat = 'messages-'.$date_now.'_uid-'.$this->userId.'-'.$friendId;
} else {
$basename_chat = 'messages-'.$date_now.'_uid-'.$friendId.'-'.$this->userId;
}
}
$message = self::prepareMessage($message);
$fileTitle = $basename_chat.'.log.html';
$filePath = $basepath_chat.'/'.$fileTitle;
$absoluteFilePath = $chat_path.$fileTitle;
if (!file_exists($absoluteFilePath)) {
$doc_id = add_document(
$courseInfo,
$filePath,
'file',
0,
$fileTitle,
null,
0,
true,
0,
0,
0,
false
);
$documentLogTypes = ['DocumentAdded', 'invisible'];
foreach ($documentLogTypes as $logType) {
api_item_property_update(
$courseInfo,
TOOL_DOCUMENT,
$doc_id,
$logType,
$this->userId,
$group_info,
null,
null,
null,
$this->sessionId
);
}
item_property_update_on_folder($courseInfo, $basepath_chat, $this->userId);
} else {
$doc_id = DocumentManager::get_document_id($courseInfo, $filePath);
}
$fp = fopen($absoluteFilePath, 'a');
$userPhoto = UserManager::getUserPicture($this->userId, USER_IMAGE_SIZE_MEDIUM, true, $userInfo);
if ($isMaster) {
$fileContent = '
<div class="message-teacher">
<div class="content-message">
<div class="chat-message-block-name">'.$userInfo['complete_name'].'</div>
<div class="chat-message-block-content">'.$message.'</div>
<div class="message-date">'.$timeNow.'</div>
</div>
<div class="icon-message"></div>
<img class="chat-image" src="'.$userPhoto.'">
</div>
';
} else {
$fileContent = '
<div class="message-student">
<img class="chat-image" src="'.$userPhoto.'">
<div class="icon-message"></div>
<div class="content-message">
<div class="chat-message-block-name">'.$userInfo['complete_name'].'</div>
<div class="chat-message-block-content">'.$message.'</div>
<div class="message-date">'.$timeNow.'</div>
</div>
</div>
';
}
fputs($fp, $fileContent);
fclose($fp);
$size = filesize($absoluteFilePath);
update_existing_document($courseInfo, $doc_id, $size);
item_property_update_on_folder($courseInfo, $basepath_chat, $this->userId);
return true;
}
/**
* Disconnect a user from course chats.
*
* @param int $userId
*/
public static function exitChat($userId)
{
$listCourse = CourseManager::get_courses_list_by_user_id($userId);
foreach ($listCourse as $course) {
Database::getManager()
->createQuery('
DELETE FROM ChamiloCourseBundle:CChatConnected ccc
WHERE ccc.cId = :course AND ccc.userId = :user
')
->execute([
'course' => intval($course['real_id']),
'user' => intval($userId),
]);
}
}
/**
* Disconnect users who are more than 5 seconds inactive.
*/
public function disconnectInactiveUsers()
{
$em = Database::getManager();
$extraCondition = "AND ccc.toGroupId = {$this->groupId}";
if (empty($this->groupId)) {
$extraCondition = "AND ccc.sessionId = {$this->sessionId}";
}
$connectedUsers = $em
->createQuery("
SELECT ccc FROM ChamiloCourseBundle:CChatConnected ccc
WHERE ccc.cId = :course $extraCondition
")
->setParameter('course', $this->courseId)
->getResult();
$now = new DateTime(api_get_utc_datetime(), new DateTimeZone('UTC'));
$cd_count_time_seconds = $now->getTimestamp();
/** @var CChatConnected $connection */
foreach ($connectedUsers as $connection) {
$date_count_time_seconds = $connection->getLastConnection()->getTimestamp();
if (strcmp($now->format('Y-m-d'), $connection->getLastConnection()->format('Y-m-d')) !== 0) {
continue;
}
if (($cd_count_time_seconds - $date_count_time_seconds) <= 5) {
continue;
}
$em
->createQuery('
DELETE FROM ChamiloCourseBundle:CChatConnected ccc
WHERE ccc.cId = :course AND ccc.userId = :user AND ccc.toGroupId = :group
')
->execute([
'course' => $this->courseId,
'user' => $connection->getUserId(),
'group' => $this->groupId,
]);
}
}
/**
* Keep registered to a user as connected.
*/
public function keepUserAsConnected()
{
$em = Database::getManager();
$extraCondition = null;
if ($this->groupId) {
$extraCondition = 'AND ccc.toGroupId = '.intval($this->groupId);
} else {
$extraCondition = 'AND ccc.sessionId = '.intval($this->sessionId);
}
$currentTime = new DateTime(api_get_utc_datetime(), new DateTimeZone('UTC'));
$connection = $em
->createQuery("
SELECT ccc FROM ChamiloCourseBundle:CChatConnected ccc
WHERE ccc.userId = :user AND ccc.cId = :course $extraCondition
")
->setParameters([
'user' => $this->userId,
'course' => $this->courseId,
])
->getOneOrNullResult();
if ($connection) {
$connection->setLastConnection($currentTime);
$em->merge($connection);
$em->flush();
return;
}
$connection = new CChatConnected();
$connection
->setCId($this->courseId)
->setUserId($this->userId)
->setLastConnection($currentTime)
->setSessionId($this->sessionId)
->setToGroupId($this->groupId);
$em->persist($connection);
$em->flush();
}
/**
* Get the emoji allowed on course chat.
*
* @return array
*/
public static function getEmojiStrategy()
{
return require_once api_get_path(SYS_CODE_PATH).'chat/emoji_strategy.php';
}
/**
* Get the emoji list to include in chat.
*
* @return array
*/
public static function getEmojisToInclude()
{
return [
':bowtie:',
':smile:' |
':laughing:',
':blush:',
':smiley:',
':relaxed:',
':smirk:',
':heart_eyes:',
':kissing_heart:',
':kissing_closed_eyes:',
':flushed:',
':relieved:',
':satisfied:',
':grin:',
':wink:',
':stuck_out_tongue_winking_eye:',
':stuck_out_tongue_closed_eyes:',
':grinning:',
':kissing:',
':kissing_smiling_eyes:',
':stuck_out_tongue:',
':sleeping:',
':worried:',
':frowning:',
':anguished:',
':open_mouth:',
':grimacing:',
':confused:',
':hushed:',
':expressionless:',
':unamused:',
':sweat_smile:',
':sweat:',
':disappointed_relieved:',
':weary:',
':pensive:',
':disappointed:',
':confounded:',
':fearful:',
':cold_sweat:',
':persevere:',
':cry:',
':sob:',
':joy:',
':astonished:',
':scream:',
':neckbeard:',
':tired_face:',
':angry:',
':rage:',
':triumph:',
':sleepy:',
':yum:',
':mask:',
':sunglasses:',
':dizzy_face:',
':imp:',
':smiling_imp:',
':neutral_face:',
':no_mouth:',
':innocent:',
':alien:',
];
}
/**
* Get the chat history file name.
*
* @param bool $absolute Optional. Whether get the base or the absolute file path
* @param int $friendId optional
*
* @return string
*/
public function getFileName($absolute = false, $friendId = 0)
{
$date = date('Y-m-d');
$base = 'messages-'.$date.'.log.html';
if ($this->groupId && !$friendId) {
$base = 'messages-'.$date.'_gid-'.$this->groupId.'.log.html';
} elseif ($this->sessionId && !$friendId) {
$base = 'messages-'.$date.'_sid-'.$this->sessionId.'.log.html';
} elseif ($friendId) {
if ($this->userId < $friendId) {
$base = 'messages-'.$date.'_uid-'.$this->userId.'-'.$friendId.'.log.html';
} else {
$base = 'messages-'.$date.'_uid-'.$friendId.'-'.$this->userId.'.log.html';
}
}
if (!$absolute) {
return $base;
}
$courseInfo = api_get_course_info_by_id($this->courseId);
$document_path = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document';
$chatPath = $document_path.'/chat_files/';
if ($this->groupId) {
$group_info = GroupManager::get_group_properties($this->groupId);
$chatPath = $document_path.$group_info['directory'].'/chat_files/';
}
return $chatPath.$base;
}
/**
* Get the chat history.
*
* @param bool $reset
* @param int $friendId optional
*
* @return string
*/
public function readMessages($reset = false, $friendId = 0)
{
$courseInfo = api_get_course_info_by_id($this->courseId);
$date_now = date('Y-m-d');
$isMaster = (bool) api_is_course_admin();
$basepath_chat = '/chat_files';
$document_path = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document';
$group_info = [];
if ($this->groupId) {
$group_info = GroupManager::get_group_properties($this->groupId);
$basepath_chat = $group_info['directory'].'/chat_files';
}
$chat_path = $document_path.$basepath_chat.'/';
if (!is_dir($chat_path)) {
if (is_file($chat_path)) {
@unlink($chat_path);
}
if (!api_is_anonymous()) {
@mkdir($chat_path, api_get_permissions_for_new_directories());
// Save chat files document for group into item property
if ($this->groupId) {
$doc_id = add_document(
$courseInfo,
$basepath_chat,
'folder',
0,
'chat_files',
null,
0,
true,
0,
0,
0,
false
);
api_item_property_update(
$courseInfo,
TOOL_DOCUMENT,
$doc_id,
'FolderCreated',
null,
$group_info,
null,
null,
null
);
api_item_property_update(
$courseInfo,
TOOL_DOCUMENT,
$doc_id,
'invisible',
null,
$group_info,
null,
null,
null
);
}
}
}
$filename_chat = 'messages-'.$date_now.'.log.html';
if ($this->groupId && !$friendId) {
$filename_chat = 'messages-'.$date_now.'_gid-'.$this->groupId.'.log.html';
} elseif ($this->sessionId && !$friendId) {
$filename_chat = 'messages-'.$date_now.'_sid-'.$this->sessionId.'.log.html';
} elseif ($friendId) {
if ($this->userId < $friendId) {
$filename_chat = 'messages-'.$date_now.'_uid-'.$this->userId.'-'.$friendId.'.log.html';
} else {
$filename_chat = 'messages-'.$date_now.'_uid-'.$friendId.'-'.$this->userId.'.log.html';
}
}
if (!file_exists($chat_path.$filename_chat)) {
@fclose(fopen($chat_path.$filename_chat, 'w'));
if (!api_is_anonymous()) {
$doc_id = add_document(
$courseInfo,
$basepath_chat.'/'.$filename_chat,
'file',
0,
$filename_chat,
null,
0,
true,
0,
0,
0,
false
);
if ($doc_id) {
api_item_property_update(
$courseInfo,
TOOL_DOCUMENT,
$doc_id,
'DocumentAdded',
$this->userId,
$group_info,
null,
null,
null,
$this->sessionId
);
api_item_property_update(
$courseInfo,
TOOL_DOCUMENT,
$doc_id,
'invisible',
$this->userId,
$group_info,
null,
null,
null,
$this->sessionId
);
item_property_update_on_folder($courseInfo, $basepath_chat, $this->userId);
}
}
}
$basename_chat = 'messages-'.$date_now;
if ($this->groupId && !$friendId) {
$basename_chat = 'messages-'.$date_now.'_gid-'.$this->groupId;
} elseif ($this->sessionId && !$friendId) {
$basename_chat = 'messages-'.$date_now.'_sid-'.$this->sessionId;
} elseif ($friendId) {
if ($this->userId < $friendId) {
$basename_chat = 'messages-'.$date_now.'_uid-'.$this->userId.'-'.$friendId;
} else {
$basename_chat = 'messages-'.$date_now.'_uid-'.$friendId.'-'.$this->userId;
}
}
if ($reset && $isMaster) {
$i = 1;
while (file_exists($chat_path.$basename_chat.'-'.$i.'.log.html')) {
$i++;
}
@rename($chat_path.$basename_chat.'.log.html', $chat_path.$basename_chat.'-'.$i.'.log.html');
@fclose(fopen($chat_path.$basename_chat.'.log.html', 'w'));
$doc_id = add_document(
$courseInfo,
$basepath_chat.'/'.$basename_chat.'-'.$i.'.log.html',
'file',
filesize($chat_path.$basename_chat.'-'.$i.'.log.html'),
$basename_chat.'-'.$i.'.log.html',
null,
0,
true,
0,
0,
0,
false
);
api_item_property_update(
$courseInfo,
TOOL_DOCUMENT,
$doc_id,
'DocumentAdded',
$this->userId,
$group_info,
null,
null,
null,
$this->sessionId
);
api_item_property_update(
$courseInfo,
TOOL_DOCUMENT,
$doc_id,
'invisible',
$this->userId,
$group_info,
null,
null,
null,
$this->sessionId
);
item_property_update_on_folder($courseInfo, $basepath_chat, $this->userId);
$doc_id = DocumentManager::get_document_id(
$courseInfo,
$basepath_chat.'/'.$basename_chat.'.log.html'
);
update_existing_document($courseInfo, $doc_id, 0);
}
$remove = 0;
$content = [];
if (file_exists($chat_path.$basename_chat.'.log.html')) {
$content = file($chat_path.$basename_chat.'.log.html');
$nbr_lines = sizeof($content);
$remove = $nbr_lines - 100;
}
if ($remove < 0) {
$remove = 0;
}
array_splice($content, 0, $remove);
if (isset($_GET['origin']) && $_GET['origin'] == 'whoisonline') {
//the caller
$content[0] = get_lang('CallSent').'<br />'.$content[0];
}
$history = '<div id="content-chat">';
foreach ($content as $this_line) {
$history .= $this_line;
}
$history .= '</div>';
if ($isMaster || $GLOBALS['is_session_general_coach']) {
$history .= '
<div id="clear-chat">
<button type="button" id="chat-reset" class="btn btn-danger btn-sm">
'.get_lang('ClearList').'
</button>
</div>
';
}
return $history;
}
/**
* Get the number of users connected in chat.
*
* @return int
*/
public function countUsersOnline()
{
$date = new DateTime(api_get_utc_datetime(), new DateTimeZone('UTC'));
$date->modify('-5 seconds');
if ($this->groupId) {
$extraCondition = 'AND ccc.toGroupId = '.intval($this->groupId);
} else {
$extraCondition = 'AND ccc.sessionId = '.intval($this->sessionId);
}
$number = Database::getManager()
->createQuery("
SELECT COUNT(ccc.userId) FROM ChamiloCourseBundle:CChatConnected ccc
WHERE ccc.lastConnection > :date AND ccc.cId = :course $extraCondition
")
->setParameters([
'date' => $date,
'course' => $this->courseId,
])
->getSingleScalarResult();
return (int) $number;
}
/**
* Get the users online data.
*
* @throws \Doctrine\ORM\ORMException
* @throws \Doctrine\ORM\OptimisticLockException
* @throws \Doctrine\ORM\TransactionRequiredException
*
* @return array
*/
public function listUsersOnline()
{
$subscriptions = $this->getUsersSubscriptions();
$usersInfo = [];
if ($this->groupId) {
/** @var User $groupUser */
foreach ($subscriptions as $groupUser) {
$usersInfo[] = $this->formatUser(
$groupUser,
$groupUser->getStatus()
);
}
} else {
/** @var CourseRelUser|SessionRelCourseRelUser $subscription */
foreach ($subscriptions as $subscription) {
$user = $subscription->getUser();
$usersInfo[] = $this->formatUser(
$user,
$this->sessionId ? $user->getStatus() : $subscription->getStatus()
);
}
}
return $usersInfo;
}
/**
* Format the user data to return it in the user list.
*
* @param int $status
*
* @return array
*/
private function formatUser(User $user, $status)
{
return [
'id' => $user->getId(),
'firstname' => $user->getFirstname(),
'lastname' => $user->getLastname(),
'status' => $status,
'image_url' => UserManager::getUserPicture($user->getId(), USER_IMAGE_SIZE_MEDIUM),
'profile_url' => api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user->getId(),
'complete_name' => UserManager::formatUserFullName($user),
'username' => $user->getUsername(),
'email' => $user->getEmail(),
'isConnected' => $this->userIsConnected($user->getId()),
];
}
/**
* Get the users subscriptions (SessionRelCourseRelUser array or CourseRelUser array) for chat.
*
* @throws \Doctrine\ORM\ORMException
* @throws \Doctrine\ORM\OptimisticLockException
* @throws \Doctrine\ORM\TransactionRequiredException
*
* @return \Doctrine\Common\Collections\ArrayCollection
*/
private function getUsersSubscriptions()
{
$em = Database::getManager();
if ($this->groupId) {
$students = $em
->createQuery(
'SELECT u FROM ChamiloUserBundle:User u
INNER JOIN ChamiloCourseBundle:CGroupRelUser gru
WITH u.id = gru.userId AND gru.cId = :course
WHERE u.id != :user AND gru.groupId = :group
AND u.active = true'
)
->setParameters(['course' => $this->courseId, 'user' => $this->userId, 'group' => $this->groupId])
->getResult();
$tutors = $em
->createQuery(
'SELECT u FROM ChamiloUserBundle:User u
INNER JOIN ChamiloCourseBundle:CGroupRelTutor grt
WITH u.id = grt.userId AND grt.cId = :course
WHERE u.id != :user AND grt.groupId = :group
AND u.active = true'
)
->setParameters(['course' => $this->courseId, 'user' => $this->userId, 'group' => $this->groupId])
->getResult();
return array_merge($tutors, $students);
}
/** @var Course $course */
$course = $em->find('ChamiloCoreBundle:Course', $this->courseId);
if ($this->sessionId) {
/** @var Session $session */
$session = $em->find('ChamiloCoreBundle:Session', $this->sessionId);
$criteria = Criteria::create()->where(Criteria::expr()->eq('course', $course));
$userIsCoach = api_is_course_session_coach($this->userId, $course->getId(), $session->getId());
if (api_get_configuration_value('course_chat_restrict_to_coach')) {
if ($userIsCoach) {
$criteria->andWhere(
Criteria::expr()->eq('status', Session::STUDENT)
);
} else {
$criteria->andWhere(
Criteria::expr()->eq('status', Session::COACH)
);
}
}
$criteria->orderBy(['status' => Criteria::DESC]);
return $session
->getUserCourseSubscriptions()
->matching($criteria)
->filter(function (SessionRelCourseRelUser $sessionRelCourseRelUser) {
return $sessionRelCourseRelUser->getUser()->isActive();
});
}
return $course
->getUsers()
->filter(function (CourseRelUser $courseRelUser) {
return $courseRelUser->getUser()->isActive();
});
}
/**
* Check if a user is connected in course chat.
*
* @param int $userId
*
* @return int
*/
private function userIsConnected($userId)
{
$date = new DateTime(api_get_utc_datetime(), new DateTimeZone('UTC'));
$date->modify('-5 seconds');
if ($this->groupId) {
$extraCondition = 'AND ccc.toGroupId = '.intval($this->groupId);
} else {
$extraCondition = 'AND ccc.sessionId = '.intval($this->sessionId);
}
$number = Database::getManager()
->createQuery("
SELECT COUNT(ccc.userId) FROM ChamiloCourseBundle:CChatConnected ccc
WHERE ccc.lastConnection > :date AND ccc.cId = :course AND ccc.userId = :user $extraCondition
")
->setParameters([
'date' => $date,
'course' => $this->courseId,
'user' => $userId,
])
->getSingleScalarResult();
return (int) $number;
}
}

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -0,0 +1,231 @@
<?php
/* For licensing terms, see /license.txt */
/**
* GamificationUtils class
* Functions to manage the gamification mode.
*
* @author Angel Fernando Quiroz Campos <angel.quiroz@beeznest.com>
*/
class GamificationUtils
{
/**
* Get the calculated points on session with gamification mode.
*
* @param int $userId The user ID
* @param int $userStatus The user Status
*
* @return float
*/
public static function getTotalUserPoints($userId, $userStatus)
{
$points = 0;
$sessions = SessionManager::getSessionsFollowedByUser(
$userId,
$userStatus
);
if (empty($sessions)) {
return 0;
}
foreach ($sessions as $session) {
$points += self::getSessionPoints($session['id'], $userId);
}
return round($points / count($sessions), 2);
}
/**
* Get the achieved points for an user in a session.
*
* @param int $sessionId The session ID
* @param int $userId The user ID
*
* @return int The count of points
*/
public static function getSessionPoints($sessionId, $userId)
{
$totalPoints = 0;
$courses = SessionManager::get_course_list_by_session_id($sessionId);
if (empty($courses)) {
return 0;
}
foreach ($courses as $course) {
$learnPathListObject = new LearnpathList(
$userId,
api_get_course_info($course['code']),
$sessionId
);
$learnPaths = $learnPathListObject->get_flat_list();
if (empty($learnPaths)) {
continue;
}
$score = 0;
foreach ($learnPaths as $learnPathId => $learnPathInfo) {
if (empty($learnPathInfo['seriousgame_mode'])) {
continue;
}
$learnPath = new learnpath(
$course['code'],
$learnPathId,
$userId
);
$score += $learnPath->getCalculateScore($sessionId);
}
$totalPoints += round($score / count($learnPaths), 2);
}
return round($totalPoints / count($courses), 2);
}
/**
* Get the calculated progress for an user in a session.
*
* @param int $sessionId The session ID
* @param int $userId The user ID
*
* @return float The progress
*/
public static function getSessionProgress($sessionId, $userId)
{
$courses = SessionManager::get_course_list_by_session_id($sessionId);
$progress = 0;
if (empty($courses)) {
return 0;
}
foreach ($courses as $course) {
$courseProgress = Tracking::get_avg_student_progress(
$userId,
$course['code'],
[],
$sessionId,
false,
true
);
if (false === $courseProgress) {
continue;
}
$progress += $courseProgress;
}
return round($progress / count($courses), 2);
}
/**
* Get the number of stars achieved for an user in a session.
*
* @param int $sessionId The session ID
* @param int $userId The user ID
*
* @return int The number of stars
*/
public static function getSessionStars($sessionId, $userId)
{
$totalStars = 0;
$courses = SessionManager::get_course_list_by_session_id($sessionId);
if (empty($courses)) {
return 0;
}
foreach ($courses as $course) {
$learnPathListObject = new LearnpathList(
$userId,
api_get_course_info($course['code']),
$sessionId
);
$learnPaths = $learnPathListObject->get_flat_list();
if (empty($learnPaths)) {
continue;
}
$stars = 0;
foreach ($learnPaths as $learnPathId => $learnPathInfo) {
if (empty($learnPathInfo['seriousgame_mode'])) {
continue;
}
$learnPath = new learnpath(
$course['code'],
$learnPathId,
$userId
);
$stars += $learnPath->getCalculateStars($sessionId);
}
$totalStars += round($stars / count($learnPaths));
}
return round($totalStars / count($courses));
}
/**
* Get the stars on sessions with gamification mode.
*
* @param int $userId The user ID
* @param int $userStatus The user Status
*
* @return int
*/
public static function getTotalUserStars($userId, $userStatus)
{
$stars = 0;
$sessions = SessionManager::getSessionsFollowedByUser(
$userId,
$userStatus
);
if (empty($sessions)) {
return 0;
}
foreach ($sessions as $session) {
$stars += self::getSessionStars($session['id'], $userId);
}
return round($stars / count($sessions));
}
/**
* Get the total progress on sessions with gamification mode.
*
* @param int $userId The user ID
* @param int $userStatus The user Status
*
* @return float
*/
public static function getTotalUserProgress($userId, $userStatus)
{
$progress = 0;
$sessions = SessionManager::getSessionsFollowedByUser(
$userId,
$userStatus
);
if (empty($sessions)) {
return 0;
}
foreach ($sessions as $session) {
$progress += self::getSessionProgress($session['id'], $userId);
}
return round($progress / count($sessions), 2);
}
}

View File

@@ -0,0 +1,237 @@
<?php
/* For licensing terms, see /license.txt */
use Symfony\Component\Finder\Finder;
/**
* Class MailTemplateManager.
*/
class MailTemplateManager extends Model
{
public $columns = [
'id',
'name',
'template',
'type',
'system',
'url_id',
'default_template',
'created_at',
'updated_at',
'author_id',
];
public function __construct()
{
parent::__construct();
$this->table = 'mail_template';
}
/**
* @return int
*/
public function get_count()
{
$row = Database::select(
'count(*) as count',
$this->table,
['where' => ['url_id = ? ' => api_get_current_access_url_id()]],
'first'
);
return $row['count'];
}
/**
* Displays the title + grid.
*
* @return string html code
*/
public function display()
{
// Action links
$html = '<div class="actions" style="margin-bottom:20px">';
$html .= '<a href="'.api_get_path(WEB_CODE_PATH).'admin">'.
Display::return_icon(
'back.png',
get_lang('Back'),
'',
'32'
)
.'</a>';
$html .= '<a href="'.api_get_self().'?action=add">'.
Display::return_icon(
'add.png',
get_lang('Add'),
'',
'32'
).'</a>';
$html .= '</div>';
$html .= Display::grid_html('mail_template');
return $html;
}
/**
* Returns a Form validator Obj.
*
* @param string $url
* @param string $action
*
* @return FormValidator
*/
public function returnForm($url, $action = 'add')
{
$form = new FormValidator('template', 'post', $url);
// Setting the form elements
$header = get_lang('Add');
if ($action === 'edit') {
$header = get_lang('Modify');
}
$id = isset($_GET['id']) ? (int) $_GET['id'] : '';
$form->addElement('header', '', $header);
$form->addElement('hidden', 'id', $id);
$form->addElement(
'text',
'name',
get_lang('Name'),
['size' => '70', 'id' => 'name']
);
/*$form->addHtmlEditor(
'email_template',
get_lang('Template'),
false,
false,
[
'ToolbarSet' => 'Careers',
'Width' => '100%',
'Height' => '250',
]
);*/
$form->addTextarea(
'email_template',
get_lang('Template')
);
$finder = new Finder();
$files = $finder
->files()
->in(api_get_path(SYS_CODE_PATH).'template/default/mail')
->sort(
function ($a, $b) {
return strcmp($a->getRealpath(), $b->getRealpath());
}
);
$options = [];
/** @var SplFileInfo $file */
foreach ($files as $file) {
$options[$file->getFilename()] = $file->getFilename();
}
$form->addSelect(
'type',
get_lang('Type'),
$options
);
$defaults = $this->get($id);
if ($action === 'edit') {
$form->addLabel(get_lang('CreatedAt'), Display::dateToStringAgoAndLongDate($defaults['created_at']));
$form->addLabel(get_lang('UpdatedAt'), Display::dateToStringAgoAndLongDate($defaults['updated_at']));
$form->addButtonSave(get_lang('Modify'), 'submit');
} else {
$form->addButtonCreate(get_lang('Add'), 'submit');
}
// Setting the defaults
if (!empty($defaults)) {
$defaults['email_template'] = $defaults['template'];
}
$form->setDefaults($defaults);
// Setting the rules
$form->addRule('name', get_lang('ThisFieldIsRequired'), 'required');
return $form;
}
/**
* @param int $id
*
* @return bool
*/
public function setDefault($id)
{
$template = $this->get($id);
if (empty($template)) {
return false;
}
$type = $template['type'];
$urlId = api_get_current_access_url_id();
$sql = "UPDATE {$this->table} SET default_template = 0
WHERE type = '$type' AND url_id = $urlId";
Database::query($sql);
$sql = "UPDATE {$this->table} SET default_template = 1
WHERE id = $id";
Database::query($sql);
return true;
}
/**
* @param int $templateId
* @param array $userInfo
*
* @return string|false
*/
public function parseTemplate($templateId, $userInfo)
{
$templateInfo = $this->get($templateId);
if (!empty($templateInfo)) {
$emailTemplate = nl2br($templateInfo['template']);
$keys = array_keys($userInfo);
foreach ($keys as $key) {
$emailTemplate = str_replace("{{user.$key}}", $userInfo[$key], $emailTemplate);
}
$template = new Template();
$template->twig->setLoader(new \Twig_Loader_String());
$emailBody = $template->twig->render($emailTemplate);
return $emailBody;
}
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'];
}
}

File diff suppressed because it is too large Load Diff

101
main/inc/lib/MyStudents.php Normal file
View File

@@ -0,0 +1,101 @@
<?php
/* For licensing terms, see /license.txt */
class MyStudents
{
public static function userCareersTable(int $studentId): string
{
if (!api_get_configuration_value('allow_career_users')) {
return '';
}
$careers = UserManager::getUserCareers($studentId);
if (empty($careers)) {
return '';
}
$title = Display::page_subheader(get_lang('Careers'), null, 'h3', ['class' => 'section-title']);
return $title.self::getCareersTable($careers, $studentId);
}
public static function getCareersTable(array $careers, int $studentId): string
{
if (empty($careers)) {
return '';
}
$webCodePath = api_get_path(WEB_CODE_PATH);
$iconDiagram = Display::return_icon('multiplicate_survey.png', get_lang('Diagram'));
$careerModel = new Career();
$headers = [
get_lang('Career'),
get_lang('Diagram'),
];
$data = array_map(
function (array $careerInfo) use ($careerModel, $webCodePath, $iconDiagram, $studentId) {
$careerId = $careerInfo['id'];
if (api_get_configuration_value('use_career_external_id_as_identifier_in_diagrams')) {
$careerId = $careerModel->getCareerIdFromInternalToExternal($careerId);
}
$url = $webCodePath.'user/career_diagram.php?career_id='.$careerId.'&user_id='.$studentId;
return [
$careerInfo['name'],
Display::url($iconDiagram, $url),
];
},
$careers
);
$table = new HTML_Table(['class' => 'table table-hover table-striped data_table']);
$table->setHeaders($headers);
$table->setData($data);
return $table->toHtml();
}
public static function getBlockForSkills(int $studentId, int $courseId, int $sessionId): string
{
$allowAll = api_get_configuration_value('allow_teacher_access_student_skills');
if ($allowAll) {
return Tracking::displayUserSkills($studentId, 0, 0, true);
}
// Default behaviour - Show all skills depending the course and session id
return Tracking::displayUserSkills($studentId, $courseId, $sessionId);
}
public static function getBlockForClasses($studentId): ?string
{
$userGroupManager = new UserGroup();
$userGroups = $userGroupManager->getNameListByUser(
$studentId,
UserGroup::NORMAL_CLASS
);
if (empty($userGroups)) {
return null;
}
$headers = [get_lang('Classes')];
$data = array_map(
function ($class) {
return [$class];
},
$userGroups
);
$table = new HTML_Table(['class' => 'table table-hover table-striped data_table']);
$table->setHeaders($headers);
$table->setData($data);
return $table->toHtml();
}
}

View File

@@ -0,0 +1,452 @@
<?php
/* For licensing terms, see /license.txt */
class NotificationEvent extends Model
{
public const ACCOUNT_EXPIRATION = 1;
public const JUSTIFICATION_EXPIRATION = 2;
public const GLOBAL_NOTIFICATION = 3;
public const SPECIFIC_USER = 4;
public $table;
public $columns = [
'id',
'title',
'content',
'link',
'persistent',
'day_diff',
'event_type',
'event_id',
];
public $extraFieldName;
/**
* Constructor.
*/
public function __construct()
{
parent::__construct();
$this->table = 'notification_event';
$this->extraFieldName = 'notification_event';
}
public function eventTypeToString($eventTypeId)
{
$list = $this->getEventsForSelect(false);
return $list[$eventTypeId];
}
public function getEventsForSelect($onlyEnabled = true): array
{
$eventTypes = [
self::ACCOUNT_EXPIRATION => get_lang('AccountExpiration'),
self::GLOBAL_NOTIFICATION => get_lang('Global'),
self::SPECIFIC_USER => get_lang('SpecificUsers'),
];
if (!$onlyEnabled || api_get_plugin_setting('justification', 'tool_enable') === 'true') {
$eventTypes[self::JUSTIFICATION_EXPIRATION] = get_lang('JustificationExpiration');
}
return $eventTypes;
}
/**
* @throws Exception
*/
public function getForm(FormValidator $form, $data = []): FormValidator
{
$options = $this->getEventsForSelect();
$form->addSelect('event_type', get_lang('EventType'), $options);
$form->freeze('event_type');
$eventType = $data['event_type'];
switch ($eventType) {
case self::JUSTIFICATION_EXPIRATION:
$list = [];
if (api_get_plugin_setting('justification', 'tool_enable') === 'true'
&& $list = Justification::create()->getList()
) {
$list = array_column($list, 'name', 'id');
}
$form->addSelect('event_id', get_lang('JustificationType'), $list);
$form->freeze('event_id');
break;
default:
break;
}
$form->addText('title', get_lang('Title'));
$form->addTextarea('content', get_lang('Content'));
$form->addText('link', get_lang('Link'), false);
$form->addCheckBox('persistent', get_lang('Persistent'));
$form->addNumeric('day_diff', get_lang('DaysDifference'), false);
switch ($eventType) {
case self::SPECIFIC_USER:
$form->addSelectAjax(
'users',
get_lang('Users'),
$data['users'] ?? [],
[
'url' => api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_like',
'multiple' => 'multiple',
]
);
//no break
case self::GLOBAL_NOTIFICATION:
$form->removeElement('day_diff');
break;
}
return $form;
}
/**
* @throws Exception
*/
public function getAddForm(FormValidator $form): FormValidator
{
$options = $this->getEventsForSelect();
$eventType = $form->getSubmitValue('event_type');
$form->addSelect(
'event_type',
get_lang('EventType'),
$options,
['placeholder' => get_lang('SelectAnOption'), 'onchange' => 'document.add.submit()']
);
if (!empty($eventType)) {
$form->freeze('event_type');
$form->addText('title', get_lang('Title'));
$form->addTextarea('content', get_lang('Content'));
$form->addText('link', get_lang('Link'), false);
$form->addCheckBox('persistent', get_lang('Persistent'));
$form->addNumeric('day_diff', get_lang('DaysDifference'), false);
switch ($eventType) {
case self::JUSTIFICATION_EXPIRATION:
$list = [];
if (api_get_plugin_setting('justification', 'tool_enable') === 'true'
&& $list = Justification::create()->getList()
) {
$list = array_column($list, 'name', 'id');
}
$form->addSelect('event_id', get_lang('JustificationType'), $list);
break;
case self::SPECIFIC_USER:
$form->addSelectAjax(
'users',
get_lang('Users'),
[],
[
'url' => api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_like',
'multiple' => 'multiple',
]
);
//no break
case self::GLOBAL_NOTIFICATION:
$form->removeElement('day_diff');
break;
default:
break;
}
$form->addButtonSave(get_lang('Save'));
}
return $form;
}
public function getUserExtraData($userId)
{
$data = UserManager::get_extra_user_data_by_field($userId, $this->extraFieldName);
return $data['notification_event'] ?? '';
}
/**
* @throws Exception
*/
public function getNotificationsByUser(int $userId): array
{
$userInfo = api_get_user_info($userId);
$events = $this->get_all();
$extraFieldData = $this->getUserExtraData($userId);
$notifications = [];
foreach ($events as $event) {
$days = (int) $event['day_diff'];
$checkIsRead = $event['persistent'] == 0;
$eventItemId = $event['event_id'];
switch ($event['event_type']) {
case self::ACCOUNT_EXPIRATION:
if (empty($userInfo['expiration_date'])) {
break;
}
$id = 'id_'.self::ACCOUNT_EXPIRATION.'_event_'.$event['id'].'_'.$userInfo['id'];
$read = false;
if ($checkIsRead) {
$read = $this->isRead($id, $extraFieldData);
}
$showNotification = $this->showNotification($userInfo['expiration_date'], $days);
if ($showNotification && $read === false) {
$notifications[] = [
'id' => $id,
'title' => $event['title'],
'content' => $event['content'],
'event_text' => get_lang('ExpirationDate').': '.api_get_local_time($userInfo['expiration_date']),
'link' => $event['link'],
'persistent' => $event['persistent'],
];
}
break;
case self::JUSTIFICATION_EXPIRATION:
if (api_get_plugin_setting('justification', 'tool_enable') !== 'true') {
break;
}
$plugin = Justification::create();
$userJustificationList = $plugin->getUserJustificationList($userId);
foreach ($userJustificationList as $userJustification) {
if (empty($userJustification['date_validity'])) {
continue;
}
if ($eventItemId != $userJustification['justification_document_id']) {
continue;
}
$showNotification = $this->showNotification($userJustification['date_validity'], $days);
$id = 'id_'.self::JUSTIFICATION_EXPIRATION.'_event_'.$event['id'].'_'.$userJustification['id'];
$fieldData = $plugin->getJustification($userJustification['justification_document_id']);
$read = false;
if ($checkIsRead) {
$read = $this->isRead($id, $extraFieldData);
}
$eventText = $plugin->get_lang('Justification').': '.$fieldData['name'].' <br />';
$eventText .= $plugin->get_lang('JustificationDate').': '.$userJustification['date_validity'];
$url = $event['link'];
if (empty($url)) {
$url = api_get_path(WEB_CODE_PATH).'auth/justification.php#'.$fieldData['code'];
}
if ($showNotification && $read === false) {
$notifications[] = [
'id' => $id,
'title' => $event['title'],
'content' => $event['content'],
'event_text' => $eventText,
'link' => $url,
'persistent' => $event['persistent'],
];
}
}
break;
case self::SPECIFIC_USER:
$assignedUsers = self::getAssignedUsers($event['id']);
$assignedUserIdList = array_keys($assignedUsers);
if (!in_array($userId, $assignedUserIdList)) {
break;
}
//no break
case self::GLOBAL_NOTIFICATION:
$id = "id_{$event['event_type']}_event_{$event['id']}_$userId";
$wasRead = $checkIsRead && $this->isRead($id, $extraFieldData);
if (!$wasRead) {
$notifications[] = [
'id' => $id,
'title' => $event['title'],
'content' => $event['content'],
'event_text' => null,
'link' => $event['link'],
'persistent' => $event['persistent'],
];
}
break;
}
}
return $notifications;
}
public function isRead($id, $extraData): bool
{
$userId = api_get_user_id();
if (empty($extraData)) {
return false;
}
$data = $this->getUserExtraData($userId);
if (empty($data)) {
return false;
}
$data = json_decode($data);
if (in_array($id, $data)) {
return true;
}
return false;
}
public function markAsRead($id): bool
{
if (empty($id)) {
return false;
}
$userId = api_get_user_id();
$data = $this->getUserExtraData($userId);
if (!empty($data)) {
$data = json_decode($data);
} else {
$data = [];
}
$data[] = $id;
$data = json_encode($data);
UserManager::update_extra_field_value($userId, $this->extraFieldName, $data);
return true;
}
/**
* @throws Exception
*/
public function showNotification($date, $dayDiff): bool
{
$today = api_get_utc_datetime();
$expiration = api_get_utc_datetime($date, false, true);
$interval = new DateInterval('P'.$dayDiff.'D');
$diff = $expiration->sub($interval);
if ($diff->format('Y-m-d H:i:s') < $today) {
return true;
}
return false;
}
public function install()
{
$sql = "CREATE TABLE IF NOT EXISTS notification_event (
id INT unsigned NOT NULL auto_increment PRIMARY KEY,
title VARCHAR(255),
content TEXT,
link TEXT,
persistent INT,
day_diff INT,
event_type VARCHAR(255)
)";
Database::query($sql);
}
public function save($params, $show_query = false)
{
$userIdList = [];
if (isset($params['users'])) {
$userIdList = $params['users'];
unset($params['users']);
}
/** @var int|bool $saved */
$saved = parent::save($params, $show_query);
if (false !== $saved && !empty($userIdList)) {
self::assignUserIdList($saved, $userIdList);
}
return $saved;
}
public function update($params, $showQuery = false): bool
{
$userIdList = [];
if (isset($params['users'])) {
$userIdList = $params['users'];
unset($params['users']);
}
$updated = parent::update($params, $showQuery);
self::deleteAssignedUsers($params['id']);
self::assignUserIdList($params['id'], $userIdList);
return $updated;
}
public function get($id)
{
$props = parent::get($id);
$props['users'] = self::getAssignedUsers($id);
return $props;
}
public static function assignUserIdList(int $eventId, array $userIdList)
{
foreach ($userIdList as $userId) {
Database::insert(
'notification_event_rel_user',
[
'event_id' => $eventId,
'user_id' => (int) $userId,
]
);
}
}
public static function getAssignedUsers(int $eventId): array
{
$tblUser = Database::get_main_table(TABLE_MAIN_USER);
$result = Database::select(
'u.id, u.username, u.firstname, u.lastname',
"notification_event_rel_user neru INNER JOIN $tblUser u ON neru.user_id = u.id",
['where' => ['neru.event_id = ?' => $eventId]]
);
$userList = [];
foreach ($result as $userInfo) {
$userList[$userInfo['id']] = api_get_person_name(
$userInfo['firstname'],
$userInfo['lastname'],
null,
null,
null,
$userInfo['username']
);
}
return $userList;
}
public static function deleteAssignedUsers(int $eventId)
{
Database::delete(
'notification_event_rel_user',
['event_id = ?' => $eventId]
);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,102 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CoreBundle\Entity\Course as CourseEntity;
use Chamilo\CoreBundle\Entity\PortfolioComment;
use Chamilo\CoreBundle\Entity\Session as SessionEntity;
class PortfolioNotifier
{
public static function notifyTeachersAndAuthor(PortfolioComment $comment)
{
$item = $comment->getItem();
$course = $item->getCourse();
$session = $item->getSession();
$messageSubject = sprintf(
get_lang('PortfolioAlertNewCommentSubject'),
$item->getTitle(true)
);
$userIdListToSend = [];
$userIdListToSend[] = $comment->getItem()->getUser()->getId();
$cidreq = api_get_cidreq_params(
$course ? $course->getCode() : '',
$session ? $session->getId() : 0
);
$commentUrl = api_get_path(WEB_CODE_PATH).'portfolio/index.php?'
.($course ? $cidreq.'&' : '')
.http_build_query(['action' => 'view', 'id' => $item->getId()])."#comment-{$comment->getId()}";
if ($course) {
$courseInfo = api_get_course_info($course->getCode());
if (1 !== (int) api_get_course_setting('email_alert_teachers_student_new_comment', $courseInfo)) {
return;
}
$courseTitle = self::getCourseTitle($course, $session);
$userIdListToSend = array_merge(
$userIdListToSend,
self::getTeacherList($course, $session)
);
$messageContent = sprintf(
get_lang('CoursePortfolioAlertNewCommentContent'),
$item->getTitle(),
$courseTitle,
$commentUrl
);
} else {
$messageContent = sprintf(
get_lang('PortfolioAlertNewCommentContent'),
$item->getTitle(),
$commentUrl
);
}
$messageContent .= '<br><br><figure>'
.'<blockquote>'.$comment->getExcerpt().'</blockquote>'
.'<figcaption>'.$comment->getAuthor()->getCompleteName().'</figcaption>'
.'</figure>';
foreach ($userIdListToSend as $userIdToSend) {
MessageManager::send_message_simple(
$userIdToSend,
$messageSubject,
$messageContent,
0,
false,
false,
[],
false
);
}
}
private static function getCourseTitle(CourseEntity $course, ?SessionEntity $session = null): string
{
if ($session) {
return "{$course->getTitle()} ({$session->getName()})";
}
return $course->getTitle();
}
private static function getTeacherList(CourseEntity $course, ?SessionEntity $session = null): array
{
if ($session) {
$teachers = SessionManager::getCoachesByCourseSession(
$session->getId(),
$course->getId()
);
return array_values($teachers);
}
$teachers = CourseManager::get_teacher_list_from_course_code($course->getCode());
return array_keys($teachers);
}
}

View File

@@ -0,0 +1,612 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Class ScheduledAnnouncement
* Requires DB change:.
*
* CREATE TABLE scheduled_announcements (id INT AUTO_INCREMENT NOT NULL, subject VARCHAR(255) NOT NULL, message LONGTEXT NOT NULL, date DATETIME DEFAULT NULL, sent TINYINT(1) NOT NULL, session_id INT NOT NULL, c_id INT DEFAULT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;
*
* Config setting:
* $_configuration['allow_scheduled_announcements'] = true;
*
* Setup linux cron file:
* main/cron/scheduled_announcement.php
*
* Requires:
* composer update
*/
class ScheduledAnnouncement extends Model
{
public $table;
public $columns = ['id', 'subject', 'message', 'date', 'sent', 'session_id'];
/**
* Constructor.
*/
public function __construct()
{
parent::__construct();
$this->table = 'scheduled_announcements';
}
/**
* @param array $where_conditions
*
* @return array
*/
public function get_all($where_conditions = [])
{
return Database::select(
'*',
$this->table,
['where' => $where_conditions, 'order' => 'subject ASC']
);
}
/**
* @return mixed
*/
public function get_count()
{
$row = Database::select(
'count(*) as count',
$this->table,
[],
'first'
);
return $row['count'];
}
/**
* Displays the title + grid.
*
* @param int $sessionId
*
* @return string
*/
public function getGrid($sessionId)
{
// action links
$action = '<div class="actions" style="margin-bottom:20px">';
$action .= Display::url(
Display::return_icon('back.png', get_lang('Back'), '', ICON_SIZE_MEDIUM),
api_get_path(WEB_CODE_PATH).'session/resume_session.php?id_session='.$sessionId
);
$action .= '<a href="'.api_get_self().'?action=add&session_id='.$sessionId.'">'.
Display::return_icon('add.png', get_lang('Add'), '', ICON_SIZE_MEDIUM).'</a>';
$action .= '<a href="scheduled_announcement.php?action=run&session_id='.$sessionId.'">'.
Display::return_icon('tuning.png', get_lang('SendManuallyPendingAnnouncements'), '', ICON_SIZE_MEDIUM).
'</a>';
$action .= '</div>';
$html = $action;
$html .= '<div id="session-table" class="table-responsive">';
$html .= Display::grid_html('programmed');
$html .= '</div>';
return $html;
}
/**
* Returns a Form validator Obj.
*
* @param int $id
* @param string $url
* @param string $action add, edit
* @param array $sessionInfo
*
* @return FormValidator form validator obj
*/
public function returnSimpleForm($id, $url, $action, $sessionInfo = [])
{
$form = new FormValidator(
'announcement',
'post',
$url
);
$form->addHidden('session_id', $sessionInfo['id']);
$form->addDateTimePicker('date', get_lang('Date'));
$useBaseProgress = api_get_configuration_value('scheduled_announcements_use_base_progress');
if ($useBaseProgress) {
$extraFieldValue = new ExtraFieldValue('scheduled_announcement');
$baseProgress = $extraFieldValue->get_values_by_handler_and_field_variable(
$id,
'use_base_progress'
);
$form->addNumeric('progress',
get_lang('Progress'),
[
'step' => 1,
'min' => 1,
'max' => 100,
'value' => $baseProgress['value'],
],
true
);
}
$form->addText('subject', get_lang('Subject'));
$form->addHtmlEditor('message', get_lang('Message'));
$extraField = new ExtraField('scheduled_announcement');
$extra = $extraField->addElements($form, $id);
$js = $extra['jquery_ready_content'];
$form->addHtml("<script> $(function() { $js }); </script> ");
$this->setTagsInForm($form);
$form->addCheckBox('sent', null, get_lang('MessageSent'));
if ('edit' === $action) {
$form->addButtonUpdate(get_lang('Modify'));
}
return $form;
}
/**
* Returns a Form validator Obj.
*
* @todo the form should be auto generated
*
* @param string $url
* @param string $action add, edit
* @param array
*
* @return FormValidator form validator obj
*/
public function returnForm($url, $action, $sessionInfo = [])
{
// Setting the form elements
$header = get_lang('Add');
if ('edit' === $action) {
$header = get_lang('Modify');
}
$form = new FormValidator(
'announcement',
'post',
$url
);
$form->addHeader($header);
if ('add' === $action) {
$form->addHtml(
Display::return_message(
nl2br(get_lang('ScheduleAnnouncementDescription')),
'normal',
false
)
);
}
$form->addHidden('session_id', $sessionInfo['id']);
$useBaseDate = false;
$startDate = $sessionInfo['access_start_date'];
$endDate = $sessionInfo['access_end_date'];
if (!empty($startDate) || !empty($endDate)) {
$useBaseDate = true;
}
$typeOptions = [
'specific_date' => get_lang('SpecificDate'),
];
if ($useBaseDate) {
$typeOptions['base_date'] = get_lang('BaseDate');
}
$useBaseProgress = api_get_configuration_value('scheduled_announcements_use_base_progress');
if ($useBaseProgress) {
$typeOptions['base_progress'] = get_lang('Progress');
}
$form->addSelect(
'type',
get_lang('Type'),
$typeOptions,
[
'onchange' => "javascript:
if (this.options[this.selectedIndex].value == 'base_date') {
document.getElementById('options').style.display = 'block';
document.getElementById('specific_date').style.display = 'none';
document.getElementById('base_progress').style.display = 'none';
} else if (this.options[this.selectedIndex].value == 'specific_date') {
document.getElementById('options').style.display = 'none';
document.getElementById('specific_date').style.display = 'block';
document.getElementById('base_progress').style.display = 'none';
} else {
document.getElementById('options').style.display = 'block';
document.getElementById('specific_date').style.display = 'none';
document.getElementById('base_progress').style.display = 'block';
}
", ]
);
$form->addHtml('<div id="specific_date">');
$form->addDateTimePicker('date', get_lang('Date'));
$form->addHtml('</div>');
$form->addHtml('<div id="base_progress" style="display:none">');
$form->addNumeric('progress',
get_lang('Progress'),
[
'step' => 1,
'min' => 1,
'max' => 100,
'value' => 100,
],
true
);
$form->addHtml('</div>');
$form->addHtml('<div id="options" style="display:none">');
$startDate = $sessionInfo['access_start_date'];
$endDate = $sessionInfo['access_end_date'];
$form->addText(
'days',
get_lang('Days'),
false
);
$form->addSelect(
'moment_type',
get_lang('AfterOrBefore'),
[
'after' => get_lang('After'),
'before' => get_lang('Before'),
]
);
if (!empty($startDate)) {
$options['start_date'] = get_lang('StartDate').' - '.$startDate;
}
if (!empty($endDate)) {
$options['end_date'] = get_lang('EndDate').' - '.$endDate;
}
if (!empty($options)) {
$form->addSelect('base_date', get_lang('BaseDate'), $options);
}
$form->addHtml('</div>');
$form->addText('subject', get_lang('Subject'));
$form->addHtmlEditor('message', get_lang('Message'));
$extraField = new ExtraField('scheduled_announcement');
$extra = $extraField->addElements($form);
$js = $extra['jquery_ready_content'];
$form->addHtml("<script> $(function() { $js }); </script> ");
$this->setTagsInForm($form);
if ('edit' === $action) {
$form->addButtonUpdate(get_lang('Modify'));
} else {
$form->addButtonCreate(get_lang('Add'));
}
return $form;
}
/**
* @param int $id
*
* @return string
*/
public function getAttachmentToString($id)
{
$file = $this->getAttachment($id);
if (!empty($file) && !empty($file['value'])) {
$url = api_get_path(WEB_UPLOAD_PATH).$file['value'];
return get_lang('Attachment').': '.Display::url(basename($file['value']), $url, ['target' => '_blank']);
}
return '';
}
/**
* @param int $id
*
* @return array
*/
public function getAttachment($id)
{
$extraFieldValue = new ExtraFieldValue('scheduled_announcement');
$attachment = $extraFieldValue->get_values_by_handler_and_field_variable($id, 'attachment');
return $attachment;
}
/**
* @param int $urlId
*
* @return int
*/
public function sendPendingMessages($urlId = 0)
{
if (!$this->allowed()) {
return 0;
}
$messagesSent = 0;
$now = api_get_utc_datetime();
$result = $this->get_all();
$extraFieldValue = new ExtraFieldValue('scheduled_announcement');
// get user extra fields list (only visible to self and filter-able)
$extraField = new ExtraField('user');
$extraFields = $extraField->get_all(['filter = ? AND visible_to_self = ?' => [1, 1]]);
foreach ($result as $result) {
if (empty($result['sent'])) {
if (!empty($result['date']) && $result['date'] < $now) {
$sessionId = $result['session_id'];
$sessionInfo = api_get_session_info($sessionId);
if (empty($sessionInfo)) {
continue;
}
$users = SessionManager::get_users_by_session(
$sessionId,
0,
false,
$urlId
);
$coachId = $sessionInfo['id_coach'];
if (empty($users) || empty($coachId)) {
continue;
}
$coachList = [];
if ($users) {
$sendToCoaches = $extraFieldValue->get_values_by_handler_and_field_variable(
$result['id'],
'send_to_coaches'
);
$courseList = SessionManager::getCoursesInSession($sessionId);
if (!empty($sendToCoaches) && !empty($sendToCoaches['value']) && 1 == $sendToCoaches['value']) {
foreach ($courseList as $courseItemId) {
$coaches = SessionManager::getCoachesByCourseSession(
$sessionId,
$courseItemId
);
$coachList = array_merge($coachList, $coaches);
}
$coachList = array_unique($coachList);
}
$useBaseProgress = api_get_configuration_value('scheduled_announcements_use_base_progress');
if ($useBaseProgress) {
$baseProgress = $extraFieldValue->get_values_by_handler_and_field_variable(
$result['id'],
'use_base_progress'
);
if (empty($baseProgress) || empty($baseProgress['value']) || $baseProgress['value'] < 1) {
$this->update(['id' => $result['id'], 'sent' => 1]);
}
} else {
$this->update(['id' => $result['id'], 'sent' => 1]);
}
$attachments = $this->getAttachmentToString($result['id']);
$subject = $result['subject'];
$courseInfo = [];
if (!empty($courseList)) {
$courseId = current($courseList);
$courseInfo = api_get_course_info_by_id($courseId);
}
$message = '';
foreach ($users as $user) {
// Take original message
$message = $result['message'];
$userInfo = api_get_user_info($user['user_id']);
$userPicture = UserManager::getUserPicture($user['user_id'], USER_IMAGE_SIZE_ORIGINAL);
$progress = '';
if (!empty($sessionInfo) && !empty($courseInfo)) {
$progress = Tracking::get_avg_student_progress(
$user['user_id'],
$courseInfo['code'],
[],
$sessionId
);
}
if ($useBaseProgress) {
$baseProgress = $extraFieldValue->get_values_by_handler_and_field_variable(
$result['id'],
'use_base_progress'
);
if (!empty($baseProgress) && !empty($baseProgress['value']) && $baseProgress['value'] >= 1) {
if ((is_numeric($progress) && $progress > $baseProgress['value']) || !is_numeric($progress)) {
continue;
} else {
$comment = json_decode($baseProgress['comment'], true);
if ($comment !== null && is_array($comment)) {
if (isset($comment['sended']) && is_array($comment['sended'])) {
$userFound = false;
foreach ($comment['sended'] as $item) {
if (isset($item['user']) && $item['user'] === $user['user_id']) {
$userFound = true;
break;
}
}
if ($userFound) {
continue;
} else {
$comment['sended'][] = ['user' => $user['user_id'], 'send_date' => time(), 'progress_user' => $progress, 'progress_mark' => $baseProgress['value']];
$newExtraFieldParams = $baseProgress;
$newExtraFieldParams['comment'] = json_encode($comment);
$extraFieldValue->save($newExtraFieldParams);
}
}
} else {
$comment['sended'][] = ['user' => $user['user_id'], 'send_date' => time(), 'progress_user' => $progress, 'progress_mark' => $baseProgress['value']];
$newExtraFieldParams = $baseProgress;
$newExtraFieldParams['comment'] = json_encode($comment);
$extraFieldValue->save($newExtraFieldParams);
}
}
}
}
if (is_numeric($progress)) {
$progress = $progress.'%';
} else {
$progress = '0%';
}
$startTime = api_get_local_time(
$sessionInfo['access_start_date'],
null,
null,
true
);
$endTime = api_get_local_time(
$sessionInfo['access_end_date'],
null,
null,
true
);
$generalCoach = '';
$generalCoachEmail = '';
if (!empty($coachId)) {
$coachInfo = api_get_user_info($coachId);
if (!empty($coachInfo)) {
$generalCoach = $coachInfo['complete_name'];
$generalCoachEmail = $coachInfo['email'];
}
}
$tags = [
'((session_name))' => $sessionInfo['name'],
'((session_start_date))' => $startTime,
'((general_coach))' => $generalCoach,
'((general_coach_email))' => $generalCoachEmail,
'((session_end_date))' => $endTime,
'((user_username))' => $userInfo['username'],
'((user_complete_name))' => $userInfo['complete_name'],
'((user_firstname))' => $userInfo['firstname'],
'((user_lastname))' => $userInfo['lastname'],
'((user_first_name))' => $userInfo['firstname'],
'((user_last_name))' => $userInfo['lastname'],
'((user_official_code))' => $userInfo['official_code'],
'((user_picture))' => $userPicture,
'((lp_progress))' => $progress,
];
if (!empty($extraFields)) {
$efv = new ExtraFieldValue('user');
foreach ($extraFields as $extraField) {
$valueExtra = $efv->get_values_by_handler_and_field_variable(
$user['user_id'],
$extraField['variable'],
true
);
$tags['(('.strtolower($extraField['variable']).'))'] = $valueExtra['value'];
}
}
$message = str_replace(array_keys($tags), $tags, $message);
$message .= $attachments;
MessageManager::send_message_simple(
$userInfo['user_id'],
$subject,
$message,
$coachId
);
}
$message = get_lang('YouAreReceivingACopyBecauseYouAreACourseCoach').'<br /><br />'.$message;
foreach ($coachList as $courseCoachId) {
MessageManager::send_message_simple(
$courseCoachId,
get_lang('YouAreReceivingACopyBecauseYouAreACourseCoach').'&nbsp;'.$subject,
$message,
$coachId
);
}
}
$messagesSent++;
}
}
}
return $messagesSent;
}
/**
* @return array
*/
public function getTags()
{
$tags = [
'((session_name))',
'((session_start_date))',
'((session_end_date))',
'((general_coach))',
'((general_coach_email))',
'((user_username))',
'((user_complete_name))',
'((user_first_name))',
'((user_last_name))',
'((user_picture))',
'((lp_progress))',
'((user_official_code))',
];
// get user extra fields list (only visible to self and filter-able)
$extraField = new ExtraField('user');
$extraFields = $extraField->get_all(['filter = ? AND visible_to_self = ?' => [1, 1]]);
if (!empty($extraFields)) {
foreach ($extraFields as $extraField) {
$tags[] = '(('.strtolower($extraField['variable']).'))';
}
}
return $tags;
}
/**
* @return bool
*/
public function allowed()
{
return api_get_configuration_value('allow_scheduled_announcements');
}
/**
* @param FormValidator $form
*/
private function setTagsInForm(&$form)
{
$form->addLabel(
get_lang('Tags'),
Display::return_message(
implode('<br />', $this->getTags()),
'normal',
false
)
);
}
}

143
main/inc/lib/SmsPlugin.php Normal file
View File

@@ -0,0 +1,143 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Class SmsPlugin.
*
* @author Julio Montoya
*/
class SmsPlugin extends Plugin
{
public const WELCOME_LOGIN_PASSWORD = 0;
public const NEW_FILE_SHARED_COURSE_BY = 1;
public const ACCOUNT_APPROVED_CONNECT = 2;
public const NEW_COURSE_BEEN_CREATED = 3;
public const NEW_USER_SUBSCRIBED_COURSE = 4;
public const NEW_COURSE_SUGGESTED_TEACHER = 5;
public const COURSE_OPENING_REQUEST_CODE_REGISTERED = 6;
public const COURSE_OPENING_REQUEST_CODE_APPROVED = 7;
public const COURSE_OPENING_REQUEST_CODE_REJECTED = 8;
public const COURSE_OPENING_REQUEST_CODE = 9;
public const BEEN_SUBSCRIBED_COURSE = 10;
public const ASSIGNMENT_BEEN_CREATED_COURSE = 11;
public const ACCOUNT_CREATED_UPDATED_LOGIN_PASSWORD = 12;
public const PASSWORD_UPDATED_LOGIN_PASSWORD = 13;
public const REQUESTED_PASSWORD_CHANGE = 14;
public const RECEIVED_NEW_PERSONAL_MESSAGES = 15;
public const NEW_USER_PENDING_APPROVAL = 16;
public const POSTED_FORUM_COURSE = 17;
public const CHECK_EMAIL_CONNECT_MORE_INFO = 18;
public const STUDENT_ANSWERED_TEST = 19;
public const STUDENT_ANSWERED_TEST_OPEN_QUESTION = 20;
public const STUDENT_ANSWERED_TEST_VOICE_QUESTION = 21;
public const ANSWER_OPEN_QUESTION_TEST_REVIEWED = 22;
public const NEW_THREAD_STARTED_FORUM = 23;
public const NEW_ANSWER_POSTED_FORUM = 24;
public const NEW_SYSTEM_ANNOUNCEMENT_ADDED = 25;
public const TEST_NEW_SYSTEM_ANNOUNCEMENT_ADDED = 26;
public const SYSTEM_ANNOUNCEMENT_UPDATE = 27;
public const TEST_SYSTEM_ANNOUNCEMENT_UPDATE = 28;
public const USER_UPLOADED_ASSIGNMENT_COURSE_STUDENT_SUBMITS_PAPER = 29;
public const USER_UPLOADED_ASSIGNMENT_CHECK_STUDENT_SUBMITS_PAPER = 30;
public const USER_UPLOADED_ASSIGNMENT_COURSE = 31;
public const USER_UPLOADED_ASSIGNMENT_CHECK = 32;
public const SUBSCRIBED_SESSION = 33;
public const SUBSCRIBED_SESSION_CSV = 34;
public const USER_SUGGESTED_BE_FRIENDS = 35;
public const USER_ANSWERED_INBOX_MESSAGE = 36;
public const BEEN_INVITED_JOIN_GROUP = 37;
public const MESSAGES_SENT_EDITED_GROUP_EDITED = 38;
public const MESSAGES_SENT_EDITED_GROUP_ADDED = 39;
public const BEEN_INVITED_COMPLETE_SURVEY_COURSE = 40;
public const REMINDER_ASSIGNMENT_COURSE_DUE = 41;
public const USER_DETAILS_MODIFIED = 42;
public const CERTIFICATE_NOTIFICATION = 43;
public $isCoursePlugin = true;
public $isMailPlugin = true;
/**
* getSmsTypeOptions (returns all SMS types).
*
* @return array SMS types
*/
public function getSmsTypeOptions()
{
return [
'MessageWelcomeXLoginXPasswordX',
'MessageXNewFileSharedCourseXByX',
'MessageXAccountApprovedConnectX',
'MessageXNewCourseXBeenCreatedX',
'MessageXNewUserXSubscribedCourseX',
'MessageXNewCourseSuggestedTeacherX',
'MessageXCourseOpeningRequestCodeXRegistered',
'MessageXCourseOpeningRequestCourseCodeXApproved',
'MessageXRequestOpenCourseCodeXReject',
'MessageXCourseOpeningRequestCourseCodeX',
'MessageXBeenSubscribedCourseX',
'MessageXAssignmentBeenCreatedCourseX',
'MessageXAccountCreatedUpdatedLoginXPasswordX',
'MessageXPasswordUpdatedLoginXPasswordX',
'MessageXRequestedPasswordChange',
'MessageXReceivedNewPersonalMessages',
'MessageXNewUserXPendingApproval',
'MessageXXPostedForumXCourseX',
'MessageXXXCheckEmailConnectMoreInfo',
'MessageXXStudentXAnsweredTestX',
'MessageXXStudentXAnsweredTestXOpenQuestion',
'MessageXXStudentXAnsweredTestXVoiceQuestion',
'MessageXXAnswerOpenQuestionTestXReviewed',
'MessageXXNewThreadXStartedForumX',
'MessageXXNewAnswerPostedXForumX',
'MessageXXNewSystemAnnouncementAdded',
'MessageXTestXNewSystemAnnouncementAdded',
'MessageXXSystemAnnouncementUpdate',
'MessageXTestXSystemAnnouncementUpdate',
'MessageXUserXUploadedAssignmentXCourseXStudentSubmitsPaper',
'MessageXUserXUploadedAssignmentXCheckXStudentSubmitsPaper',
'MessageXUserXUploadedAssignmentXCourseX',
'MessageXUserXUploadedAssignmentXCheckX',
'MessageXSubscribedSessionX',
'MessageXSubscribedSessionXCSV',
'MessageXUserXSuggestedBeFriends',
'MessageXUserXAnsweredInboxMessage',
'MessageXBeenInvitedJoinGroupX',
'MessageXMessagesSentEditedGroupXEdited',
'MessageXMessagesSentEditedGroupXAdded',
'MessageXBeenInvitedCompleteSurveyXCourseX',
'MessageXReminderAssignmentXCourseXDue',
'MessageXUserDetailsModified',
];
}
/**
* install (installs the plugin).
*/
public function install()
{
$this->addMobilePhoneNumberField();
}
/**
* addMobilePhoneNumberField (adds a mobile phone number field if it is not
* already created).
*/
private function addMobilePhoneNumberField()
{
$extraField = new ExtraField('user');
$extraFieldInfo = $extraField->get_handler_field_info_by_field_variable('mobile_phone_number');
if (empty($extraFieldInfo)) {
$extraField->save([
'field_type' => 1,
'variable' => 'mobile_phone_number',
'display_text' => $this->get_lang('mobile_phone_number'),
'default_value' => null,
'field_order' => 2,
'visible' => 1,
'changeable' => 1,
'filter' => null,
]);
}
}
}

View File

@@ -0,0 +1,46 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Class SmsPluginLibraryInterface.
*
* @author Julio Montoya
*/
interface SmsPluginLibraryInterface
{
/**
* getMobilePhoneNumberById (retrieves a user mobile phone number by user id).
*
* @param int $userId
*
* @return int User's mobile phone number
*/
public function getMobilePhoneNumberById($userId);
/**
* @param array $additionalParameters
*
* @return mixed
*/
public function send($additionalParameters);
/**
* @param array $additionalParameters
*
* @return mixed
*/
public function getSms($additionalParameters);
/**
* buildSms (builds an SMS from a template and data).
*
* @param object $plugin ClockworksmsPlugin object
* @param object $tpl Template object
* @param string $templateName Template file name
* @param string $messageKey Text key from lang file
* @param array $parameters Data to fill message variables (if any)
*
* @return object Template object with message property updated
*/
public function buildSms($plugin, $tpl, $templateName, $messageKey, $parameters = null);
}

View File

@@ -0,0 +1,89 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Sortable table which can be used for data available in an array.
*/
class SortableTableFromArray extends SortableTable
{
/**
* The array containing all data for this table.
*/
public $table_data;
public $handlePagination;
/**
* Constructor.
*
* @param array $table_data
* @param int $default_column
* @param int $default_items_per_page
* @param string $tableName
* @param string $get_total_number_function
* @param string $tableId
*/
public function __construct(
$table_data,
$default_column = 1,
$default_items_per_page = 20,
$tableName = 'tablename',
$get_total_number_function = null,
$tableId = ''
) {
parent::__construct(
$tableName,
$get_total_number_function,
null,
$default_column,
$default_items_per_page,
null,
$tableId
);
$this->table_data = $table_data;
$this->handlePagination = false;
}
/**
* Get table data to show on current page.
*
* @see SortableTable#get_table_data
*/
public function get_table_data(
$from = 1,
$per_page = null,
$column = null,
$direction = null,
$sort = true
) {
if ($sort) {
$content = TableSort::sort_table(
$this->table_data,
$this->column,
'ASC' === $this->direction ? SORT_ASC : SORT_DESC
);
} else {
$content = $this->table_data;
}
return array_slice($content, $from, $this->per_page);
}
/**
* Get total number of items.
*
* @see SortableTable#get_total_number_of_items
*/
public function get_total_number_of_items()
{
if (isset($this->total_number_of_items) && !empty($this->total_number_of_items) && $this->total_number_of_items != -1) {
return $this->total_number_of_items;
} else {
if (!empty($this->table_data)) {
return count($this->table_data);
}
return 0;
}
}
}

View File

@@ -0,0 +1,118 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Sortable table which can be used for data available in an array.
*
* Is a variation of SortableTableFromArray because we add 2 new arrays $column_show and $column_order
* $column_show is an array that lets us decide which are going to be the columns to show
* $column_order is an array that lets us decide the ordering of the columns
* i.e: $column_header=array('a','b','c','d','e'); $column_order=array(1,2,5,4,5);
* These means that the 3th column (letter "c") will be sort like the order we use in the 5th column
*/
class SortableTableFromArrayConfig extends SortableTable
{
/**
* The array containing the columns that will be show
* i.e $column_show=array('1','0','0'); we will show only the 1st column.
*/
private $column_show;
/**
* The array containing the real sort column
* $column_order=array('1''4','3','4');
* The 2nd column will be order like the 4th column.
*/
private $column_order;
private $doc_filter;
private $handlePagination = true;
/**
* Constructor.
*
* @param array $data All the information of the table
* @param int $column Default column that will be used in the sort functions
* @param int $itemsPerPage Number of items per pages that we are going to see
* @param string $tableName Name of the table
* @param array $columnShow An array with binary values: 1 = show column, 2 = don't show it
* @param array $columnOrder An array of integers that let us decide how the columns are going to be sort
* @param string $direction ASC/DESC
* @param bool $docFilter special modification to fix the document name order
*/
public function __construct(
$data,
$column = 1,
$itemsPerPage = 20,
$tableName = 'tablename',
$columnShow = [],
$columnOrder = [],
$direction = 'ASC',
$docFilter = false
) {
$this->column_show = $columnShow;
$this->column_order = $columnOrder;
$this->doc_filter = $docFilter;
// if data is empty the pagination is handled with query in database
if (empty($data)) {
$this->handlePagination = false;
}
parent::__construct(
$tableName,
null,
null,
$column,
$itemsPerPage,
$direction
);
$this->table_data = $data;
}
/**
* Get table data to show on current page.
*
* @see SortableTable#get_table_data
*/
public function get_table_data(
$from = 1,
$perPage = null,
$column = null,
$direction = null,
$sort = true
) {
$table = TableSort::sort_table_config(
$this->table_data,
$this->column,
'ASC' === $this->direction ? SORT_ASC : SORT_DESC,
$this->column_show,
$this->column_order,
SORT_REGULAR,
$this->doc_filter
);
if ($this->handlePagination) {
return array_slice($table, $from, $this->per_page);
}
return $table;
}
/**
* Get total number of items.
*
* @see SortableTable#get_total_number_of_items
*/
public function get_total_number_of_items()
{
if (!empty($this->total_number_of_items) && $this->total_number_of_items !== -1) {
return $this->total_number_of_items;
} else {
if (!empty($this->table_data)) {
return count($this->table_data);
}
return 0;
}
}
}

View File

@@ -0,0 +1,214 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CourseBundle\Entity\CItemProperty;
/**
* Class StudentFollowPage.
*/
class StudentFollowPage
{
public const VARIABLE_ACQUISITION = 'acquisition';
public const VARIABLE_INVISIBLE = 'invisible';
public static function getLpSubscription(
array $lpInfo,
int $studentId,
int $courseId,
int $sessionId = 0,
bool $showTeacherName = true
): string {
$em = Database::getManager();
if ($lpInfo['subscribe_users']) {
$itemRepo = $em->getRepository(CItemProperty::class);
$itemProperty = $itemRepo->findByUserSuscribedToItem(
'learnpath',
$lpInfo['iid'],
$studentId,
$courseId,
$sessionId
);
if (null === $itemProperty) {
$userGroups = GroupManager::getAllGroupPerUserSubscription($studentId, $courseId);
foreach ($userGroups as $groupInfo) {
$itemProperty = $itemRepo->findByGroupSuscribedToLp(
'learnpath',
$lpInfo['iid'],
$groupInfo['iid'],
$courseId,
$sessionId
);
if (null !== $itemProperty) {
break;
}
}
}
if (null === $itemProperty) {
return '-';
}
$formattedDate = api_convert_and_format_date($itemProperty->getInsertDate(), DATE_TIME_FORMAT_LONG);
if ($showTeacherName) {
$insertUser = $itemProperty->getInsertUser()->getId() !== $studentId
? $itemProperty->getInsertUser()->getCompleteName()
: '-';
return "$insertUser<br>".Display::tag('small', $formattedDate);
}
return $formattedDate;
}
$subscriptionEvent = Event::findUserSubscriptionToCourse($studentId, $courseId, $sessionId);
if (empty($subscriptionEvent)) {
return '-';
}
$formattedDate = api_convert_and_format_date($subscriptionEvent['default_date'], DATE_TIME_FORMAT_LONG);
if ($showTeacherName) {
$creator = api_get_user_entity($subscriptionEvent['default_user_id']);
return "{$creator->getCompleteName()}<br>".Display::tag('small', $formattedDate);
}
return $formattedDate;
}
public static function getLpAcquisition(
array $lpInfo,
int $studentId,
int $courseId,
int $sessionId = 0,
bool $allowEdit = false
): string {
$lpView = learnpath::findLastView($lpInfo['iid'], $studentId, $courseId, $sessionId, true);
$extraField = new ExtraField('lp_view');
$field = $extraField->get_handler_field_info_by_field_variable(self::VARIABLE_ACQUISITION);
$extraFieldValue = new ExtraFieldValue('lp_view');
$value = $extraFieldValue->get_values_by_handler_and_field_variable($lpView['iid'], self::VARIABLE_ACQUISITION);
$return = '';
if (empty($value)) {
$return .= '-';
} else {
$optionSelected = array_filter(
$field['options'],
function (array $option) use ($value) {
return $option['option_value'] == $value['value'];
}
);
if (empty($optionSelected)) {
$return .= '-';
} else {
$optionSelected = current($optionSelected);
$valueComment = json_decode($value['comment'], true);
$register = api_get_user_entity($valueComment['user']);
$return .= ExtraFieldOption::translateDisplayName($optionSelected['display_text']).'<br>'
.Display::tag('small', $register->getCompleteName()).'<br>'
.Display::tag(
'small',
api_convert_and_format_date($valueComment['datetime'], DATE_TIME_FORMAT_LONG)
).'<br>';
}
}
$editUrl = api_get_path(WEB_AJAX_PATH).'student_follow_page.ajax.php?'
.http_build_query(['lp_view' => $lpView['iid'], 'a' => 'form_adquisition']);
if ($allowEdit) {
$return .= Display::url(
Display::return_icon('edit.png', get_lang('Edit'), [], ICON_SIZE_TINY),
$editUrl,
['class' => 'ajax', 'data-title' => strip_tags($lpInfo['lp_name'])]
);
}
return '<div id="acquisition-'.$lpView['iid'].'">'.$return.'</div>';
}
public static function getLpVisibleScript()
{
$url = api_get_path(WEB_AJAX_PATH).'student_follow_page.ajax.php?'.http_build_query(['a' => 'views_invisible']);
return "<script>$(function () {
var chkbView = $('[name=\"chkb_view[]\"]');
function doRequest(element, state) {
element.prop('disabled', true);
var views = $.makeArray(element).map(function (input) { return input.value; });
return $.post('$url', { 'chkb_view[]': views, 'state': state }, function () { element.prop('disabled', false); });
}
$('[name=\"chkb_category[]\"]').on('change', function () {
var checked = this.checked;
var chkbs = $(this).parents('table').find('td :checkbox').each(function () { this.checked = checked; });
doRequest(chkbs, checked);
}).prop('checked', true);
chkbView.on('change', function () {
doRequest($(this), this.checked);
$(this).parents('table').find('th :checkbox').prop(
'checked',
$.makeArray($(this).parents('table').find('td :checkbox'))
.map(function (input) { return input.checked; })
.reduce(function (acc, cur) { return acc && cur; })
);
}).each(function () {
if (!this.checked) {
$(this).parents('table').find('th :checkbox').prop('checked', false);
}
});
});</script>";
}
public static function getLpVisibleField(array $lpInfo, int $studentId, int $courseId, int $sessionId = 0)
{
$attrs = [];
$isVisible = self::isViewVisible($lpInfo['iid'], $studentId, $courseId, $sessionId);
if (!$isVisible) {
$attrs['checked'] = 'checked';
}
return Display::input(
'checkbox',
'chkb_view[]',
implode('_', [$lpInfo['iid'], $studentId, $courseId, $sessionId]),
$attrs
);
}
public static function isViewVisible(int $lpId, int $studentId, int $courseId, int $sessionId): bool
{
$lpView = learnpath::findLastView($lpId, $studentId, $courseId, $sessionId);
if (empty($lpView)) {
return true;
}
$extraFieldValue = new ExtraFieldValue('lp_view');
$value = $extraFieldValue->get_values_by_handler_and_field_variable($lpView['iid'], self::VARIABLE_INVISIBLE);
return empty($value) || empty($value['value']);
}
}

View File

@@ -0,0 +1,111 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Library for generate a teacher time report.
*
* @author Angel Fernando Quiroz Campos <angel.quiroz@beeznest.com>
*/
class TeacherTimeReport
{
/**
* The report data.
*
* @var array
*/
public $data = [];
/**
* Callback for compare sessions names.
*
* @param array $dataA The data A
* @param array $dataB The data B
*
* @return int returns -1 if dataA is less than dataB, 1 if dataA is greater than dataB, and 0 if they are equal
*/
public function compareSessions($dataA, $dataB)
{
return strnatcmp($dataA['session']['name'], $dataB['session']['name']);
}
/**
* Callback for compare courses names.
*
* @param array $dataA The datab A
* @param array $dataB The data B
*
* @return int returns -1 if dataA is less than dataB, 1 if dataA is greater than dataB, and 0 if they are equal
*/
public function compareCourses($dataA, $dataB)
{
return strnatcmp($dataA['course']['name'], $dataB['course']['name']);
}
/**
* Callback for compare coaches names.
*
* @param array $dataA The datab A
* @param array $dataB The data B
*
* @return int returns -1 if dataA is less than dataB, 1 if dataA is greater than dataB, and 0 if they are equal
*/
public function compareCoaches($dataA, $dataB)
{
return strnatcmp($dataA['coach']['complete_name'], $dataB['coach']['complete_name']);
}
/**
* Sort the report data.
*
* @param bool $withFilter Whether sort by sessions and courses
*/
public function sortData($withFilter = false)
{
if ($withFilter) {
uasort($this->data, [$this, 'compareSessions']);
uasort($this->data, [$this, 'compareCourses']);
}
uasort($this->data, [$this, 'compareCoaches']);
}
/**
* @param bool|false $withFilter
*
* @return array
*/
public function prepareDataToExport($withFilter = false)
{
$dataToExport = [];
if ($withFilter) {
$dataToExport[] = [
get_lang('Session'),
get_lang('Course'),
get_lang('Coach'),
get_lang('TotalTime'),
];
} else {
$dataToExport[] = [
get_lang('Coach'),
get_lang('TotalTime'),
];
}
foreach ($this->data as $row) {
$data = [];
if ($withFilter) {
$data[] = $row['session']['name'];
$data[] = $row['course']['name'];
}
$data[] = $row['coach']['complete_name'];
$data[] = $row['total_time'];
$dataToExport[] = $data;
}
return $dataToExport;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,121 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Class UnserializeApi.
*/
class UnserializeApi
{
/**
* Unserialize content using Brummann\Polyfill\Unserialize.
*
* @param string $type
* @param string $serialized
*
* @return mixed
*/
public static function unserialize($type, $serialized, $ignoreErrors = false)
{
$allowedClasses = [];
switch ($type) {
case 'career':
case 'sequence_graph':
$allowedClasses = [
\Fhaculty\Graph\Graph::class,
\Fhaculty\Graph\Set\VerticesMap::class,
\Fhaculty\Graph\Set\Vertices::class,
\Fhaculty\Graph\Set\Edges::class,
\Fhaculty\Graph\Vertex::class,
\Fhaculty\Graph\Edge\Base::class,
\Fhaculty\Graph\Edge\Directed::class,
\Fhaculty\Graph\Edge\Undirected::class,
];
break;
case 'course':
$allowedClasses = [
\Chamilo\CourseBundle\Component\CourseCopy\Course::class,
\Chamilo\CourseBundle\Component\CourseCopy\Resources\Announcement::class,
\Chamilo\CourseBundle\Component\CourseCopy\Resources\Asset::class,
\Chamilo\CourseBundle\Component\CourseCopy\Resources\Attendance::class,
\Chamilo\CourseBundle\Component\CourseCopy\Resources\CalendarEvent::class,
\Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseCopyLearnpath::class,
\Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseCopyTestCategory::class,
\Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseDescription::class,
\Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseSession::class,
\Chamilo\CourseBundle\Component\CourseCopy\Resources\Document::class,
\Chamilo\CourseBundle\Component\CourseCopy\Resources\Forum::class,
\Chamilo\CourseBundle\Component\CourseCopy\Resources\ForumCategory::class,
\Chamilo\CourseBundle\Component\CourseCopy\Resources\ForumPost::class,
\Chamilo\CourseBundle\Component\CourseCopy\Resources\ForumTopic::class,
\Chamilo\CourseBundle\Component\CourseCopy\Resources\Glossary::class,
\Chamilo\CourseBundle\Component\CourseCopy\Resources\GradeBookBackup::class,
\Chamilo\CourseBundle\Component\CourseCopy\Resources\LearnPathCategory::class,
\Chamilo\CourseBundle\Component\CourseCopy\Resources\Link::class,
\Chamilo\CourseBundle\Component\CourseCopy\Resources\LinkCategory::class,
\Chamilo\CourseBundle\Component\CourseCopy\Resources\Quiz::class,
\Chamilo\CourseBundle\Component\CourseCopy\Resources\QuizQuestion::class,
\Chamilo\CourseBundle\Component\CourseCopy\Resources\QuizQuestionOption::class,
\Chamilo\CourseBundle\Component\CourseCopy\Resources\ScormDocument::class,
\Chamilo\CourseBundle\Component\CourseCopy\Resources\Survey::class,
\Chamilo\CourseBundle\Component\CourseCopy\Resources\SurveyInvitation::class,
\Chamilo\CourseBundle\Component\CourseCopy\Resources\SurveyQuestion::class,
\Chamilo\CourseBundle\Component\CourseCopy\Resources\Thematic::class,
\Chamilo\CourseBundle\Component\CourseCopy\Resources\ToolIntro::class,
\Chamilo\CourseBundle\Component\CourseCopy\Resources\Wiki::class,
\Chamilo\CourseBundle\Component\CourseCopy\Resources\Work::class,
\Chamilo\CourseBundle\Component\CourseCopy\Resources\XapiTool::class,
\Chamilo\CourseBundle\Entity\CLpCategory::class,
stdClass::class,
Category::class,
AttendanceLink::class,
DropboxLink::class,
Evaluation::class,
ExerciseLink::class,
ForumThreadLink::class,
LearnpathLink::class,
LinkFactory::class,
Result::class,
StudentPublicationLink::class,
SurveyLink::class,
];
// no break
case 'lp':
$allowedClasses = array_merge(
$allowedClasses,
[
learnpath::class,
learnpathItem::class,
aicc::class,
aiccBlock::class,
aiccItem::class,
aiccObjective::class,
aiccResource::class,
scorm::class,
scormItem::class,
scormMetadata::class,
scormOrganization::class,
scormResource::class,
Link::class,
LpItem::class,
]
);
break;
case 'not_allowed_classes':
default:
$allowedClasses = false;
}
if ($ignoreErrors) {
return @unserialize(
$serialized,
['allowed_classes' => $allowedClasses]
);
}
return unserialize(
$serialized,
['allowed_classes' => $allowedClasses]
);
}
}

View File

@@ -0,0 +1,96 @@
<?php
/* For licensing terms, see /license.txt */
/**
* VideoChat class.
*
* This class provides methods for video chat management.
*
* @author Angel Fernando Quiroz Campos <angel.quiroz@beeznest.com>
*/
class VideoChat
{
/**
* Get the video chat info by its users.
*
* @param int $user1 User id
* @param int $user2 Other user id
*
* @return array The video chat info. Otherwise return false
*/
public static function getChatRoomByUsers($user1, $user2)
{
$user1 = (int) $user1;
$user2 = (int) $user2;
if (empty($user1) || empty($user2)) {
return false;
}
return Database::select(
'*',
Database::get_main_table(TABLE_MAIN_CHAT_VIDEO),
[
'where' => [
'(from_user = ? AND to_user = ?)' => [$user1, $user2],
'OR (from_user = ? AND to_user = ?)' => [$user2, $user1],
],
],
'first'
);
}
/**
* Create a video chat.
*
* @param int $fromUser The sender user
* @param int $toUser The receiver user
*
* @return int The created video chat id. Otherwise return false
*/
public static function createRoom($fromUser, $toUser)
{
$fromUserInfo = api_get_user_info($fromUser);
$toUserInfo = api_get_user_info($toUser);
$chatName = vsprintf(
get_lang('VideoChatBetweenUserXAndUserY'),
[$fromUserInfo['firstname'], $toUserInfo['firstname']]
);
return Database::insert(
Database::get_main_table(TABLE_MAIN_CHAT_VIDEO),
[
'from_user' => $fromUser,
'to_user' => $toUser,
'room_name' => $chatName,
'datetime' => api_get_utc_datetime(),
]
);
}
/**
* Check if the video chat exists by its room name.
*
* @param string $name The video chat name
*
* @return bool
*/
public static function nameExists($name)
{
$resultData = Database::select(
'COUNT(1) AS count',
Database::get_main_table(TABLE_MAIN_CHAT_VIDEO),
[
'where' => ['room_name = ?' => $name],
],
'first'
);
if ($resultData !== false) {
return $resultData['count'] > 0;
}
return false;
}
}

View File

@@ -0,0 +1,67 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Definition of the Accessurleditcoursestourl class.
*/
/**
* Access_url_edit_courses_to_url class
* Contains several functions dealing with displaying,
* editing,... of a Access_url_edit_courses_to_url_functions.
*
* @version 1.0
*
* @author Toon Keppens <toon@vi-host.net>
* @author Julio Montoya - Cleaning code
* @author Ricardo Rodriguez - Separated the function and code
*/
class Accessurleditcoursestourl
{
/**
* Search for a list of available courses by title or code, based on
* a given string.
*
* @param string String to search for
* @param int Deprecated param
*
* @return xajaxResponse A formatted, xajax answer block
* @assert () === false
*/
public function search_courses($needle, $id)
{
$tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
$xajax_response = new xajaxResponse();
$return = '';
if (!empty($needle)) {
// xajax send utf8 datas... datas in db can be non-utf8 datas
$charset = api_get_system_encoding();
$needle = api_convert_encoding($needle, $charset, 'utf-8');
$needle = Database::escape_string($needle);
// search courses where username or firstname or lastname begins likes $needle
$sql = 'SELECT id, code, title FROM '.$tbl_course.' u '.
' WHERE (title LIKE "'.$needle.'%" '.
' OR code LIKE "'.$needle.'%" '.
' ) '.
' ORDER BY title, code '.
' LIMIT 11';
$rs = Database::query($sql);
$i = 0;
while ($course = Database::fetch_array($rs)) {
$i++;
if ($i <= 10) {
$return .= '<a href="javascript: void(0);" onclick="javascript: add_course_to_url('.addslashes($course['id']).',\''.addslashes($course['title']).' ('.addslashes($course['code']).')'.'\')">'.$course['title'].' ('.$course['code'].')</a><br />';
} else {
$return .= '...<br />';
}
}
}
$xajax_response->addAssign(
'ajax_list_courses',
'innerHTML',
api_utf8_encode($return)
);
return $xajax_response;
}
}

View File

@@ -0,0 +1,65 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Definition of the Accessurleditsessiontourl class.
*/
require_once 'xajax/xajax.inc.php';
/**
* Accessurleditsessiontourl class
* Contains several functions dealing with displaying,
* editing,... of a Access_url_edit_session_to_url_functions.
*
* @version 1.0
*
* @author Toon Keppens <toon@vi-host.net>
* @author Julio Montoya - Cleaning code
* @author Ricardo Rodriguez - Separated the function and code
*/
class Accessurleditsessionstourl
{
/**
* Search sessions by name, based on a search string.
*
* @param string Search string
* @param int Deprecated param
*
* @return string Xajax response block
* @assert () === false
*/
public function search_sessions($needle, $id)
{
$tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
$xajax_response = new xajaxResponse();
$return = '';
if (!empty($needle)) {
// xajax send utf8 datas... datas in db can be non-utf8 datas
$charset = api_get_system_encoding();
$needle = api_convert_encoding($needle, $charset, 'utf-8');
$needle = Database::escape_string($needle);
// search sessiones where username or firstname or lastname begins likes $needle
$sql = 'SELECT id, name FROM '.$tbl_session.' u
WHERE (name LIKE "'.$needle.'%")
ORDER BY name, id
LIMIT 11';
$rs = Database::query($sql);
$i = 0;
while ($session = Database::fetch_array($rs)) {
$i++;
if ($i <= 10) {
$return .= '<a href="#" onclick="add_user_to_url(\''.addslashes($session['id']).'\',\''.addslashes($session['name']).' ('.addslashes($session['id']).')'.'\')">'.$session['name'].' </a><br />';
} else {
$return .= '...<br />';
}
}
}
$xajax_response->addAssign(
'ajax_list_courses',
'innerHTML',
api_utf8_encode($return)
);
return $xajax_response;
}
}

View File

@@ -0,0 +1,65 @@
<?php
/* For licensing terms, see /license.txt */
/**
* AccessUrlEditUsersToUrl class definition
* Contains several functions dealing with displaying,
* editing,... of a Access_url_edit_users_to_url_functions.
*
* @version 1.0
*
* @author Toon Keppens <toon@vi-host.net>
* @author Julio Montoya - Cleaning code
* @author Ricardo Rodriguez - Separated the function and code
*/
class AccessUrlEditUsersToUrl
{
/**
* Search users by username, firstname or lastname, based on the given
* search string.
*
* @param string Search string
* @param int Deprecated param
*
* @return xajaxResponse Xajax response block
* @assert () === false
*/
public static function search_users($needle, $id)
{
$tbl_user = Database::get_main_table(TABLE_MAIN_USER);
$xajax_response = new xajaxResponse();
$return = '';
if (!empty($needle)) {
// xajax send utf8 datas... datas in db can be non-utf8 datas
$charset = api_get_system_encoding();
$needle = api_convert_encoding($needle, $charset, 'utf-8');
$needle = Database::escape_string($needle);
// search users where username or firstname or lastname begins likes $needle
$order_clause = api_sort_by_first_name() ? ' ORDER BY firstname, lastname, username' : ' ORDER BY lastname, firstname, username';
$sql = 'SELECT u.user_id, username, lastname, firstname FROM '.$tbl_user.' u '.
' WHERE (username LIKE "'.$needle.'%" '.
' OR firstname LIKE "'.$needle.'%" '.
' OR lastname LIKE "'.$needle.'%") '.
$order_clause.
' LIMIT 11';
$rs = Database::query($sql);
$i = 0;
while ($user = Database::fetch_array($rs)) {
$i++;
if ($i <= 10) {
$return .= '<a href="javascript: void(0);" onclick="javascript: add_user_to_url(\''.addslashes($user['user_id']).'\',\''.api_get_person_name(addslashes($user['firstname']), addslashes($user['lastname'])).' ('.addslashes($user['username']).')'.'\')">'.api_get_person_name($user['firstname'], $user['lastname']).' ('.$user['username'].')</a><br />';
} else {
$return .= '...<br />';
}
}
}
$xajax_response->addAssign(
'ajax_list_users',
'innerHTML',
api_utf8_encode($return)
);
return $xajax_response;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,132 @@
<?php
/* For licensing terms, see /license.txt */
use ChamiloSession as Session;
/**
* Class AddCourseToSession.
*/
class AddCourseToSession
{
/**
* Searches a course, given a search string and a type of search box.
*
* @param string $needle Search string
* @param string $type Type of search box ('single' or anything else)
* @param int $id_session
*
* @return xajaxResponse XajaxResponse
* @assert ('abc', 'single') !== null
* @assert ('abc', 'multiple') !== null
*/
public static function search_courses($needle, $type, $id_session)
{
$tbl_session_rel_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
// Session value set in file add_courses_to_session.php
$id_session = (int) $id_session;
$tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
$course_title = null;
$xajax_response = new xajaxResponse();
$return = '';
if (!empty($needle) && !empty($type)) {
// xajax send utf8 datas... datas in db can be non-utf8 datas
$charset = api_get_system_encoding();
$needle = api_convert_encoding($needle, $charset, 'utf-8');
$needle = Database::escape_string($needle);
$cond_course_code = '';
if (!empty($id_session)) {
$id_session = (int) $id_session;
// check course_code from session_rel_course table
$sql = 'SELECT c_id FROM '.$tbl_session_rel_course.'
WHERE session_id = '.$id_session;
$res = Database::query($sql);
$course_codes = '';
if (Database::num_rows($res) > 0) {
while ($row = Database::fetch_row($res)) {
$course_codes .= '\''.$row[0].'\',';
}
$course_codes = substr($course_codes, 0, (strlen($course_codes) - 1));
$cond_course_code = ' AND course.id NOT IN('.$course_codes.') ';
}
}
if ('single' == $type) {
// search users where username or firstname or lastname begins likes $needle
$sql = 'SELECT
course.id,
course.visual_code,
course.title,
session_rel_course.session_id
FROM '.$tbl_course.' course
LEFT JOIN '.$tbl_session_rel_course.' session_rel_course
ON course.id = session_rel_course.c_id
AND session_rel_course.session_id = '.intval($id_session).'
WHERE
course.visual_code LIKE "'.$needle.'%" OR
course.title LIKE "'.$needle.'%"';
} else {
$sql = 'SELECT course.id, course.visual_code, course.title
FROM '.$tbl_course.' course
WHERE
course.visual_code LIKE "'.$needle.'%" '.$cond_course_code.'
ORDER BY course.code ';
}
if (api_is_multiple_url_enabled()) {
$tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
$access_url_id = api_get_current_access_url_id();
if (-1 != $access_url_id) {
if ('single' == $type) {
$sql = 'SELECT
course.id,
course.visual_code,
course.title,
session_rel_course.session_id
FROM '.$tbl_course.' course
LEFT JOIN '.$tbl_session_rel_course.' session_rel_course
ON course.id = session_rel_course.c_id
AND session_rel_course.session_id = '.intval($id_session).'
INNER JOIN '.$tbl_course_rel_access_url.' url_course
ON (url_course.c_id = course.id)
WHERE
access_url_id = '.$access_url_id.' AND
(course.visual_code LIKE "'.$needle.'%" OR
course.title LIKE "'.$needle.'%" )';
} else {
$sql = 'SELECT course.id, course.visual_code, course.title
FROM '.$tbl_course.' course, '.$tbl_course_rel_access_url.' url_course
WHERE
url_course.c_id = course.id AND
access_url_id = '.$access_url_id.' AND
course.visual_code LIKE "'.$needle.'%" '.$cond_course_code.'
ORDER BY course.code ';
}
}
}
$rs = Database::query($sql);
$course_list = [];
if ('single' == $type) {
while ($course = Database::fetch_array($rs)) {
$course_list[] = $course['id'];
$course_title = str_replace("'", "\'", $course_title);
$return .= '<a href="javascript: void(0);" onclick="javascript: add_course_to_session(\''.$course['id'].'\',\''.$course_title.' ('.$course['visual_code'].')'.'\')">'.$course['title'].' ('.$course['visual_code'].')</a><br />';
}
$xajax_response->addAssign('ajax_list_courses_single', 'innerHTML', api_utf8_encode($return));
} else {
$return .= '<select id="origin" name="NoSessionCoursesList[]" multiple="multiple" size="20" style="width:340px;">';
while ($course = Database::fetch_array($rs)) {
$course_list[] = $course['id'];
$course_title = str_replace("'", "\'", $course_title);
$return .= '<option value="'.$course['id'].'" title="'.htmlspecialchars($course['title'].' ('.$course['visual_code'].')', ENT_QUOTES).'">'.$course['title'].' ('.$course['visual_code'].')</option>';
}
$return .= '</select>';
$xajax_response->addAssign('ajax_list_courses_multiple', 'innerHTML', api_utf8_encode($return));
}
}
Session::write('course_list', $course_list);
return $xajax_response;
}
}

5386
main/inc/lib/agenda.lib.php Normal file

File diff suppressed because it is too large Load Diff

10701
main/inc/lib/api.lib.php Normal file

File diff suppressed because it is too large Load Diff

106
main/inc/lib/app_view.php Normal file
View File

@@ -0,0 +1,106 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Class View.
*
* @deprecated use Template class
*/
class View
{
private $data;
private $template;
private $layout;
private $tool_path;
/**
* Constructor, init tool path for rendering.
*
* @deprecated
*
* @param string $toolname tool name (optional)
* @param string $template_path
*/
public function __construct($toolname = '', $template_path = null)
{
if (!empty($toolname)) {
if (isset($template_path)) {
$path = $template_path.$toolname.'/';
} else {
$path = api_get_path(SYS_CODE_PATH).$toolname.'/';
}
if (is_dir($path)) {
$this->tool_path = $path;
} else {
throw new Exception('View::__construct() $path directory does not exist '.$path);
}
}
}
/**
* Set data sent from a controller.
*
* @param array data
*/
public function set_data($data)
{
if (!is_array($data)) {
throw new Exception('View::set_data() $data must to be an array, you have sent a'.gettype($data));
}
$this->data = $data;
}
/**
* Set layout view sent from a controller.
*
* @param string $layout view
*/
public function set_layout($layout)
{
$this->layout = $layout;
}
/**
* Set template view sent from a controller.
*
* @param string $template view
*/
public function set_template($template)
{
$this->template = $template;
}
/**
* Render data to the template and layout views.
*/
public function render()
{
$content = $this->render_template();
$target = $this->tool_path.$this->layout.'.php';
if (file_exists($target)) {
require_once $target;
} else {
throw new Exception('View::render() invalid file path '.$target);
}
}
/**
* It's used into render method for rendering data in the template and layout views.
*
* @return string Rendered template (as HTML, most of the time)
*/
private function render_template()
{
$target = $this->tool_path.$this->template.'.php';
if (file_exists($target)) {
ob_start();
@extract($this->data, EXTR_OVERWRITE); //pass the $this->data array into local scope
require_once $target;
$content = ob_get_clean();
return $content;
} else {
throw new Exception('View::render_template() invalid file path '.$target);
}
}
}

152
main/inc/lib/array.lib.php Normal file
View File

@@ -0,0 +1,152 @@
<?php
/* For licensing terms, see /license.txt */
/**
* This is the array library for Chamilo.
* Include/require it in your code to use its functionality.
*/
/**
* Removes duplicate values from a dimensional array.
*
* @param array $array dimensional array
*
* @return array an array with unique values
*/
function array_unique_dimensional($array)
{
if (!is_array($array)) {
return $array;
}
foreach ($array as &$myvalue) {
$myvalue = serialize($myvalue);
}
$array = array_unique($array);
foreach ($array as &$myvalue) {
$myvalue = UnserializeApi::unserialize('not_allowed_clases', $myvalue);
}
return $array;
}
/**
* Sort multidimensional arrays.
*
* @param array unsorted multidimensional array
* @param string key to be sorted
*
* @return array result array
*
* @author found in http://php.net/manual/en/function.sort.php
*/
function msort($array, $id = 'id', $order = 'desc')
{
if (empty($array)) {
return $array;
}
$temp_array = [];
while (count($array) > 0) {
$lowest_id = 0;
$index = 0;
foreach ($array as $item) {
if ('desc' == $order) {
if (strip_tags($item[$id]) < strip_tags($array[$lowest_id][$id])) {
$lowest_id = $index;
}
} else {
if (isset($item[$id]) && strip_tags($item[$id]) > strip_tags($array[$lowest_id][$id])) {
$lowest_id = $index;
}
}
$index++;
}
$temp_array[] = $array[$lowest_id];
$array = array_merge(
array_slice($array, 0, $lowest_id),
array_slice($array, $lowest_id + 1)
);
}
return $temp_array;
}
/**
* @param $array
*
* @return mixed
*/
function utf8_sort($array)
{
$old_locale = setlocale(LC_ALL, 0);
$code = api_get_language_isocode();
$locale_list = [$code.'.utf8', 'en.utf8', 'en_US.utf8', 'en_GB.utf8'];
$try_sort = false;
foreach ($locale_list as $locale) {
$my_local = setlocale(LC_COLLATE, $locale);
if ($my_local) {
$try_sort = true;
break;
}
}
if ($try_sort) {
uasort($array, 'strcoll');
}
setlocale(LC_COLLATE, $old_locale);
return $array;
}
/**
* @param array $array
* @param string $separator
*
* @return string
*/
function array_to_string($array, $separator = ',')
{
if (empty($array)) {
return '';
}
return implode($separator.' ', $array);
}
/**
* @return array
*/
function array_flatten(array $array)
{
$flatten = [];
array_walk_recursive(
$array,
function ($value) use (&$flatten) {
$flatten[] = $value;
}
);
return $flatten;
}
/**
* Shuffles an array keeping the associations.
*
* @param $array
*
* @return bool
*/
function shuffle_assoc(&$array)
{
$keys = array_keys($array);
shuffle($keys);
$new = [];
foreach ($keys as $key) {
$new[$key] = $array[$key];
}
$array = $new;
return true;
}

File diff suppressed because it is too large Load Diff

399
main/inc/lib/auth.lib.php Normal file
View File

@@ -0,0 +1,399 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Class Auth
* Auth can be used to instantiate objects or as a library to manage courses
* This file contains a class used like library provides functions for auth tool.
* It's also used like model to courses_controller (MVC pattern).
*
* @author Christian Fasanando <christian1827@gmail.com>
*/
class Auth
{
/**
* Constructor.
*/
public function __construct()
{
}
/**
* This function get all the courses in the particular user category.
*
* @param bool $hidePrivate
*
* @return array
*/
public function getCoursesInCategory($hidePrivate = true)
{
$user_id = api_get_user_id();
$TABLECOURS = Database::get_main_table(TABLE_MAIN_COURSE);
$TABLECOURSUSER = Database::get_main_table(TABLE_MAIN_COURSE_USER);
$avoidCoursesCondition = CoursesAndSessionsCatalog::getAvoidCourseCondition();
$showCoursesCondition = CoursesAndSessionsCatalog::getCoursesToShowInCatalogueCondition();
$visibilityCondition = CourseManager::getCourseVisibilitySQLCondition('course', true, $hidePrivate);
$sql = "SELECT
course.id as real_id,
course.code, course.visual_code, course.subscribe subscr, course.unsubscribe unsubscr,
course.title title, course.tutor_name tutor, course.directory, course_rel_user.status status,
course_rel_user.sort sort, course_rel_user.user_course_cat user_course_cat
FROM $TABLECOURS course,
$TABLECOURSUSER course_rel_user
WHERE
course.id = course_rel_user.c_id AND
course_rel_user.user_id = '".$user_id."' AND
course_rel_user.relation_type <> ".COURSE_RELATION_TYPE_RRHH."
$avoidCoursesCondition
$showCoursesCondition
$visibilityCondition
ORDER BY course_rel_user.user_course_cat, course_rel_user.sort ASC";
$result = Database::query($sql);
$data = [];
while ($course = Database::fetch_array($result)) {
$data[$course['user_course_cat']][] = $course;
}
return $data;
}
/**
* stores the changes in a course category
* (moving a course to a different course category).
*
* @param int $courseId
* @param int Category id
*
* @return bool True if it success
*/
public function updateCourseCategory($courseId, $newcategory)
{
$courseId = (int) $courseId;
$newcategory = (int) $newcategory;
$current_user = api_get_user_id();
$table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
$max_sort_value = api_max_sort_value($newcategory, $current_user);
$sql = "UPDATE $table SET
user_course_cat='".$newcategory."',
sort='".($max_sort_value + 1)."'
WHERE
c_id ='".$courseId."' AND
user_id='".$current_user."' AND
relation_type<>".COURSE_RELATION_TYPE_RRHH;
$resultQuery = Database::query($sql);
$result = false;
if (Database::affected_rows($resultQuery)) {
$result = true;
}
return $result;
}
/**
* moves the course one place up or down.
*
* @param string Direction (up/down)
* @param string Course code
* @param int Category id
*
* @return bool True if it success
*/
public function move_course($direction, $course2move, $category)
{
$table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
$current_user_id = api_get_user_id();
$all_user_courses = CourseManager::getCoursesByUserCourseCategory($current_user_id);
// we need only the courses of the category we are moving in
$user_courses = [];
foreach ($all_user_courses as $key => $course) {
if ($course['user_course_category'] == $category) {
$user_courses[] = $course;
}
}
$target_course = [];
foreach ($user_courses as $count => $course) {
if ($course2move == $course['code']) {
// source_course is the course where we clicked the up or down icon
$source_course = $course;
// target_course is the course before/after the source_course (depending on the up/down icon)
if ('up' == $direction) {
$target_course = $user_courses[$count - 1];
} else {
$target_course = $user_courses[$count + 1];
}
break;
}
}
$result = false;
if (count($target_course) > 0 && count($source_course) > 0) {
$courseInfo = api_get_course_info($source_course['code']);
$courseId = $courseInfo['real_id'];
$targetCourseInfo = api_get_course_info($target_course['code']);
$targetCourseId = $targetCourseInfo['real_id'];
$sql = "UPDATE $table
SET sort='".$target_course['sort']."'
WHERE
c_id = '".$courseId."' AND
user_id = '".$current_user_id."' AND
relation_type<>".COURSE_RELATION_TYPE_RRHH;
$result1 = Database::query($sql);
$sql = "UPDATE $table SET sort='".$source_course['sort']."'
WHERE
c_id ='".$targetCourseId."' AND
user_id='".$current_user_id."' AND
relation_type<>".COURSE_RELATION_TYPE_RRHH;
$result2 = Database::query($sql);
if (Database::affected_rows($result1) && Database::affected_rows($result2)) {
$result = true;
}
}
return $result;
}
/**
* Moves the course one place up or down.
*
* @param string $direction Direction up/down
* @param string $category2move Category id
*
* @return bool True If it success
*/
public function move_category($direction, $category2move)
{
$userId = api_get_user_id();
$userCategories = CourseManager::get_user_course_categories($userId);
$categories = array_values($userCategories);
$previous = null;
$target_category = [];
foreach ($categories as $key => $category) {
$category_id = $category['id'];
if ($category2move == $category_id) {
// source_course is the course where we clicked the up or down icon
$source_category = $userCategories[$category2move];
// target_course is the course before/after the source_course (depending on the up/down icon)
if ('up' == $direction) {
if (isset($categories[$key - 1])) {
$target_category = $userCategories[$categories[$key - 1]['id']];
}
} else {
if (isset($categories[$key + 1])) {
$target_category = $userCategories[$categories[$key + 1]['id']];
}
}
}
}
$result = false;
if (count($target_category) > 0 && count($source_category) > 0) {
$table = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
$sql = "UPDATE $table SET
sort = '".Database::escape_string($target_category['sort'])."'
WHERE id='".intval($source_category['id'])."' AND user_id='".$userId."'";
$resultFirst = Database::query($sql);
$sql = "UPDATE $table SET
sort = '".Database::escape_string($source_category['sort'])."'
WHERE id='".intval($target_category['id'])."' AND user_id='".$userId."'";
$resultSecond = Database::query($sql);
if (Database::affected_rows($resultFirst) && Database::affected_rows($resultSecond)) {
$result = true;
}
}
return $result;
}
/**
* Updates the user course category in the chamilo_user database.
*
* @param string Category title
* @param int Category id
*
* @return bool True if it success
*/
public function store_edit_course_category($title, $category_id)
{
$title = Database::escape_string($title);
$category_id = (int) $category_id;
$result = false;
$table = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
$sql = "UPDATE $table
SET title='".api_htmlentities($title, ENT_QUOTES, api_get_system_encoding())."'
WHERE id='".$category_id."'";
$resultQuery = Database::query($sql);
if (Database::affected_rows($resultQuery)) {
$result = true;
}
return $result;
}
/**
* deletes a course category and moves all the courses that were in this category to main category.
*
* @param int Category id
*
* @return bool True if it success
*/
public function delete_course_category($category_id)
{
$current_user_id = api_get_user_id();
$tucc = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
$TABLECOURSUSER = Database::get_main_table(TABLE_MAIN_COURSE_USER);
$category_id = (int) $category_id;
$result = false;
$sql = "DELETE FROM $tucc
WHERE
id='".$category_id."' AND
user_id='".$current_user_id."'";
$resultQuery = Database::query($sql);
if (Database::affected_rows($resultQuery)) {
$result = true;
}
$sql = "UPDATE $TABLECOURSUSER
SET user_course_cat='0'
WHERE
user_course_cat='".$category_id."' AND
user_id='".$current_user_id."' AND
relation_type<>".COURSE_RELATION_TYPE_RRHH." ";
Database::query($sql);
return $result;
}
/**
* @param int $categoryId
*
* @return array|mixed
*/
public function getUserCourseCategory($categoryId)
{
$userId = api_get_user_id();
$tucc = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
$categoryId = (int) $categoryId;
$sql = "SELECT * FROM $tucc
WHERE
id= $categoryId AND
user_id= $userId";
$resultQuery = Database::query($sql);
return Database::fetch_array($resultQuery, 'ASSOC');
}
/**
* unsubscribe the user from a given course.
*
* @param string $course_code
*
* @return bool True if it success
*/
public function remove_user_from_course($course_code, $sessionId = 0)
{
$tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
// protect variables
$current_user_id = api_get_user_id();
$course_code = Database::escape_string($course_code);
$courseInfo = api_get_course_info($course_code);
if (empty($courseInfo) || empty($current_user_id)) {
return false;
}
// Check if course can be unsubscribe.
if ('1' !== $courseInfo['unsubscribe']) {
return false;
}
$courseId = $courseInfo['real_id'];
// we check (once again) if the user is not course administrator
// because the course administrator cannot unsubscribe himself
// (s)he can only delete the course
$sql = "SELECT * FROM $tbl_course_user
WHERE
user_id='".$current_user_id."' AND
c_id ='".$courseId."' AND
status='1' ";
$result_check = Database::query($sql);
$number_of_rows = Database::num_rows($result_check);
$result = true;
if ($number_of_rows > 0) {
$result = false;
}
if ($result) {
CourseManager::unsubscribe_user($current_user_id, $course_code, $sessionId);
}
return $result;
}
/**
* stores the user course category in the chamilo_user database.
*
* @param string Category title
*
* @return bool True if it success
*/
public function store_course_category($category_title)
{
$table = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
// protect data
$current_user_id = api_get_user_id();
$category_title = Database::escape_string($category_title);
// step 1: we determine the max value of the user defined course categories
$sql = "SELECT sort FROM $table
WHERE user_id='".$current_user_id."'
ORDER BY sort DESC";
$rs_sort = Database::query($sql);
$maxsort = Database::fetch_array($rs_sort);
$nextsort = $maxsort['sort'] + 1;
// step 2: we check if there is already a category with this name,
// if not we store it, else we give an error.
$sql = "SELECT * FROM $table
WHERE
user_id='".$current_user_id."' AND
title='".$category_title."'
ORDER BY sort DESC";
$rs = Database::query($sql);
$result = false;
if (0 == Database::num_rows($rs)) {
$sql = "INSERT INTO $table (user_id, title,sort)
VALUES ('".$current_user_id."', '".api_htmlentities(
$category_title,
ENT_QUOTES,
api_get_system_encoding()
)."', '".$nextsort."')";
$resultQuery = Database::query($sql);
if (Database::affected_rows($resultQuery)) {
$result = true;
}
}
return $result;
}
}

176
main/inc/lib/baker.lib.php Normal file
View File

@@ -0,0 +1,176 @@
<?php
/**
* Php library to Bake the PNG Images.
*/
class PNGImageBaker
{
private $_contents;
private $_size;
private $_chunks;
/**
* Prepares file for handling metadata.
* Verifies that this file is a valid PNG file.
* Unpacks file chunks and reads them into an array.
*
* @param string $contents File content as a string
*/
public function __construct($contents)
{
$this->_contents = $contents;
$png_signature = pack("C8", 137, 80, 78, 71, 13, 10, 26, 10);
// Read 8 bytes of PNG header and verify.
$header = substr($this->_contents, 0, 8);
if ($header != $png_signature) {
echo 'This is not a valid PNG image';
}
$this->_size = strlen($this->_contents);
$this->_chunks = [];
// Skip 8 bytes of IHDR image header.
$position = 8;
do {
$chunk = @unpack('Nsize/a4type', substr($this->_contents, $position, 8));
$this->_chunks[$chunk['type']][] = substr($this->_contents, $position + 8, $chunk['size']);
// Skip 12 bytes chunk overhead.
$position += $chunk['size'] + 12;
} while ($position < $this->_size);
}
/**
* Checks if a key already exists in the chunk of said type.
* We need to avoid writing same keyword into file chunks.
*
* @param string $type chunk type, like iTXt, tEXt, etc
* @param string $check keyword that needs to be checked
*
* @return bool (true|false) True if file is safe to write this keyword, false otherwise
*/
public function checkChunks($type, $check)
{
if (array_key_exists($type, $this->_chunks)) {
foreach (array_keys($this->_chunks[$type]) as $typekey) {
list($key, $data) = explode("\0", $this->_chunks[$type][$typekey]);
if (0 == strcmp($key, $check)) {
echo 'Key "'.$check.'" already exists in "'.$type.'" chunk.';
return false;
}
}
}
return true;
}
/**
* Add a chunk by type with given key and text.
*
* @param string $chunkType chunk type, like iTXt, tEXt, etc
* @param string $key keyword that needs to be added
* @param string $value currently an assertion URL that is added to an image metadata
*
* @return string $result file content with a new chunk as a string
*/
public function addChunk($chunkType, $key, $value)
{
$chunkData = $key."\0".$value;
$crc = pack("N", crc32($chunkType.$chunkData));
$len = pack("N", strlen($chunkData));
$newChunk = $len.$chunkType.$chunkData.$crc;
$result = substr($this->_contents, 0, $this->_size - 12)
.$newChunk
.substr($this->_contents, $this->_size - 12, 12);
return $result;
}
/**
* removes a chunk by type with given key and text.
*
* @param string $chunkType chunk type, like iTXt, tEXt, etc
* @param string $key keyword that needs to be deleted
* @param string $png the png image
*
* @return string $result new File content
*/
public function removeChunks($chunkType, $key, $png)
{
// Read the magic bytes and verify
$retval = substr($png, 0, 8);
$ipos = 8;
if ($retval != "\x89PNG\x0d\x0a\x1a\x0a") {
throw new Exception('Is not a valid PNG image');
}
// Loop through the chunks. Byte 0-3 is length, Byte 4-7 is type
$chunkHeader = substr($png, $ipos, 8);
$ipos = $ipos + 8;
while ($chunkHeader) {
// Extract length and type from binary data
$chunk = @unpack('Nsize/a4type', $chunkHeader);
$skip = false;
if ($chunk['type'] == $chunkType) {
$data = substr($png, $ipos, $chunk['size']);
$sections = explode("\0", $data);
print_r($sections);
if ($sections[0] == $key) {
$skip = true;
}
}
// Extract the data and the CRC
$data = substr($png, $ipos, $chunk['size'] + 4);
$ipos = $ipos + $chunk['size'] + 4;
// Add in the header, data, and CRC
if (!$skip) {
$retval = $retval.$chunkHeader.$data;
}
// Read next chunk header
$chunkHeader = substr($png, $ipos, 8);
$ipos = $ipos + 8;
}
return $retval;
}
/**
* Extracts the baked PNG info by the Key.
*
* @param string $png the png image
* @param string $key keyword that needs to be searched
*
* @return mixed - If there is an error - boolean false is returned
* If there is PNG information that matches the key an array is returned
*/
public function extractBadgeInfo($png, $key = 'openbadges')
{
// Read the magic bytes and verify
$retval = substr($png, 0, 8);
$ipos = 8;
if ("\x89PNG\x0d\x0a\x1a\x0a" != $retval) {
return false;
}
// Loop through the chunks. Byte 0-3 is length, Byte 4-7 is type
$chunkHeader = substr($png, $ipos, 8);
$ipos = $ipos + 8;
while ($chunkHeader) {
// Extract length and type from binary data
$chunk = @unpack('Nsize/a4type', $chunkHeader);
$skip = false;
if ('tEXt' == $chunk['type']) {
$data = substr($png, $ipos, $chunk['size']);
$sections = explode("\0", $data);
if ($sections[0] == $key) {
return $sections;
}
}
// Extract the data and the CRC
$data = substr($png, $ipos, $chunk['size'] + 4);
$ipos = $ipos + $chunk['size'] + 4;
// Read next chunk header
$chunkHeader = substr($png, $ipos, 8);
$ipos = $ipos + 8;
}
}
}

1085
main/inc/lib/banner.lib.php Normal file

File diff suppressed because it is too large Load Diff

3306
main/inc/lib/blog.lib.php Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1570
main/inc/lib/career.lib.php Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,955 @@
<?php
/* For licensing terms, see /license.txt */
use Endroid\QrCode\ErrorCorrectionLevel;
use Endroid\QrCode\QrCode;
/**
* Certificate Class
* Generate certificates based in the gradebook tool.
*/
class Certificate extends Model
{
public $table;
public $columns = [
'id',
'cat_id',
'score_certificate',
'created_at',
'path_certificate',
];
/**
* Certification data.
*/
public $certificate_data = [];
/**
* Student's certification path.
*/
public $certification_user_path = null;
public $certification_web_user_path = null;
public $html_file = null;
public $qr_file = null;
public $user_id;
/** If true every time we enter to the certificate URL
* we would generate a new certificate (good thing because we can edit the
* certificate and all users will have the latest certificate bad because we.
* load the certificate every time */
public $force_certificate_generation = true;
/**
* Constructor.
*
* @param int $certificate_id ID of the certificate
* @param int $userId
* @param bool $sendNotification send message to student
* @param bool $updateCertificateData
*
* If no ID given, take user_id and try to generate one
*/
public function __construct(
$certificate_id = 0,
$userId = 0,
$sendNotification = false,
$updateCertificateData = true
) {
$this->table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CERTIFICATE);
$this->user_id = !empty($userId) ? $userId : api_get_user_id();
if (!empty($certificate_id)) {
$certificate = $this->get($certificate_id);
if (!empty($certificate) && is_array($certificate)) {
$this->certificate_data = $certificate;
$this->user_id = $this->certificate_data['user_id'];
}
}
if ($this->user_id) {
// Need to be called before any operation
$this->check_certificate_path();
// To force certification generation
if ($this->force_certificate_generation) {
$this->generate([], $sendNotification);
}
if (isset($this->certificate_data) && $this->certificate_data) {
if (empty($this->certificate_data['path_certificate'])) {
$this->generate([], $sendNotification);
}
}
}
// Setting the qr and html variables
if (isset($certificate_id) &&
!empty($this->certification_user_path) &&
isset($this->certificate_data['path_certificate'])
) {
$pathinfo = pathinfo($this->certificate_data['path_certificate']);
$this->html_file = $this->certification_user_path.basename($this->certificate_data['path_certificate']);
$this->qr_file = $this->certification_user_path.$pathinfo['filename'].'_qr.png';
} else {
$this->check_certificate_path();
if (api_get_configuration_value('allow_general_certificate')) {
// General certificate
$name = md5($this->user_id).'.html';
$my_path_certificate = $this->certification_user_path.$name;
$path_certificate = '/'.$name;
// Getting QR filename
$file_info = pathinfo($path_certificate);
$content = $this->generateCustomCertificate();
$my_new_content_html = str_replace(
'((certificate_barcode))',
Display::img(
$this->certification_web_user_path.$file_info['filename'].'_qr.png',
'QR'
),
$content
);
$my_new_content_html = mb_convert_encoding(
$my_new_content_html,
'UTF-8',
api_get_system_encoding()
);
$this->html_file = $my_path_certificate;
$result = @file_put_contents($my_path_certificate, $my_new_content_html);
if ($result) {
// Updating the path
self::updateUserCertificateInfo(
0,
$this->user_id,
$path_certificate,
$updateCertificateData
);
$this->certificate_data['path_certificate'] = $path_certificate;
}
}
}
}
/**
* Checks if the certificate user path directory is created.
*/
public function check_certificate_path()
{
$this->certification_user_path = null;
// Setting certification path
$path_info = UserManager::getUserPathById($this->user_id, 'system');
$web_path_info = UserManager::getUserPathById($this->user_id, 'web');
if (!empty($path_info) && isset($path_info)) {
$this->certification_user_path = $path_info.'certificate/';
$this->certification_web_user_path = $web_path_info.'certificate/';
$mode = api_get_permissions_for_new_directories();
if (!is_dir($path_info)) {
mkdir($path_info, $mode, true);
}
if (!is_dir($this->certification_user_path)) {
mkdir($this->certification_user_path, $mode);
}
}
}
/**
* Deletes the current certificate object. This is generally triggered by
* the teacher from the gradebook tool to re-generate the certificate because
* the original version wa flawed.
*
* @param bool $force_delete
*
* @return bool
*/
public function delete($force_delete = false)
{
$delete_db = false;
if (!empty($this->certificate_data)) {
if (!is_null($this->html_file) || $this->html_file != '' || strlen($this->html_file)) {
// Deleting HTML file
if (is_file($this->html_file)) {
@unlink($this->html_file);
if (is_file($this->html_file) === false) {
$delete_db = true;
} else {
$delete_db = false;
}
}
// Deleting QR code PNG image file
if (is_file($this->qr_file)) {
@unlink($this->qr_file);
}
if ($delete_db || $force_delete) {
return parent::delete($this->certificate_data['id']);
}
} else {
return parent::delete($this->certificate_data['id']);
}
}
return false;
}
/**
* Generates an HTML Certificate and fills the path_certificate field in the DB.
*
* @param array $params
* @param bool $sendNotification
*
* @return bool|int
*/
public function generate($params = [], $sendNotification = false)
{
// The user directory should be set
if (empty($this->certification_user_path) &&
$this->force_certificate_generation === false
) {
return false;
}
$params['hide_print_button'] = isset($params['hide_print_button']) ? true : false;
$categoryId = 0;
$my_category = [];
if (isset($this->certificate_data) && isset($this->certificate_data['cat_id'])) {
$categoryId = $this->certificate_data['cat_id'];
$my_category = Category::load($categoryId);
}
if (isset($my_category[0]) && !empty($categoryId) &&
$my_category[0]->is_certificate_available($this->user_id)
) {
/** @var Category $category */
$category = $my_category[0];
$courseInfo = api_get_course_info($category->get_course_code());
$courseId = $courseInfo['real_id'];
$sessionId = $category->get_session_id();
$skill = new Skill();
$skill->addSkillToUser(
$this->user_id,
$category,
$courseId,
$sessionId
);
if (is_dir($this->certification_user_path)) {
if (!empty($this->certificate_data)) {
$new_content_html = GradebookUtils::get_user_certificate_content(
$this->user_id,
$category->get_course_code(),
$category->get_session_id(),
false,
$params['hide_print_button']
);
if ($category->get_id() == $categoryId) {
$name = $this->certificate_data['path_certificate'];
$myPathCertificate = $this->certification_user_path.basename($name);
if (file_exists($myPathCertificate) &&
!empty($name) &&
!is_dir($myPathCertificate) &&
$this->force_certificate_generation == false
) {
// Seems that the file was already generated
return true;
} else {
// Creating new name
$name = md5($this->user_id.$this->certificate_data['cat_id']).'.html';
$myPathCertificate = $this->certification_user_path.$name;
$path_certificate = '/'.$name;
// Getting QR filename
$file_info = pathinfo($path_certificate);
$qr_code_filename = $this->certification_user_path.$file_info['filename'].'_qr.png';
$newContent = str_replace(
'((certificate_barcode))',
Display::img(
$this->certification_web_user_path.$file_info['filename'].'_qr.png',
'QR'
),
$new_content_html['content']
);
$newContent = api_convert_encoding(
$newContent,
'UTF-8',
api_get_system_encoding()
);
$result = @file_put_contents($myPathCertificate, $newContent);
if ($result) {
// Updating the path
$this->updateUserCertificateInfo(
$this->certificate_data['cat_id'],
$this->user_id,
$path_certificate
);
$this->certificate_data['path_certificate'] = $path_certificate;
if ($this->isHtmlFileGenerated()) {
if (!empty($file_info)) {
$text = $this->parseCertificateVariables(
$new_content_html['variables']
);
$this->generateQRImage(
$text,
$qr_code_filename
);
if ($sendNotification) {
$subject = get_lang('NotificationCertificateSubject');
$message = nl2br(get_lang('NotificationCertificateTemplate'));
$score = $this->certificate_data['score_certificate'];
self::sendNotification(
$subject,
$message,
api_get_user_info($this->user_id),
$courseInfo,
[
'score_certificate' => $score,
]
);
}
}
}
}
return $result;
}
}
}
}
} else {
$this->check_certificate_path();
// General certificate
$name = md5($this->user_id).'.html';
$my_path_certificate = $this->certification_user_path.$name;
$path_certificate = '/'.$name;
// Getting QR filename
$file_info = pathinfo($path_certificate);
$content = $this->generateCustomCertificate();
$my_new_content_html = str_replace(
'((certificate_barcode))',
Display::img(
$this->certification_web_user_path.$file_info['filename'].'_qr.png',
'QR'
),
$content
);
$my_new_content_html = mb_convert_encoding(
$my_new_content_html,
'UTF-8',
api_get_system_encoding()
);
$result = @file_put_contents($my_path_certificate, $my_new_content_html);
if ($result) {
// Updating the path
self::updateUserCertificateInfo(
0,
$this->user_id,
$path_certificate
);
$this->certificate_data['path_certificate'] = $path_certificate;
}
return $result;
}
return false;
}
/**
* @return array
*/
public static function notificationTags()
{
$tags = [
'((course_title))',
'((user_first_name))',
'((user_last_name))',
'((author_first_name))',
'((author_last_name))',
'((score))',
'((portal_name))',
'((certificate_link))',
];
return $tags;
}
/**
* @param string $subject
* @param string $message
* @param array $userInfo
* @param array $courseInfo
* @param array $certificateInfo
*
* @return bool
*/
public static function sendNotification(
$subject,
$message,
$userInfo,
$courseInfo,
$certificateInfo
) {
if (empty($userInfo) || empty($courseInfo)) {
return false;
}
$currentUserInfo = api_get_user_info();
$url = api_get_path(WEB_PATH).
'certificates/index.php?id='.$certificateInfo['id'].'&user_id='.$certificateInfo['user_id'];
$link = Display::url($url, $url);
$replace = [
$courseInfo['title'],
$userInfo['firstname'],
$userInfo['lastname'],
$currentUserInfo['firstname'],
$currentUserInfo['lastname'],
$certificateInfo['score_certificate'],
api_get_setting('Institution'),
$link,
];
$message = str_replace(self::notificationTags(), $replace, $message);
MessageManager::send_message(
$userInfo['id'],
$subject,
$message,
[],
[],
0,
0,
0,
0,
$currentUserInfo['id']
);
$plugin = new AppPlugin();
$smsPlugin = $plugin->getSMSPluginLibrary();
if ($smsPlugin) {
$additionalParameters = [
'smsType' => SmsPlugin::CERTIFICATE_NOTIFICATION,
'userId' => $userInfo['id'],
'direct_message' => $message,
];
$smsPlugin->send($additionalParameters);
}
}
/**
* Update user info about certificate.
*
* @param int $categoryId category id
* @param int $user_id user id
* @param string $path_certificate the path name of the certificate
* @param bool $updateCertificateData
*/
public function updateUserCertificateInfo(
$categoryId,
$user_id,
$path_certificate,
$updateCertificateData = true
) {
$categoryId = (int) $categoryId;
$user_id = (int) $user_id;
if ($updateCertificateData &&
!UserManager::is_user_certified($categoryId, $user_id)
) {
$table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CERTIFICATE);
$now = api_get_utc_datetime();
$sql = 'UPDATE '.$table.' SET
path_certificate="'.Database::escape_string($path_certificate).'",
created_at = "'.$now.'"
WHERE cat_id = "'.$categoryId.'" AND user_id="'.$user_id.'" ';
Database::query($sql);
}
}
/**
* Check if the file was generated.
*
* @return bool
*/
public function isHtmlFileGenerated()
{
if (empty($this->certification_user_path)) {
return false;
}
if (!empty($this->certificate_data) &&
isset($this->certificate_data['path_certificate']) &&
!empty($this->certificate_data['path_certificate'])
) {
return true;
}
return false;
}
/**
* Generates a QR code for the certificate. The QR code embeds the text given.
*
* @param string $text Text to be added in the QR code
* @param string $path file path of the image
*
* @return bool
*/
public function generateQRImage($text, $path)
{
if (!empty($text) && !empty($path)) {
$qrCode = new QrCode($text);
//$qrCode->setEncoding('UTF-8');
$qrCode->setSize(120);
$qrCode->setMargin(5);
$qrCode->setWriterByName('png');
$qrCode->setErrorCorrectionLevel(ErrorCorrectionLevel::MEDIUM);
$qrCode->setForegroundColor(['r' => 0, 'g' => 0, 'b' => 0, 'a' => 0]);
$qrCode->setBackgroundColor(['r' => 255, 'g' => 255, 'b' => 255, 'a' => 0]);
$qrCode->setValidateResult(false);
$qrCode->writeFile($path);
return true;
}
return false;
}
/**
* Transforms certificate tags into text values. This function is very static
* (it doesn't allow for much flexibility in terms of what tags are printed).
*
* @param array $array Contains two array entries: first are the headers,
* second is an array of contents
*
* @return string The translated string
*/
public function parseCertificateVariables($array)
{
$headers = $array[0];
$content = $array[1];
$final_content = [];
if (!empty($content)) {
foreach ($content as $key => $value) {
$my_header = str_replace(['((', '))'], '', $headers[$key]);
$final_content[$my_header] = $value;
}
}
/* Certificate tags
*
0 => string '((user_firstname))' (length=18)
1 => string '((user_lastname))' (length=17)
2 => string '((gradebook_institution))' (length=25)
3 => string '((gradebook_sitename))' (length=22)
4 => string '((teacher_firstname))' (length=21)
5 => string '((teacher_lastname))' (length=20)
6 => string '((official_code))' (length=17)
7 => string '((date_certificate))' (length=20)
8 => string '((course_code))' (length=15)
9 => string '((course_title))' (length=16)
10 => string '((gradebook_grade))' (length=19)
11 => string '((certificate_link))' (length=20)
12 => string '((certificate_link_html))' (length=25)
13 => string '((certificate_barcode))' (length=23)
*/
$break_space = " \n\r ";
$text =
$final_content['gradebook_institution'].' - '.
$final_content['gradebook_sitename'].' - '.
get_lang('Certification').$break_space.
get_lang('Student').': '.$final_content['user_firstname'].' '.$final_content['user_lastname'].$break_space.
get_lang('Teacher').': '.$final_content['teacher_firstname'].' '.$final_content['teacher_lastname'].$break_space.
get_lang('Date').': '.$final_content['date_certificate'].$break_space.
get_lang('Score').': '.$final_content['gradebook_grade'].$break_space.
'URL'.': '.$final_content['certificate_link'];
return $text;
}
/**
* Check if the certificate is visible for the current user
* If the global setting allow_public_certificates is set to 'false', no certificate can be printed.
* If the global allow_public_certificates is set to 'true' and the course setting allow_public_certificates
* is set to 0, no certificate *in this course* can be printed (for anonymous users).
* Connected users can always print them.
*
* @return bool
*/
public function isVisible()
{
if (!api_is_anonymous()) {
return true;
}
if (api_get_setting('allow_public_certificates') != 'true') {
// The "non-public" setting is set, so do not print
return false;
}
if (!isset($this->certificate_data, $this->certificate_data['cat_id'])) {
return false;
}
$gradeBook = new Gradebook();
$gradeBookInfo = $gradeBook->get($this->certificate_data['cat_id']);
if (empty($gradeBookInfo['course_code'])) {
return false;
}
$setting = api_get_course_setting(
'allow_public_certificates',
api_get_course_info($gradeBookInfo['course_code'])
);
if ($setting == 0) {
// Printing not allowed
return false;
}
return true;
}
/**
* Check if the certificate is available.
*
* @return bool
*/
public function isAvailable()
{
if (empty($this->certificate_data['path_certificate'])) {
return false;
}
$userCertificate = $this->certification_user_path.basename($this->certificate_data['path_certificate']);
if (!file_exists($userCertificate)) {
return false;
}
return true;
}
/**
* Shows the student's certificate (HTML file).
*/
public function show()
{
$user_certificate = $this->certification_user_path.basename($this->certificate_data['path_certificate']);
if (file_exists($user_certificate)) {
// Needed in order to browsers don't add custom CSS
$certificateContent = '<!DOCTYPE html>';
$certificateContent .= (string) file_get_contents($user_certificate);
// Remove media=screen to be available when printing a document
$certificateContent = str_replace(
' media="screen"',
'',
$certificateContent
);
if ($this->user_id == api_get_user_id() &&
!empty($this->certificate_data) &&
isset($this->certificate_data['id'])
) {
$certificateId = $this->certificate_data['id'];
$extraFieldValue = new ExtraFieldValue('user_certificate');
$value = $extraFieldValue->get_values_by_handler_and_field_variable(
$certificateId,
'downloaded_at'
);
if (empty($value)) {
$params = [
'item_id' => $this->certificate_data['id'],
'extra_downloaded_at' => api_get_utc_datetime(),
];
$extraFieldValue->saveFieldValues($params);
}
}
header('Content-Type: text/html; charset='.api_get_system_encoding());
echo $certificateContent;
return;
}
api_not_allowed(true);
}
/**
* @return string
*/
public function generateCustomCertificate()
{
$myCertificate = GradebookUtils::get_certificate_by_user_id(
0,
$this->user_id
);
if (empty($myCertificate)) {
GradebookUtils::registerUserInfoAboutCertificate(
0,
$this->user_id,
100,
api_get_utc_datetime()
);
}
$userInfo = api_get_user_info($this->user_id);
$extraFieldValue = new ExtraFieldValue('user');
$value = $extraFieldValue->get_values_by_handler_and_field_variable($this->user_id, 'legal_accept');
$termsValidationDate = '';
if (isset($value) && !empty($value['value'])) {
list($id, $id2, $termsValidationDate) = explode(':', $value['value']);
}
$sessions = SessionManager::get_sessions_by_user($this->user_id, false, true);
$totalTimeInLearningPaths = 0;
$sessionsApproved = [];
$coursesApproved = [];
$courseList = [];
if ($sessions) {
foreach ($sessions as $session) {
$allCoursesApproved = [];
foreach ($session['courses'] as $course) {
$courseInfo = api_get_course_info_by_id($course['real_id']);
$courseCode = $courseInfo['code'];
$gradebookCategories = Category::load(
null,
null,
$courseCode,
null,
false,
$session['session_id']
);
if (isset($gradebookCategories[0])) {
/** @var Category $category */
$category = $gradebookCategories[0];
$result = Category::userFinishedCourse(
$this->user_id,
$category,
true
);
// Find time spent in LP
$timeSpent = Tracking::get_time_spent_in_lp(
$this->user_id,
$courseCode,
[],
$session['session_id']
);
if (!isset($courseList[$course['real_id']])) {
$courseList[$course['real_id']]['approved'] = false;
$courseList[$course['real_id']]['time_spent'] = 0;
}
if ($result) {
$courseList[$course['real_id']]['approved'] = true;
$coursesApproved[$course['real_id']] = $courseInfo['title'];
// Find time spent in LP
//$totalTimeInLearningPaths += $timeSpent;
$allCoursesApproved[] = true;
}
$courseList[$course['real_id']]['time_spent'] += $timeSpent;
}
}
if (count($allCoursesApproved) == count($session['courses'])) {
$sessionsApproved[] = $session;
}
}
}
$totalTimeInLearningPaths = 0;
foreach ($courseList as $courseId => $courseData) {
if ($courseData['approved'] === true) {
$totalTimeInLearningPaths += $courseData['time_spent'];
}
}
$skill = new Skill();
// Ofaj
$skills = $skill->getStudentSkills($this->user_id, 2);
$timeInSeconds = Tracking::get_time_spent_on_the_platform(
$this->user_id,
'ever'
);
$time = api_time_to_hms($timeInSeconds);
$tplContent = new Template(null, false, false, false, false, false);
// variables for the default template
$tplContent->assign('complete_name', $userInfo['complete_name']);
$tplContent->assign('time_in_platform', $time);
$tplContent->assign('certificate_generated_date', api_get_local_time($myCertificate['created_at']));
if (!empty($termsValidationDate)) {
$termsValidationDate = api_get_local_time($termsValidationDate);
}
$tplContent->assign('terms_validation_date', $termsValidationDate);
// Ofaj
$tplContent->assign('time_in_platform_in_hours', round($timeInSeconds / 3600, 1));
$tplContent->assign(
'certificate_generated_date_no_time',
api_get_local_time(
$myCertificate['created_at'],
null,
null,
false,
false,
false,
'd-m-Y'
)
);
$tplContent->assign(
'terms_validation_date_no_time',
api_get_local_time(
$termsValidationDate,
null,
null,
false,
false,
false,
'd-m-Y'
)
);
$tplContent->assign('skills', $skills);
$tplContent->assign('sessions', $sessionsApproved);
$tplContent->assign('courses', $coursesApproved);
$tplContent->assign('time_spent_in_lps', api_time_to_hms($totalTimeInLearningPaths));
$tplContent->assign('time_spent_in_lps_in_hours', round($totalTimeInLearningPaths / 3600, 1));
$layoutContent = $tplContent->get_template('gradebook/custom_certificate.tpl');
$content = $tplContent->fetch($layoutContent);
return $content;
}
/**
* Ofaj.
*/
public function generatePdfFromCustomCertificate()
{
$orientation = api_get_configuration_value('certificate_pdf_orientation');
$params['orientation'] = 'landscape';
if (!empty($orientation)) {
$params['orientation'] = $orientation;
}
$params['left'] = 0;
$params['right'] = 0;
$params['top'] = 0;
$params['bottom'] = 0;
$page_format = $params['orientation'] == 'landscape' ? 'A4-L' : 'A4';
$pdf = new PDF($page_format, $params['orientation'], $params);
$pdf->html_to_pdf(
$this->html_file,
get_lang('Certificates'),
null,
false,
false
);
}
/**
* @param int $userId
*
* @return array
*/
public static function getCertificateByUser($userId)
{
$userId = (int) $userId;
if (empty($userId)) {
return [];
}
$table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CERTIFICATE);
$sql = "SELECT * FROM $table
WHERE user_id= $userId";
$rs = Database::query($sql);
return Database::store_result($rs, 'ASSOC');
}
/**
* @param int $userId
*/
public static function generateUserSkills($userId)
{
$controller = new IndexManager(get_lang('MyCourses'));
$courseAndSessions = $controller->returnCoursesAndSessions($userId, true, null, true, false);
if (isset($courseAndSessions['courses']) && !empty($courseAndSessions['courses'])) {
foreach ($courseAndSessions['courses'] as $course) {
$cats = Category::load(
null,
null,
$course['code'],
null,
null,
null,
false
);
if (isset($cats[0]) && !empty($cats[0])) {
Category::generateUserCertificate(
$cats[0]->get_id(),
$userId
);
}
}
}
if (isset($courseAndSessions['sessions']) && !empty($courseAndSessions['sessions'])) {
foreach ($courseAndSessions['sessions'] as $sessionCategory) {
if (isset($sessionCategory['sessions'])) {
foreach ($sessionCategory['sessions'] as $sessionData) {
if (!empty($sessionData['courses'])) {
$sessionId = $sessionData['session_id'];
foreach ($sessionData['courses'] as $courseData) {
$cats = Category::load(
null,
null,
$courseData['course_code'],
null,
null,
$sessionId,
false
);
if (isset($cats[0]) && !empty($cats[0])) {
Category::generateUserCertificate(
$cats[0]->get_id(),
$userId
);
}
}
}
}
}
}
}
}
}

View File

@@ -0,0 +1,162 @@
<?php
use Symfony\Component\HttpFoundation\Session\Session;
/**
* Chamilo session (i.e. the session that maintains the connection open after usr login).
*
* Usage:
*
*
* use ChamiloSession as Session;
*
* Session::read('name');
*
* Or
*
* Chamilo::session()->...
* session()->...
*
* @license see /license.txt
* @author Laurent Opprecht <laurent@opprecht.info> for the Univesity of Geneva
*/
/**
* @todo use session symfony component
* @todo replace all $_SESSION calls with this class.
* @todo remove System\Session class
* ChamiloSession class definition
*/
class ChamiloSession extends System\Session
{
public const NAME = 'ch_sid';
/**
* Generate new session instance.
*
* @return ChamiloSession
*/
public static function instance()
{
static $result = null;
if (empty($result)) {
$result = new ChamiloSession();
}
return $result;
}
/**
* Returns the session lifetime.
*
* @return int The session lifetime as defined in the config file, in seconds
*/
public static function session_lifetime()
{
return api_get_configuration_value('session_lifetime');
}
/**
* Starts the Chamilo session.
*
* The default lifetime for session is set here. It is not possible to have it
* as a database setting as it is used before the database connection has been made.
* It is taken from the configuration file, and if it doesn't exist there, it is set
* to 360000 seconds
*
* @author Olivier Brouckaert
*
* @param string variable - the variable name to save into the session
*/
public static function start($already_installed = true)
{
/*
* Prevent Session fixation bug fixes
* See http://support.chamilo.org/issues/3600
* http://php.net/manual/en/session.configuration.php
* @todo use session_set_cookie_params with some custom admin parameters
*/
//session.cookie_lifetime
//the session ID is only accepted from a cookie
ini_set('session.use_only_cookies', 1);
//HTTPS only if possible
//ini_set('session.cookie_secure', 1);
//session ID in the cookie is only readable by the server
ini_set('session.cookie_httponly', 1);
if (api_is_https()) {
ini_set('session.cookie_secure', 1);
}
if (api_get_configuration_value('security_session_cookie_samesite_none')) {
if (PHP_VERSION_ID < 70300) {
$sessionCookieParams = session_get_cookie_params();
session_set_cookie_params($sessionCookieParams['lifetime'], '/; samesite=None',
$sessionCookieParams['domain'], true, $sessionCookieParams['httponly']);
} else {
ini_set('session.cookie_samesite', 'None');
}
}
//Use entropy file
//session.entropy_file
//ini_set('session.entropy_length', 128);
//Do not include the identifier in the URL, and not to read the URL for
// identifiers.
ini_set('session.use_trans_sid', 0);
session_name(self::NAME);
session_start();
$session = self::instance();
if ($already_installed) {
if (!isset($session['checkChamiloURL'])) {
$session['checkChamiloURL'] = api_get_path(WEB_PATH);
} elseif ($session['checkChamiloURL'] != api_get_path(WEB_PATH)) {
self::clear();
}
}
// If the session time has expired, refresh the starttime value,
// so we're starting to count down from a later time
if (self::has('starttime') && $session->is_expired()) {
self::destroy();
} else {
//error_log('Time not expired, extend session for a bit more');
self::write('starttime', time());
}
}
/**
* Session start time: that is the last time the user loaded a page (before this time).
*
* @return int timestamp
*/
public function start_time()
{
return self::read('starttime');
}
/**
* Session end time: when the session expires. This is made of the last page
* load time + a number of seconds.
*
* @return int UNIX timestamp (server's timezone)
*/
public function end_time()
{
$start_time = $this->start_time();
$lifetime = self::session_lifetime();
return $start_time + $lifetime;
}
/**
* Returns whether the session is expired.
*
* @return bool True if the session is expired, false if it is still valid
*/
public function is_expired()
{
return $this->end_time() < time();
}
}

530
main/inc/lib/chat.lib.php Normal file
View File

@@ -0,0 +1,530 @@
<?php
/* For licensing terms, see /license.txt */
use ChamiloSession as Session;
/**
* Class Chat.
*
* @todo ChamiloSession instead of $_SESSION
*/
class Chat extends Model
{
public $columns = [
'id',
'from_user',
'to_user',
'message',
'sent',
'recd',
];
public $window_list = [];
/**
* The contructor sets the chat table name and the window_list attribute.
*/
public function __construct()
{
parent::__construct();
$this->table = Database::get_main_table(TABLE_MAIN_CHAT);
$this->window_list = Session::read('window_list');
Session::write('window_list', $this->window_list);
}
/**
* Get user chat status.
*
* @return int 0 if disconnected, 1 if connected
*/
public function getUserStatus()
{
$status = UserManager::get_extra_user_data_by_field(
api_get_user_id(),
'user_chat_status',
false,
true
);
return $status['user_chat_status'];
}
/**
* Set user chat status.
*
* @param int $status 0 if disconnected, 1 if connected
*/
public function setUserStatus($status)
{
UserManager::update_extra_field_value(
api_get_user_id(),
'user_chat_status',
$status
);
}
/**
* @param int $currentUserId
* @param int $userId
* @param bool $latestMessages
*
* @return array
*/
public function getLatestChat($currentUserId, $userId, $latestMessages)
{
$items = $this->getPreviousMessages(
$currentUserId,
$userId,
0,
$latestMessages
);
return array_reverse($items);
}
/**
* @return string
*/
public function getContacts()
{
$html = SocialManager::listMyFriendsBlock(
api_get_user_id(),
'',
true
);
echo $html;
}
/**
* @param array $chatHistory
* @param int $latestMessages
*
* @return mixed
*/
public function getAllLatestChats($chatHistory, $latestMessages = 5)
{
$currentUserId = api_get_user_id();
if (empty($chatHistory)) {
return [];
}
$chats = [];
foreach ($chatHistory as $userId => $time) {
$total = $this->getCountMessagesExchangeBetweenUsers($userId, $currentUserId);
$start = $total - $latestMessages;
if ($start < 0) {
$start = 0;
}
$items = $this->getMessages($userId, $currentUserId, $start, $latestMessages);
$chats[$userId]['items'] = $items;
$chats[$userId]['window_user_info'] = api_get_user_info($userId);
}
return $chats;
}
/**
* Starts a chat session and returns JSON array of status and chat history.
*
* @return bool (prints output in JSON format)
*/
public function startSession()
{
// ofaj
// $chat = new Chat();
// $chat->setUserStatus(1);
$chatList = Session::read('openChatBoxes');
$chats = $this->getAllLatestChats($chatList);
$return = [
'user_status' => $this->getUserStatus(),
'me' => get_lang('Me'),
'user_id' => api_get_user_id(),
'items' => $chats,
'sec_token' => Security::get_token('chat'),
];
echo json_encode($return);
return true;
}
/**
* @param int $fromUserId
* @param int $toUserId
*
* @return int
*/
public function getCountMessagesExchangeBetweenUsers($fromUserId, $toUserId)
{
$row = Database::select(
'count(*) as count',
$this->table,
[
'where' => [
'(from_user = ? AND to_user = ?) OR (from_user = ? AND to_user = ?) ' => [
$fromUserId,
$toUserId,
$toUserId,
$fromUserId,
],
],
],
'first'
);
return (int) $row['count'];
}
/**
* @param int $fromUserId
* @param int $toUserId
* @param int $visibleMessages
* @param int $previousMessageCount messages to show
*
* @return array
*/
public function getPreviousMessages(
$fromUserId,
$toUserId,
$visibleMessages = 1,
$previousMessageCount = 5,
$orderBy = ''
) {
$toUserId = (int) $toUserId;
$fromUserId = (int) $fromUserId;
$visibleMessages = (int) $visibleMessages;
$previousMessageCount = (int) $previousMessageCount;
$total = $this->getCountMessagesExchangeBetweenUsers($fromUserId, $toUserId);
$show = $total - $visibleMessages;
if ($show < $previousMessageCount) {
$show = $previousMessageCount;
}
$from = $show - $previousMessageCount;
if ($from < 0) {
return [];
}
return $this->getMessages($fromUserId, $toUserId, $from, $previousMessageCount, $orderBy);
}
/**
* @param int $fromUserId
* @param int $toUserId
* @param int $start
* @param int $end
* @param string $orderBy
*
* @return array
*/
public function getMessages($fromUserId, $toUserId, $start, $end, $orderBy = '')
{
$toUserId = (int) $toUserId;
$fromUserId = (int) $fromUserId;
$start = (int) $start;
$end = (int) $end;
if (empty($toUserId) || empty($fromUserId)) {
return [];
}
$orderBy = Database::escape_string($orderBy);
if (empty($orderBy)) {
$orderBy = 'ORDER BY id ASC';
}
$sql = "SELECT * FROM ".$this->table."
WHERE
(
to_user = $toUserId AND
from_user = $fromUserId
)
OR
(
from_user = $toUserId AND
to_user = $fromUserId
)
$orderBy
LIMIT $start, $end
";
$result = Database::query($sql);
$rows = Database::store_result($result);
$fromUserInfo = api_get_user_info($fromUserId, true);
$toUserInfo = api_get_user_info($toUserId, true);
$users = [
$fromUserId => $fromUserInfo,
$toUserId => $toUserInfo,
];
$items = [];
$rows = array_reverse($rows);
foreach ($rows as $chat) {
$fromUserId = $chat['from_user'];
$userInfo = $users[$fromUserId];
$toUserInfo = $users[$toUserId];
$items[$chat['id']] = [
'id' => $chat['id'],
'message' => Security::remove_XSS($chat['message']),
'date' => api_strtotime($chat['sent'], 'UTC'),
'recd' => $chat['recd'],
'from_user_info' => $userInfo,
'to_user_info' => $toUserInfo,
];
$_SESSION['openChatBoxes'][$fromUserId] = api_strtotime($chat['sent'], 'UTC');
}
return $items;
}
/**
* Refreshes the chat windows (usually called every x seconds through AJAX).
*/
public function heartbeat()
{
$chatHistory = Session::read('chatHistory');
$currentUserId = api_get_user_id();
// update current chats
if (!empty($chatHistory) && is_array($chatHistory)) {
foreach ($chatHistory as $fromUserId => &$data) {
$userInfo = api_get_user_info($fromUserId, true);
$count = $this->getCountMessagesExchangeBetweenUsers($fromUserId, $currentUserId);
$chatItems = $this->getLatestChat($fromUserId, $currentUserId, 5);
$data['window_user_info'] = $userInfo;
$data['items'] = $chatItems;
$data['total_messages'] = $count;
}
}
$sql = "SELECT * FROM ".$this->table."
WHERE
to_user = '".$currentUserId."' AND recd = 0
ORDER BY id ASC";
$result = Database::query($sql);
$chatList = [];
while ($chat = Database::fetch_array($result, 'ASSOC')) {
$chatList[$chat['from_user']][] = $chat;
}
foreach ($chatList as $fromUserId => $messages) {
$userInfo = api_get_user_info($fromUserId, true);
$count = $this->getCountMessagesExchangeBetweenUsers($fromUserId, $currentUserId);
$chatItems = $this->getLatestChat($fromUserId, $currentUserId, 5);
// Cleaning tsChatBoxes
unset($_SESSION['tsChatBoxes'][$fromUserId]);
foreach ($messages as $chat) {
$_SESSION['openChatBoxes'][$fromUserId] = api_strtotime($chat['sent'], 'UTC');
}
$chatHistory[$fromUserId] = [
'window_user_info' => $userInfo,
'total_messages' => $count,
'items' => $chatItems,
];
}
Session::write('chatHistory', $chatHistory);
$sql = "UPDATE ".$this->table."
SET recd = 1
WHERE to_user = $currentUserId AND recd = 0";
Database::query($sql);
echo json_encode(['items' => $chatHistory]);
}
/**
* Saves into session the fact that a chat window exists with the given user.
*
* @param int $userId
*/
public function saveWindow($userId)
{
$this->window_list[$userId] = true;
Session::write('window_list', $this->window_list);
}
/**
* Sends a message from one user to another user.
*
* @param int $fromUserId The ID of the user sending the message
* @param int $to_user_id The ID of the user receiving the message
* @param string $message Message
* @param bool $printResult Optional. Whether print the result
* @param bool $sanitize Optional. Whether sanitize the message
*/
public function send(
$fromUserId,
$to_user_id,
$message,
$printResult = true,
$sanitize = true
) {
$relation = SocialManager::get_relation_between_contacts($fromUserId, $to_user_id);
if (!Security::check_token('post', null, 'chat')) {
if ($printResult) {
echo '0';
exit;
}
}
if (USER_RELATION_TYPE_FRIEND == $relation) {
$now = api_get_utc_datetime();
$user_info = api_get_user_info($to_user_id, true);
$this->saveWindow($to_user_id);
$_SESSION['openChatBoxes'][$to_user_id] = api_strtotime($now, 'UTC');
if ($sanitize) {
$messagesan = $this->sanitize($message);
} else {
$messagesan = $message;
}
if (!isset($_SESSION['chatHistory'][$to_user_id])) {
$_SESSION['chatHistory'][$to_user_id] = [];
}
$item = [
's' => '1',
'f' => $fromUserId,
'm' => $messagesan,
'date' => api_strtotime($now, 'UTC'),
'username' => get_lang('Me'),
];
$_SESSION['chatHistory'][$to_user_id]['items'][] = $item;
$_SESSION['chatHistory'][$to_user_id]['user_info']['user_name'] = $user_info['complete_name'];
$_SESSION['chatHistory'][$to_user_id]['user_info']['online'] = $user_info['user_is_online'];
$_SESSION['chatHistory'][$to_user_id]['user_info']['avatar'] = $user_info['avatar_small'];
$_SESSION['chatHistory'][$to_user_id]['user_info']['user_id'] = $user_info['user_id'];
unset($_SESSION['tsChatBoxes'][$to_user_id]);
$params = [];
$params['from_user'] = (int) $fromUserId;
$params['to_user'] = (int) $to_user_id;
$params['message'] = $messagesan;
$params['sent'] = api_get_utc_datetime();
if (!empty($fromUserId) && !empty($to_user_id)) {
$messageId = $this->save($params);
if ($printResult) {
header('Content-Type: application/json');
echo json_encode(['id' => $messageId, 'sec_token' => Security::get_token('chat')]);
exit;
}
}
}
if ($printResult) {
echo '0';
exit;
}
}
/**
* Close a specific chat box (user ID taken from $_POST['chatbox']).
*
* @param int $userId
*/
public function closeWindow($userId)
{
if (empty($userId)) {
return false;
}
$list = Session::read('openChatBoxes');
if (isset($list[$userId])) {
unset($list[$userId]);
Session::write('openChatBoxes', $list);
}
$list = Session::read('chatHistory');
if (isset($list[$userId])) {
unset($list[$userId]);
Session::write('chatHistory', $list);
}
return true;
}
/**
* Close chat - disconnects the user.
*/
public function close()
{
Session::erase('tsChatBoxes');
Session::erase('openChatBoxes');
Session::erase('chatHistory');
Session::erase('window_list');
}
/**
* Filter chat messages to avoid XSS or other JS.
*
* @param string $text Unfiltered message
*
* @return string Filtered message
*/
public function sanitize($text)
{
$text = htmlspecialchars($text, ENT_QUOTES);
$text = str_replace("\n\r", "\n", $text);
$text = str_replace("\r\n", "\n", $text);
$text = str_replace("\n", "<br>", $text);
return $text;
}
/**
* SET Disable Chat.
*
* @param bool $status to disable chat
*/
public static function setDisableChat($status = true)
{
Session::write('disable_chat', $status);
}
/**
* Disable Chat - disable the chat.
*
* @return bool - return true if setDisableChat status is true
*/
public static function disableChat()
{
$status = Session::read('disable_chat');
if (!empty($status)) {
if ($status == true) {
Session::write('disable_chat', null);
return true;
}
}
return false;
}
/**
* @return bool
*/
public function isChatBlockedByExercises()
{
$currentExercises = Session::read('current_exercises');
if (!empty($currentExercises)) {
foreach ($currentExercises as $attempt_status) {
if ($attempt_status == true) {
return true;
}
}
}
return false;
}
}

View File

@@ -0,0 +1,44 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Conditional login
* Used to implement the loading of custom pages
* 2011, Noel Dieschburg <noel@cblue.be>.
*/
class ConditionalLogin
{
/**
* Check conditions based in the $login_conditions see conditional_login.php file.
*
* @param array $user
*/
public static function check_conditions($user)
{
$file = api_get_path(SYS_CODE_PATH).'auth/conditional_login/conditional_login.php';
if (file_exists($file)) {
include_once $file;
if (isset($login_conditions)) {
foreach ($login_conditions as $condition) {
//If condition fails we redirect to the URL defined by the condition
if (isset($condition['conditional_function'])) {
$function = $condition['conditional_function'];
$result = $function($user);
if (false == $result) {
$_SESSION['conditional_login']['uid'] = $user['user_id'];
$_SESSION['conditional_login']['can_login'] = false;
header("Location: ".$condition['url']);
exit;
}
}
}
}
}
}
public static function login()
{
$_SESSION['conditional_login']['can_login'] = true;
LoginRedirection::redirect();
}
}

Some files were not shown because too many files have changed in this diff Show More