Actualización

This commit is contained in:
Xes
2025-04-10 12:49:05 +02:00
parent 4aff98e77b
commit 1cdd00920f
9151 changed files with 1800913 additions and 0 deletions

View File

@@ -0,0 +1,90 @@
<?php
/* For licensing terms, see /license.txt */
exit;
/**
* Adds gradebook certificates to gradebook_certificate table from users
* who have achieved the requirements but have not reviewed them yet.
*
* @author Imanol Losada <imanol.losada@beeznest.com>
*/
require_once __DIR__.'/../inc/global.inc.php';
/**
* Get all categories and users ids from gradebook.
*
* @return array Categories and users ids
*/
function getAllCategoriesAndUsers()
{
$table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_RESULT);
$jointable = Database::get_main_table(TABLE_MAIN_GRADEBOOK_EVALUATION);
$joinStatement = ' JOIN '.$jointable.' ON '.$table.'.evaluation_id = '.$jointable.'.id';
return Database::select(
'DISTINCT '.$jointable.'.category_id,'.$table.'.user_id',
$table.$joinStatement
);
}
if ($categoriesAndUsers = getAllCategoriesAndUsers()) {
foreach ($categoriesAndUsers as $categoryAndUser) {
Category::generateUserCertificate(
$categoryAndUser['category_id'],
$categoryAndUser['user_id'],
false,
true
);
}
}
$urlList = [1];
foreach ($urlList as $urlId) {
$_configuration['access_url'] = $urlId;
$sql = "SELECT gc.*
FROM gradebook_category gc
INNER JOIN course c
ON (c.code = gc.course_code)
INNER JOIN access_url_rel_course a
ON (a.c_id = c.id)
WHERE
generate_certificates = 1 AND
parent_id = 0 AND
access_url_id = $urlId
";
$result = Database::query($sql);
$categories = Database::store_result($result);
$total = count($categories);
$counter = 1;
foreach ($categories as $category) {
$courseCode = $category['course_code'];
$sessionId = (int) $category['session_id'];
$filter = STUDENT;
if (!empty($sessionId)) {
$filter = 0;
}
$users = CourseManager::get_user_list_from_course_code(
$courseCode,
$sessionId,
null,
null,
$filter
);
$_SESSION['id_session'] = $sessionId;
echo "Category: ".$category['id']." Course: ".$courseCode." Session: $sessionId - Processing: $counter/".$total.PHP_EOL;
foreach ($users as $user) {
echo "Generating certificate user #".$user['user_id'].PHP_EOL;
Category::generateUserCertificate(
$category['id'],
$user['user_id'],
false,
true
);
}
$counter++;
}
}

View File

@@ -0,0 +1,206 @@
<?php
/* For licensing terms, see /license.txt */
/**
* This script send notification messages to users that have reminders from an event in their agenda.
*/
require_once __DIR__.'/../../main/inc/global.inc.php';
exit;
if (false === api_get_configuration_value('agenda_reminders')) {
exit;
}
$batchCounter = 0;
$batchSize = 100;
$agendaCollectiveInvitations = api_get_configuration_value('agenda_collective_invitations');
$now = new DateTime('now', new DateTimeZone('UTC'));
$em = Database::getManager();
$remindersRepo = $em->getRepository('ChamiloCoreBundle:AgendaReminder');
$reminders = $remindersRepo->findBySent(false);
$senderId = api_get_configuration_value('agenda_reminders_sender_id');
if (empty($senderId)) {
$firstAdmin = current(UserManager::get_all_administrators());
$senderId = $firstAdmin['user_id'];
}
foreach ($reminders as $reminder) {
if ('personal' === $reminder->getType()) {
$event = $em->find('ChamiloCoreBundle:PersonalAgenda', $reminder->getEventId());
if (null === $event) {
continue;
}
$notificationDate = clone $event->getDate();
$notificationDate->sub($reminder->getDateInterval());
if ($notificationDate > $now) {
continue;
}
$eventDetails = [];
$eventDetails[] = '<p><strong>'.$event->getTitle().'</strong></p>';
if ($event->getAllDay()) {
$eventDetails[] = '<p class="small">'.get_lang('AllDay').'</p>';
} else {
$eventDetails[] = sprintf(
'<p class="small">'.get_lang('FromDateX').'</p>',
api_get_local_time($event->getDate(), null, null, false, true, true)
);
if (!empty($event->getEnddate())) {
$eventDetails[] = sprintf(
'<p class="small">'.get_lang('UntilDateX').'</p>',
api_get_local_time($event->getEnddate(), null, null, false, true, true)
);
}
}
if (!empty($event->getText())) {
$eventDetails[] = $event->getText();
}
$messageSubject = sprintf(get_lang('ReminderXEvent'), $event->getTitle());
$messageContent = implode(PHP_EOL, $eventDetails);
MessageManager::send_message_simple(
$event->getUser(),
$messageSubject,
$messageContent,
$event->getUser()
);
if ($agendaCollectiveInvitations) {
$invitees = Agenda::getInviteesForPersonalEvent($reminder->getEventId());
$inviteesIdList = array_column($invitees, 'id');
foreach ($inviteesIdList as $userId) {
MessageManager::send_message_simple(
$userId,
$messageSubject,
$messageContent,
$event->getUser()
);
}
}
}
if ('course' === $reminder->getType()) {
$event = $em->find('ChamiloCourseBundle:CCalendarEvent', $reminder->getEventId());
if (null === $event) {
continue;
}
$agenda = new Agenda('course');
$notificationDate = clone $event->getStartDate();
$notificationDate->sub($reminder->getDateInterval());
if ($notificationDate > $now) {
continue;
}
$eventDetails = [];
$eventDetails[] = '<p><strong>'.$event->getTitle().'</strong></p>';
if ($event->getAllDay()) {
$eventDetails[] = '<p class="small">'.get_lang('AllDay').'</p>';
} else {
$eventDetails[] = sprintf(
'<p class="small">'.get_lang('FromDateX').'</p>',
api_get_local_time($event->getStartDate(), null, null, false, true, true)
);
if (!empty($event->getEndDate())) {
$eventDetails[] = sprintf(
'<p class="small">'.get_lang('UntilDateX').'</p>',
api_get_local_time($event->getEndDate(), null, null, false, true, true)
);
}
}
if (!empty($event->getContent())) {
$eventDetails[] = $event->getContent();
}
if (!empty($event->getComment())) {
$eventDetails[] = '<p class="small">'.$event->getComment().'</p>';
}
$messageSubject = sprintf(get_lang('ReminderXEvent'), $event->getTitle());
$messageContent = implode(PHP_EOL, $eventDetails);
$courseInfo = api_get_course_info_by_id($event->getCId());
$sendTo = $agenda->getUsersAndGroupSubscribedToEvent(
$event->getIid(),
$event->getCId(),
$event->getSessionId()
);
if ($sendTo['everyone']) {
$users = CourseManager::get_user_list_from_course_code($courseInfo['code'], $event->getSessionId());
$userIdList = array_keys($users);
if ($event->getSessionId()) {
$coaches = SessionManager::getCoachesByCourseSession($event->getSessionId(), $event->getCId());
$userIdList += $coaches;
}
foreach ($userIdList as $userId) {
MessageManager::send_message_simple(
$userId,
$messageSubject,
$messageContent,
$senderId
);
}
} else {
foreach ($sendTo['groups'] as $groupId) {
$groupUserList = GroupManager::get_users($groupId, false, null, null, false, $event->getSessionId());
foreach ($groupUserList as $groupUserId) {
MessageManager::send_message_simple(
$groupUserId,
$messageSubject,
$messageContent,
$senderId
);
}
}
foreach ($sendTo['users'] as $userId) {
MessageManager::send_message_simple(
$userId,
$messageSubject,
$messageContent,
$senderId
);
}
}
}
$reminder->setSent(true);
$em->persist($reminder);
$batchCounter++;
if (($batchCounter % $batchSize) === 0) {
$em->flush();
}
}
$em->flush();
$em->clear();

View File

@@ -0,0 +1,161 @@
<?php
/* For licensing terms, see /license.txt */
/**
* This script cleans old records in (mostly) track_e_* and saves them to a
* separate track_e_*_[YYYY] table, with the name of the year in which this
* script is run as a suffix.
* Because we don't know the column that reflects the date of the record in the
* corresponding table (it varies from table to table), we use the time of
* running the script as the suffix to the archive table.
* This script uses the primary key to calculate the ID up to which we want to
* archive records, so if many records have previously been deleted, the
* number of moved records might be considerable inferior to $archiveNumber.
* This script does the following:
* - run through the list of programmed tables to archive
* - check if the archive table exists, otherwise create it
* - gets the lower ID of the original table, adds the threshold and proceeds
* to move all first [$threshold] records to an archive table
* - removes the moved records from the original table
* - writes a log in a local file (see $logFile below)
* To fine-tune it, change the $tables, $threshold and $archiveNumber variables
* below.
*
* @author Yannick Warnier <yannick.warnier@beeznest.com>
*/
if (php_sapi_name() !== 'cli') {
exit("This script must be run from the command-line. Goodbye.\n");
}
require __DIR__.'/../../main/inc/global.inc.php';
ini_set('max_execution_time', 0);
$logFile = __DIR__.'/archive_track_tables_records.log';
// List of tables to be "archived"
$tables = [
'track_e_downloads',
];
// The threshold (number under which nothing must be done). Defaults to 10M
$threshold = 10000000;
// The number of records to be archived
$archiveNumber = 5000000;
// Browse tables and archive some data
foreach ($tables as $table) {
$tableArchive = $table.'_'.date('Y');
if (!checkAndCreateTable($tableArchive, $table)) {
exit("Could not create table $tableArchive. Please check your database user has the CREATE TABLE permission.\n");
}
$sql = "SELECT count(*) FROM $table";
$res = Database::query($sql);
$row = Database::fetch_row($res);
file_put_contents(
$logFile,
"Checking current records in $table (".date('Y-m-d H:i:s').")\n===\n",
FILE_APPEND
);
// If more than 10M registers, move the 10M first registers to a, history table
if ($row[0] > $threshold) {
$pk = getPKFromTable($table);
$sql = "SELECT min($pk) FROM $table";
$res = Database::query($sql);
$row = Database::fetch_row($res);
$min = $row[0];
$max = $min + $archiveNumber;
$sql = "INSERT INTO $tableArchive SELECT * FROM $table WHERE $pk >= $min AND $pk < $max";
file_put_contents(
$logFile,
"Moving rows $min to ".($max - 1)." to $tableArchive. Starting at ".date('Y-m-d H:i:s')."\n",
FILE_APPEND
);
$res = Database::query($sql);
file_put_contents(
$logFile,
"Done moving at ".date('Y-m-d H:i:s')."\n",
FILE_APPEND
);
if ($res !== false) {
$sql = "DELETE FROM $table WHERE $pk < $max";
file_put_contents(
$logFile,
"Deleting rows < $max from $table. Starting at ".date('Y-m-d H:i:s')."\n",
FILE_APPEND
);
$res = Database::query($sql);
file_put_contents(
$logFile,
"Done cleaning up at ".date('Y-m-d H:i:s')."\n",
FILE_APPEND
);
} else {
file_put_contents(
$logFile,
"There was an issue copying the rows to $tableArchive\n[Query: $sql ].\n",
FILE_APPEND
);
}
file_put_contents(
$logFile,
"Table process finished at ".date('Y-m-d H:i:s').".\n",
FILE_APPEND
);
} else {
file_put_contents(
$logFile,
"There are no more than $threshold transactions in $table table. No action taken.\n",
FILE_APPEND
);
}
}
file_put_contents(
$logFile,
"Archiving finished at ".date('Y-m-d H:i:s').". No action taken.\n",
FILE_APPEND
);
/**
* Returns the name of the primary key column for the given table.
*
* @param string $table The name of the table
*
* @return string The column name of the primary key
*/
function getPKFromTable($table)
{
$sql = "SELECT k.column_name
FROM information_schema.table_constraints t
JOIN information_schema.key_column_usage k
USING(constraint_name, table_schema, table_name)
WHERE t.constraint_type = 'PRIMARY KEY'
AND t.table_schema='".api_get_configuration_value('main_database')."'
AND t.table_name='$table'";
$res = Database::query($sql);
if (Database::num_rows($res) > 0) {
$row = Database::fetch_assoc($res);
return $row['column_name'];
}
return '';
}
/**
* Check a table exists and create it if it doesn't.
*
* @param string $table The table to check/create
* @param string $templateTable The model from which this table should be created
*
* @return bool True if it exists *or* it could be created, false if there was an error at create time
*/
function checkAndCreateTable($table, $templateTable)
{
$sqlCheck = "SHOW TABLES LIKE '$table'";
$res = Database::query($sqlCheck);
if (Database::num_rows($res) > 0) {
// The table already exists
return true;
} else {
$sqlCreate = "CREATE TABLE $table like $templateTable";
$res = Database::query($sqlCreate);
return $res;
}
}

View File

@@ -0,0 +1,156 @@
<?php
/* For licensing terms, see /license.txt */
/**
* This script checks and propose a query fix for LP items with high time values
* Only if the total LP time is bigger than the total course time.
*/
exit;
require_once __DIR__.'/../../main/inc/global.inc.php';
api_protect_admin_script();
opcache_reset();
$testSessionId = 182;
$testCourseId = 97;
$max = 10;
$counter = 0;
// Check Sessions
$_configuration['access_url'] = 6;
$sessions = SessionManager::formatSessionsAdminForGrid();
foreach ($sessions as $session) {
$sessionId = $session['id'];
if (!empty($testSessionId)) {
if ($sessionId != $testSessionId) {
continue;
}
}
$courses = SessionManager::getCoursesInSession($sessionId);
foreach ($courses as $courseId) {
if (!empty($testCourseId)) {
if ($testCourseId != $courseId) {
continue;
}
}
$courseInfo = api_get_course_info_by_id($courseId);
$courseCode = $courseInfo['code'];
$users = CourseManager::get_user_list_from_course_code(
$courseCode,
$sessionId,
null,
null,
0
);
foreach ($users as $user) {
$result = compareLpTimeAndCourseTime($user, $courseInfo, $sessionId);
if ($result) {
$counter++;
}
if ($counter > $max) {
break 3;
}
}
}
}
// Courses
/*$courses = CourseManager::get_courses_list();
foreach($courses as $courseInfo) {
$courseCode = $courseInfo['code'];
$courseInfo['real_id'] = $courseInfo['id'];
$users = CourseManager::get_user_list_from_course_code($courseCode);
foreach ($users as $user) {
$userId = $user['id'];
compareLpTimeAndCourseTime($userId, $courseInfo);
}
}*/
/**
* @param array $user
* @param array $courseInfo
* @param int $sessionId
*
* @return bool
*/
function compareLpTimeAndCourseTime($user, $courseInfo, $sessionId = 0)
{
$userId = $user['user_id'];
$defaultValue = 600; // 10 min
$courseCode = $courseInfo['code'];
$courseId = $courseInfo['real_id'];
$totalLpTime = Tracking::get_time_spent_in_lp(
$userId,
$courseCode,
[],
$sessionId
);
if (empty($totalLpTime)) {
return false;
}
$totalCourseTime = Tracking::get_time_spent_on_the_course(
$userId,
$courseId,
$sessionId
);
$content = '';
if ($totalLpTime > $totalCourseTime) {
$totalCourseTimeFormatted = api_time_to_hms($totalCourseTime);
$totalLpTimeFormatted = api_time_to_hms($totalLpTime);
$diff = $totalLpTime - $totalCourseTime;
$content = PHP_EOL."User: ".$user['user_id']." - Total course: $totalCourseTimeFormatted / Total LP: $totalLpTimeFormatted".PHP_EOL;
$content .= PHP_EOL."Diff: ".api_time_to_hms($diff).PHP_EOL;
$url = api_get_path(WEB_CODE_PATH).'mySpace/myStudents.php?student='.$userId.'&course='.$courseCode.'&id_session='.$sessionId;
$content .= Display::url('Check', $url, ['target' => '_blank']);
$content .= PHP_EOL;
// Check possible records with high values
$sql = "SELECT iv.iid, lp_id, total_time
FROM c_lp_view v
INNER JOIN c_lp_item_view iv
ON (iv.c_id = v.c_id AND v.id = iv.lp_view_id)
WHERE
user_id = $userId AND
v.c_id = $courseId AND
session_id = $sessionId
ORDER BY total_time desc
LIMIT 1
";
echo $sql.PHP_EOL;
$result = Database::query($sql);
$results = Database::store_result($result, 'ASSOC');
if (!empty($results)) {
$content .= 'Top 1 high lp item times'.PHP_EOL.PHP_EOL;
foreach ($results as $item) {
$lpId = $item['lp_id'];
$link = api_get_path(WEB_CODE_PATH).'mySpace/lp_tracking.php?cidReq='.$courseCode.
'&course='.$courseCode.'&origin=&lp_id='.$lpId.'&student_id='.$userId.'&id_session='.$sessionId;
$content .= "total_time to be reduced = ".api_time_to_hms($item['total_time']).PHP_EOL;
$content .= Display::url('See report before update', $link, ['target' => '_blank']).PHP_EOL;
$content .= "SQL with possible fix:".PHP_EOL;
if ($item['total_time'] < $defaultValue) {
$content .= "Skip because total_time is too short. total_time: ".$item['total_time'].' value to rest'.$defaultValue.PHP_EOL;
continue;
}
$content .= "UPDATE c_lp_item_view SET total_time = total_time - '$defaultValue' WHERE iid = ".$item['iid'].";".PHP_EOL.PHP_EOL;
}
}
}
echo nl2br($content);
return true;
}
exit;

View File

@@ -0,0 +1,55 @@
<?php
/* For licensing terms, see /license.txt */
require_once __DIR__.'/../inc/global.inc.php';
$file = 'all_session_careers_with_users.csv';
$data = Import::csvToArray($file);
$extraFieldValue = new ExtraFieldValue('session');
$count = 1;
$careerValue = new ExtraFieldValue('career');
foreach ($data as $row) {
echo "Line $count ".PHP_EOL;
$count++;
$users = explode('|', $row['Users']);
$externalCareerIdList = $row['extra_careerid'];
if (substr($externalCareerIdList, 0, 1) === '[') {
$externalCareerIdList = substr($externalCareerIdList, 1, -1);
$externalCareerIds = preg_split('/,/', $externalCareerIdList);
} else {
$externalCareerIds = [$externalCareerIdList];
}
$chamiloCareerList = [];
foreach ($externalCareerIds as $careerId) {
$careerFound = $careerValue->get_item_id_from_field_variable_and_field_value('external_career_id', $careerId);
if ($careerFound && isset($careerFound['item_id'])) {
$chamiloCareerList[] = $careerFound['item_id'];
}
}
if (empty($chamiloCareerList)) {
echo "No career found ".PHP_EOL;
continue;
}
foreach ($users as $username) {
$userInfo = api_get_user_info_from_username($username);
if ($userInfo) {
$userId = $userInfo['user_id'];
foreach ($chamiloCareerList as $careerId) {
if (UserManager::userHasCareer($userId, $careerId)) {
echo "User $username (#$userId) has already the chamilo career # $careerId ".PHP_EOL;
continue;
} else {
//UserManager::addUserCareer($userId, $careerId);
echo "Save career #$careerId to user $username (#$userId) ".PHP_EOL;
}
}
} else {
echo "Username not found: $username ".PHP_EOL;
}
}
}

View File

@@ -0,0 +1,94 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CoreBundle\Entity\Session;
use Chamilo\CourseBundle\Entity\CItemProperty;
require __DIR__.'/../inc/global.inc.php';
if (php_sapi_name() != 'cli') {
exit; //do not run from browser
}
if (!api_get_configuration_value('course_announcement_scheduled_by_date')) {
exit;
}
// Get all pending (visible) announcements where e-mail sent is empty
$dql = "SELECT a
FROM ChamiloCourseBundle:CAnnouncement a
JOIN ChamiloCourseBundle:CItemProperty ip
WITH a.id = ip.ref AND a.cId = ip.course
WHERE
(a.emailSent != 1 OR
a.emailSent IS NULL) AND
ip.tool = '".TOOL_ANNOUNCEMENT."' AND
ip.visibility = 1
ORDER BY a.displayOrder DESC";
$qb = Database::getManager()->createQuery($dql);
$result = $qb->execute();
if (!$result) {
exit;
}
$extraFieldValue = new ExtraFieldValue('course_announcement');
$today = date('Y-m-d');
// For each announcement, check rules about sending the notification at a
// specific date
foreach ($result as $announcement) {
$sendNotification = $extraFieldValue->get_values_by_handler_and_field_variable($announcement->getId(), 'send_notification_at_a_specific_date');
if ($sendNotification['value'] == 1) {
$dateToSend = $extraFieldValue->get_values_by_handler_and_field_variable($announcement->getId(), 'date_to_send_notification');
if ($today >= $dateToSend['value']) {
$query = "SELECT ip FROM ChamiloCourseBundle:CItemProperty ip
WHERE ip.ref = :announcementId
AND ip.course = :courseId
AND ip.tool = '".TOOL_ANNOUNCEMENT."'
ORDER BY ip.iid DESC";
$sql = Database::getManager()->createQuery($query);
$itemProperty = $sql->execute(['announcementId' => $announcement->getId(), 'courseId' => $announcement->getCId()]);
if (empty($itemProperty) or !isset($itemProperty[0])) {
continue;
}
/* @var CItemProperty $itemPropertyObject */
$itemPropertyObject = $itemProperty[0];
// Check if the last record for this announcement was not a removal
if ($itemPropertyObject->getLastEditType() == 'AnnouncementDeleted' or $itemPropertyObject->getVisibility() == 2) {
continue;
}
/* @var Session $sessionObject */
$sessionObject = $itemPropertyObject->getSession();
if (!empty($sessionObject)) {
$sessionId = $sessionObject->getId();
} else {
$sessionId = null;
}
$courseInfo = api_get_course_info_by_id($announcement->getCId());
$senderId = $itemPropertyObject->getInsertUser()->getId();
// Check if we need to send it to all users of all sessions that
// include this course.
$sendToUsersInSession = (int) $extraFieldValue->get_values_by_handler_and_field_variable(
$announcement->getId(),
'send_to_users_in_session'
)['value'];
$messageSentTo = AnnouncementManager::sendEmail(
$courseInfo,
$sessionId,
$announcement->getId(),
$sendToUsersInSession,
false,
null,
$senderId,
false,
true
);
}
}
}

View File

@@ -0,0 +1,89 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CoreBundle\Entity\Session;
/**
* Cron for send a email when the course are finished.
*
* @author Angel Fernando Quiroz Campos <angel.quiroz@beeznest.com>
*/
require_once __DIR__.'/../inc/global.inc.php';
if (php_sapi_name() !== 'cli') {
exit; //do not run from browser
}
$isActive = api_get_setting('cron_remind_course_expiration_activate') === 'true';
if (!$isActive) {
exit;
}
$endDate = new DateTime('now', new DateTimeZone('UTC'));
$endDate = $endDate->format('Y-m-d');
$entityManager = Database::getManager();
$sessionRepo = $entityManager->getRepository('ChamiloCoreBundle:Session');
$accessUrlRepo = $entityManager->getRepository('ChamiloCoreBundle:AccessUrl');
/** @var Session[] $sessions */
$sessions = $sessionRepo->createQueryBuilder('s')
->where('s.accessEndDate LIKE :date')
->setParameter('date', "$endDate%")
->getQuery()
->getResult();
if (empty($sessions)) {
echo "No sessions finishing today $endDate".PHP_EOL;
exit;
}
$administrator = [
'complete_name' => api_get_person_name(
api_get_setting('administratorName'),
api_get_setting('administratorSurname'),
null,
PERSON_NAME_EMAIL_ADDRESS
),
'email' => api_get_setting('emailAdministrator'),
];
foreach ($sessions as $session) {
$sessionUsers = $session->getUsers();
if (empty($sessionUsers)) {
echo 'No users to send mail'.PHP_EOL;
exit;
}
foreach ($sessionUsers as $sessionUser) {
$user = $sessionUser->getUser();
$subjectTemplate = new Template(null, false, false, false, false, false);
$subjectTemplate->assign('session_name', $session->getName());
$subjectLayout = $subjectTemplate->get_template('mail/cron_course_finished_subject.tpl');
$bodyTemplate = new Template(null, false, false, false, false, false);
$bodyTemplate->assign('complete_user_name', UserManager::formatUserFullName($user));
$bodyTemplate->assign('session_name', $session->getName());
$bodyLayout = $bodyTemplate->get_template('mail/cron_course_finished_body.tpl');
api_mail_html(
UserManager::formatUserFullName($user),
$user->getEmail(),
$subjectTemplate->fetch($subjectLayout),
$bodyTemplate->fetch($bodyLayout),
$administrator['complete_name'],
$administrator['email']
);
echo '============'.PHP_EOL;
echo "Email sent to: ".UserManager::formatUserFullName($user)." ({$user->getEmail()})".PHP_EOL;
echo "Session: {$session->getName()}".PHP_EOL;
echo "End date: {$session->getAccessEndDate()->format('Y-m-d h:i')}".PHP_EOL;
}
}

View File

@@ -0,0 +1,214 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Create course sessions procedure. It creates sessions for courses that haven't it yet.
* If today is greater than OFFSET, it will create them also for the next quarter.
*
* @package chamilo.cron
*
* @author Imanol Losada <imanol.losada@beeznest.com>
*/
/**
* Initialization.
*/
if (php_sapi_name() != 'cli') {
exit; //do not run from browser
}
require_once __DIR__."/../inc/global.inc.php";
// First day of the current month to create sessions and add courses for the next month (e.g. "07")
define("OFFSET", "15");
/**
* If no $initialDate is supplied, returns an array with the first and last days of the current
* month. Otherwise, returns an array with the first and last days of the $initialDate month .
*
* @param array $initialDate First day of the month
*
* @return array First and last days of the month
*/
function getMonthFirstAndLastDates($initialDate = null)
{
$startDate = $initialDate ? $initialDate : date("Y-m-01");
$nextMonthStartDate = date("Y-m-d", api_strtotime($startDate." + 1 month"));
$endDate = date("Y-m-d", api_strtotime($nextMonthStartDate." - 1 minute"));
return ['startDate' => $startDate, 'endDate' => $endDate];
}
/**
* Same as month, but for quarters.
*
* @param array $initialDate First day of the quarter
*
* @return array First and last days of the quarter
*/
function getQuarterFirstAndLastDates($initialDate = null)
{
$startDate = $initialDate ? $initialDate : date("Y-m-01");
$month = getQuarterFirstMonth(getQuarter(date('m', $startDate)));
$startDate = substr($startDate, 0, 5).$month.'-01';
$nextQuarterStartDate = date('Y-m-d', api_strtotime($startDate.' + 3 month'));
$endDate = date('Y-m-d', api_strtotime($nextQuarterStartDate.' - 1 minute'));
return ['startDate' => $startDate, 'endDate' => $endDate];
}
/**
* Returns a quarter from a month.
*
* @param string The month (digit), with or without leading 0
* @param string $month
*
* @return int The yearly quarter (1, 2, 3 or 4) in which this month lies
*/
function getQuarter($month)
{
$quarter = 1;
// Remove the leading 0 if any
if (substr($month, 0, 1) == '0') {
$month = substr($month, 1);
}
// reduce to 4 quarters: 1..3=1; 4..6=2
switch ($month) {
case 1:
case 2:
case 3:
$quarter = 1;
break;
case 4:
case 5:
case 6:
$quarter = 2;
break;
case 7:
case 8:
case 9:
$quarter = 3;
break;
case 10:
case 11:
case 12:
$quarter = 4;
break;
}
return $quarter;
}
/**
* Returns the first month of the quarter.
*
* @param int Quarter
* @param int $quarter
*
* @return string Number of the month, with leading 0
*/
function getQuarterFirstMonth($quarter)
{
switch ($quarter) {
case 1:
return '01';
case 2:
return '04';
case 3:
return '07';
case 4:
return '10';
}
return false;
}
/**
* Get the quarter in Roman letters.
*
* @param int Quarter
* @param int $quarter
*
* @return string Roman letters
*/
function getQuarterRoman($quarter)
{
switch ($quarter) {
case 1:
return 'I';
case 2:
return 'II';
case 3:
return 'III';
case 4:
return 'IV';
}
}
/**
* Creates one session per course with $administratorId as the creator and
* adds it to the session starting on $startDate and finishing on $endDate.
*
* @param array $courses Courses
* @param int $administratorId Administrator id
* @param date $startDate First day of the month
* @param date $endDate Last day of the month
*/
function createCourseSessions($courses, $administratorId, $startDate, $endDate)
{
echo "\n";
echo $courses ?
"Creating sessions and adding courses for the period between ".$startDate." and ".$endDate : "Every course is already in session for the period between ".$startDate." and ".$endDate;
echo "\n=====================================================================================\n\n";
// Loop through courses creating one session per each and adding them
foreach ($courses as $course) {
//$period = date("m/Y", api_strtotime($startDate));
$month = date("m", api_strtotime($startDate));
$year = date("Y", api_strtotime($startDate));
$quarter = getQuarter($month);
$quarter = getQuarterRoman($quarter);
$period = $year.'-'.$quarter;
$sessionName = '['.$period.'] '.$course['title'];
$sessionId = SessionManager::create_session(
$sessionName,
$startDate,
$endDate,
null,
null,
null,
null,
$administratorId,
0,
SESSION_INVISIBLE
);
SessionManager::add_courses_to_session($sessionId, [$course['id']]);
echo "Session '".$sessionName."' created.\nCourse '".$course['title']."' added.\n\n";
}
}
// Starts the script
echo "Starting process...".PHP_EOL;
// Get first active administrator
$administrators = array_reverse(UserManager::get_all_administrators());
$lastingAdministrators = count($administrators);
while (!$administrators[$lastingAdministrators - 1]['active'] && $lastingAdministrators > 0) {
$lastingAdministrators--;
}
if (!$lastingAdministrators) {
echo "There are no active administrators. Process halted.\n";
exit;
}
$administratorId = intval($administrators[$lastingAdministrators - 1]['user_id']);
// Creates course sessions for the current month
$dates = getQuarterFirstAndLastDates(date('Y-m-').'01');
// Get courses that don't have any session
$courses = CourseManager::getCoursesWithoutSession($dates['startDate'], $dates['endDate']);
createCourseSessions($courses, $administratorId, $dates['startDate'], $dates['endDate']);
// Creates course sessions for the following month
$offsetDay = intval(substr($dates['endDate'], 8, 2)) - OFFSET;
if (date("Y-m-d") >= date(substr($dates['endDate'], 0, 8).$offsetDay)) {
$dates = getQuarterFirstAndLastDates(date("Y-m-d", api_strtotime(date("Y-m-01")." + 3 month")));
// Get courses that don't have any session the next month
$courses = CourseManager::getCoursesWithoutSession($dates['startDate'], $dates['endDate']);
createCourseSessions($courses, $administratorId, $dates['startDate'], $dates['endDate']);
}

View File

@@ -0,0 +1,26 @@
<?php
/**
* Script to find a document with a specific title or path in all courses.
*/
/**
* Code init - comment die() call to enable.
*/
exit();
require '../../inc/global.inc.php';
if (empty($_GET['doc'])) {
echo "To add a document name to search, add ?doc=abc to the URL";
} else {
echo "Received param ".Security::remove_XSS($_GET['doc'])."<br />";
}
$courses_list = CourseManager::get_courses_list();
foreach ($courses_list as $course) {
$title = Database::escape_string($_GET['doc']);
$td = Database::get_course_table(TABLE_DOCUMENT);
$sql = "SELECT id, path FROM $td WHERE c_id = ".$course['id']." AND path LIKE '%$title%' OR title LIKE '%$title%'";
$res = Database::query($sql);
if (Database::num_rows($res) > 0) {
while ($row = Database::fetch_array($res)) {
echo "Found doc ".$row['id']."-> ".$row['path']." in course ".$course['code']."<br />";
}
}
}

View File

@@ -0,0 +1,69 @@
<?php
/**
* Script to find a document with a specific title or path in all courses.
*/
/**
* Code init - comment die() call to enable.
*/
exit();
require '../../inc/global.inc.php';
if (empty($_GET['doc'])) {
echo "To add a document name to search, add ?doc=abc to the URL\n";
} else {
echo "Received param ".$_GET['doc']."<br />\n";
}
$allowed_mime_types = DocumentManager::file_get_mime_type(true);
$allowed_extensions = [
'doc',
'docx',
'ppt',
'pptx',
'pps',
'ppsx',
'xls',
'xlsx',
'odt',
'odp',
'ods',
'pdf',
'txt',
'rtf',
'msg',
'csv',
'html',
'htm',
];
$courses_list = CourseManager::get_courses_list();
// Simulating empty specific fields (this is necessary for indexing)
require_once api_get_path(LIBRARY_PATH).'specific_fields_manager.lib.php';
$specific_fields = get_specific_field_list();
$specific_fields_values = [];
foreach ($specific_fields as $sf) {
$specific_fields_values[$sf['code']] = '';
}
$td = Database::get_course_table(TABLE_DOCUMENT);
foreach ($courses_list as $course) {
$course_dir = $course['directory'].'/document';
$title = Database::escape_string($_GET['doc']);
$sql = "SELECT id, path, session_id FROM $td WHERE c_id = ".$course['id']." AND path LIKE '%$title%' or title LIKE '%$title%'";
$res = Database::query($sql);
if (Database::num_rows($res) > 0) {
while ($row = Database::fetch_array($res)) {
$doc_path = api_get_path(SYS_COURSE_PATH).$course_dir.$row['path'];
$extensions = preg_split("/[\/\\.]/", $doc_path);
$doc_ext = strtolower($extensions[count($extensions) - 1]);
if (in_array($doc_ext, $allowed_extensions) && !is_dir($doc_path)) {
$doc_mime = mime_content_type($doc_path);
echo "Indexing doc ".$row['id']." (".$row['path'].") in course ".$course['code']."\n";
$residx = DocumentManager::index_document($row['id'], $course['code'], $row['session_id'], $course['course_language'], $specific_fields_values);
if ($residx) {
echo "Success\n";
} else {
echo "Failure\n";
}
}
}
}
}

View File

@@ -0,0 +1,75 @@
<?php
/* For licensing terms, see /license.txt */
/**
* This script checks and updates (if you uncomment the query)
* the records in track_e_course_access that is used to calculate the
* total course time.
*/
require_once __DIR__.'/../../main/inc/global.inc.php';
exit;
opcache_reset();
$maxSeconds = 10 * 60 * 60; // Check records higher than 7 hours
$addSecondsToLogin = 2 * 60 * 60; // Update this abusive records with 3 hours
$limit = 10; // Only fix first 10
$sendMessage = true;
$userId = 868; // User id that will receive a report
$update = false;
$sql = "SELECT
course_access_id,
counter,
UNIX_TIMESTAMP(logout_course_date) - UNIX_TIMESTAMP(login_course_date) diff,
login_course_date,
logout_course_date
FROM track_e_course_access
WHERE UNIX_TIMESTAMP(logout_course_date) > UNIX_TIMESTAMP(login_course_date)
ORDER by diff DESC
LIMIT $limit
";
$result = Database::query($sql);
$log = '';
while ($row = Database::fetch_array($result)) {
if ($row['diff'] >= $maxSeconds) {
$id = $row['course_access_id'];
$loginDate = $row['login_course_date'];
$logoutDate = $row['logout_course_date'];
$diff = round($row['diff'] / 60 / 60);
$login = api_strtotime($row['login_course_date'], 'UTC') + $addSecondsToLogin;
$newLogout = api_get_utc_datetime($login);
$sql = "UPDATE track_e_course_access
SET logout_course_date = '$newLogout'
WHERE course_access_id = $id ;
";
// Uncomment to fix
if ($update) {
Database::query($sql);
}
$report = "Login : $loginDate ";
$report .= PHP_EOL;
$report .= "Logout: $logoutDate Diff in hours: $diff";
$report .= PHP_EOL;
$report .= $sql;
$report .= PHP_EOL;
$report .= PHP_EOL;
$log .= $report;
echo $report;
}
}
if ($sendMessage && !empty($log)) {
$log = nl2br($log);
MessageManager::send_message_simple(
$userId,
'Course time spent fixes',
$log,
1
);
}

View File

@@ -0,0 +1,79 @@
<?php
/* For licensing terms, see /license.txt */
require_once __DIR__.'/../inc/global.inc.php';
api_protect_admin_script();
$table = Database::get_course_table(TABLE_QUIZ_ANSWER);
$execute = isset($_GET['execute']) ? $_GET['execute'] : null;
$courseId = isset($_GET['c_id']) ? $_GET['c_id'] : null;
$questionId = isset($_GET['question_id']) ? $_GET['question_id'] : null;
$sql2 = "SELECT * FROM $table WHERE answer LIKE '%[%]%'";
if (!empty($courseId)) {
$courseId = intval($courseId);
$sql2 .= " AND c_id = $courseId";
if (!empty($questionId)) {
$questionId = intval($questionId);
$sql2 .= " AND question_id = $questionId";
}
}
var_dump($sql2);
$res2 = Database::query($sql2);
while ($row = Database::fetch_array($res2)) {
$id = $row['iid'];
$courseId = $row['c_id'];
$idAuto = $row['id_auto'];
$answerOriginal = $row['answer'];
$answer = $row['answer'];
$answer = str_replace('â', '&acirc;', $answer);
$answer = str_replace('à', '&agrave;', $answer);
$answer = str_replace('é', '&eacute;', $answer);
$answer = str_replace('ê', '&ecirc;', $answer);
$answer = str_replace('è', '&egrave;', $answer);
$answer = str_replace('í', '&iacute;', $answer);
$answer = str_replace('ì', '&igrave;', $answer);
$answer = str_replace('ó', '&oacute;', $answer);
$answer = str_replace('ò', '&ograve;', $answer);
$answer = str_replace('ù', '&ugrave;', $answer);
$answer = str_replace('ú', '&uacute', $answer);
$answer = str_replace('ç', '&ccedil;', $answer);
$answer = str_replace('À', '&Agrave;', $answer);
$answer = str_replace('Ç', '&Ccedil;', $answer);
$answerFixedNotEscape = $answer;
$answer = Database::escape_string($answer);
$sql4 = "UPDATE c_quiz_answer SET
answer = '$answer'
WHERE id = $id AND c_id = $courseId AND id_auto = $idAuto ";
if ($answerOriginal != $answerFixedNotEscape) {
if (!empty($execute) && $execute == 1) {
Database::query($sql4);
echo '<pre>';
var_dump($sql4);
echo '</pre>';
var_dump('executed');
} else {
echo "to be executed";
echo '<pre>';
var_dump($sql4);
echo 'Original:<br />';
echo $answerOriginal;
echo 'Fixed:<br />';
echo $answerFixedNotEscape;
echo '</pre>';
echo '----------<br />';
}
}
}

View File

@@ -0,0 +1,58 @@
<?php
/* For licensing terms, see /license.txt */
/**
* This script checks that the c_lp_item_view.total_time field
* doesn't have big values. The scripts updates it or send a message to the admin (depending the settings).
*/
exit;
require_once __DIR__.'/../../main/inc/global.inc.php';
opcache_reset();
$maxSeconds = 5 * 60 * 60; // Check records higher than 5 hours
$valueToUpdate = 1 * 60 * 60; // Update this abusive records with 1 hours
$limit = 10; // Only fix first 10
$sendMessage = true;
$userId = 1; // User id that will receive a report
$update = false;
$sql = "SELECT iid, total_time FROM c_lp_item_view
WHERE total_time > $maxSeconds
order by total_time desc
LIMIT $limit
";
$result = Database::query($sql);
$log = '';
while ($row = Database::fetch_array($result, 'ASSOC')) {
$id = $row['iid'];
$oldTotalTime = $row['total_time'];
$sql = "UPDATE c_lp_item_view SET total_time = '$valueToUpdate' WHERE iid = $id;";
// Uncomment to fix
if ($update) {
Database::query($sql);
}
$oldTotalTime = round($oldTotalTime / 3600, 2);
$report = "Previous total_time : ".$oldTotalTime." hours";
$report .= PHP_EOL;
$report .= "New total_time: $valueToUpdate";
$report .= PHP_EOL;
$report .= $sql;
$report .= PHP_EOL;
$report .= PHP_EOL;
$log .= $report;
echo $report;
}
if ($sendMessage && !empty($log)) {
$log = nl2br($log);
MessageManager::send_message_simple(
$userId,
'LP time abusive fixes',
$log,
1
);
}

View File

@@ -0,0 +1,151 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Automatic fix online time procedure. If a user has been idle for $timeLimit
* or more then the procedure adds $extraTime to his logout_course_date.
*
* How to use it:
*
* By default the script will fix only users with teacher status (COURSEMANAGER)
*
* php main/cron/fix_online_time.php
*
* If you want to add an specific status you can call the file with:
*
* php main/cron/fix_online_time.php status=5
*
* Where "5" is the value of the 'STUDENT' constant.
*
* @package chamilo.cron
*
* @author Imanol Losada <imanol.losada@beeznest.com>
* @author Julio Montoya
*/
require_once __DIR__.'/../inc/global.inc.php';
if (php_sapi_name() != 'cli') {
exit; //do not run from browser
}
/**
* Get ids of users that are inside a course right now.
*
* @param int $status COURSEMANAGER|STUDENT constants
*
* @return array user id
*/
function getUsersInCourseIds($status)
{
$status = (int) $status;
$table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ONLINE);
$joinStatement = ' JOIN '.Database::get_main_table(TABLE_MAIN_USER).' ON login_user_id = user_id';
return Database::select(
'login_user_id',
$table.$joinStatement,
[
'where' => [
'c_id IS NOT NULL AND status = ?' => [
$status,
],
],
]
);
}
/**
* If a user has been idle for $timeLimit or more then
* the procedure adds $extraTime to his logout_course_date.
*
* @param array $users user id list
*
* @return int
*/
function updateUsersInCourseIdleForTimeLimit($users)
{
$timeLimit = '- 30 minute';
$extraTime = '+ 5 minute';
$utcResult = Database::fetch_array(Database::query('SELECT UTC_TIMESTAMP'));
$dataBaseCurrentHour = array_shift($utcResult);
$maximumIdleTimeInCourse = date(
'Y-m-d H:i:s',
strtotime($dataBaseCurrentHour.' '.$timeLimit)
);
$table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
$onLineTrackTable = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ONLINE);
$count = 1;
foreach ($users as $key => $value) {
$value = array_shift($value);
$logResult = Database::select(
'course_access_id, logout_course_date',
$table,
[
'where' => [
'user_id = ?' => [
$value,
],
],
'order' => 'course_access_id DESC',
'limit' => '1',
]
);
$currentTeacherData = array_shift($logResult);
Database::update(
$table,
[
'logout_course_date' => date(
'Y-m-d H:i:s',
strtotime($currentTeacherData['logout_course_date'].' '.$extraTime)
),
],
[
'user_id = ? AND logout_course_date < ? AND course_access_id = ?' => [
$value,
$maximumIdleTimeInCourse,
$currentTeacherData['course_access_id'],
],
]
);
/*
* (Avoid multiple updates)
* When the user enters a course, this field is updated with the course code.
* And when the user goes to another tool, returns to NULL
*/
$userId = intval($value);
$sql = "UPDATE $onLineTrackTable
SET c_id = NULL
WHERE login_user_id = $userId";
Database::query($sql);
$count++;
}
return $count;
}
// Default status when running script
$status = COURSEMANAGER;
if (!empty($argv) && isset($argv[1])) {
// Get status from parameter
parse_str($argv[1], $params);
if (isset($params['status'])) {
$status = (int) $params['status'];
}
}
$statusToString = api_get_status_langvars();
if (isset($statusToString[$status])) {
echo "Fixing users with status: '$status' = ".$statusToString[$status].PHP_EOL;
} else {
echo "User status not '$status' not found. Try with status=1 or status=5";
exit;
}
$users = getUsersInCourseIds($status);
if (!empty($users)) {
$result = updateUsersInCourseIdleForTimeLimit($users);
echo "# users updated: $result".PHP_EOL;
} else {
echo "Nothing to update. No users found to be fixed.".PHP_EOL;
}

View File

@@ -0,0 +1,140 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Script to send notification to course's teachers when there are activities in a thread of a forum in his courses in the last X days
* The number of days is defined at the begining of the script with the variable
* It will send one sigle mail per user to notify with a line for each thread including thread's title, thread link and number of new post.
*
* @package chamilo.cron
*/
//This variable define the number of days in the past to look for activies in the forums
//This variable should be the same as the periodicity of the cron (if the cron is every day, then the variable should be equal to 1)
$numberOfDaysForLastActivy = 1;
require_once __DIR__.'/../inc/global.inc.php';
/**
* Initialization.
*/
if ('cli' != php_sapi_name()) {
exit; //do not run from browser
}
$date = new DateTime('now', new DateTimeZone('UTC'));
$date->modify("-$numberOfDaysForLastActivy day");
$startDate = $date->format('Y-m-d H:i:s');
$tablePost = Database::get_course_table(TABLE_FORUM_POST);
$tableThread = Database::get_course_table(TABLE_FORUM_THREAD);
$UpdatedThreads = [];
$sql = "SELECT * FROM $tableThread WHERE thread_date > '".$startDate."'";
$result = Database::query($sql);
while ($row = Database::fetch_array($result)) {
$courseInfo = api_get_course_info_by_id($row['c_id']);
$updatedThreads[$row['c_id']]['courseName'] = $courseInfo['name'];
$sqlNbPost = "SELECT count(*) as nbPost FROM $tablePost WHERE thread_id = '".$row['iid']."' and post_date > '".$startDate."'";
$resultNbPost = Database::query($sqlNbPost);
$rowNbPost = Database::fetch_array($resultNbPost);
$updatedThreads[$row['c_id']][$row['session_id']][$row['iid']] = [
'threadTitle' => $row['thread_title'],
'threadNbPost' => $rowNbPost['nbPost'],
'threadLink' => api_get_path(WEB_PATH).'main/forum/viewthread.php?cidReq='.$courseInfo['code'].'&id_session='.$row['session_id'].'&gidReq=0&gradebook=0&origin=&forum='.$row['forum_id'].'&thread='.$row['iid'],
];
}
foreach ($updatedThreads as $courseId => $sessions) {
foreach ($sessions as $sessionId => $threads) {
if ($sessionId === 0) {
$teacherList = CourseManager::getTeachersFromCourse($courseId, false);
foreach ($teacherList as $teacher) {
$usersToNotify[$teacher['id']][$courseId]['courseName'] = $sessions['courseName'];
$usersToNotify[$teacher['id']][$courseId][$sessionId] = $threads;
}
} else {
$courseCoachs = CourseManager::get_coachs_from_course(
$sessionId,
$courseId,
false
);
foreach ($courseCoachs as $coach) {
$usersToNotify[$coach['user_id']][$courseId]['courseName'] = $sessions['courseName'];
$usersToNotify[$coach['user_id']][$courseId][$sessionId] = $threads;
}
}
}
}
foreach ($usersToNotify as $userId => $notifyInfo) {
sendMessage($userId, $notifyInfo);
}
/**
* Send the message to notify the specific user for all its courses and threads that have been updated,
* manage the corresponding template and send through MessageManager::send_message_simple.
*
* @param $toUserId
* @param $notifyInfo
*
* @return bool|int
*/
function sendMessage(
$toUserId,
$notifyInfo
) {
$userInfo = api_get_user_info($toUserId);
$language = $userInfo['language'];
$subject = getUserLang('ForumBulkNotificationMailSubject', $language);
$bodyTemplate = new Template(
null,
false,
false,
false,
false,
false
);
$userFullName = api_get_person_name($userInfo['firstname'], $userInfo['lastname']);
$bodyTemplate->assign('HelloX', sprintf(getUserLang('HelloX', $language), $userFullName));
$bodyTemplate->assign('NotificationInYouForums', sprintf(getUserLang('NotificationInYouForums', $language)));
$bodyTemplate->assign('SignatureFormula', sprintf(getUserLang('SignatureFormula', $language)));
$bodyTemplate->assign('notifyInfo', $notifyInfo);
$bodyLayout = $bodyTemplate->get_template(
'mail/cron_forum_update_bulk_notification_body.tpl'
);
$content = $bodyTemplate->fetch($bodyLayout);
return MessageManager::send_message_simple(
$toUserId,
$subject,
$content,
1
);
}
/**
* Returns a translated (localized) string by user language.
*
* @param $variable
* @param $language
*
* @return mixed
*/
function getUserLang($variable, $language)
{
$languageFilesToLoad = api_get_language_files_to_load($language);
foreach ($languageFilesToLoad as $languageFile) {
include $languageFile;
}
$translate = $variable;
if (isset($$variable)) {
$langVariable = $$variable;
$translate = $langVariable;
}
return $translate;
}
exit();

View File

@@ -0,0 +1,119 @@
<?php
/* For licensing terms, see /license.txt */
require_once __DIR__.'/../inc/global.inc.php';
/**
* Checks total platform size.
*
* @param bool $debug
*
* @return bool
*/
function isTotalPortalSizeBiggerThanLimit($debug = true)
{
$sizeLimit = api_get_configuration_value('hosting_total_size_limit');
if (empty($sizeLimit)) {
return true;
}
$updateFile = true;
$file = api_get_path(SYS_COURSE_PATH).'hosting_total_size.php';
// Default data
$hostingData = [
'frequency' => 86400,
];
$log = null;
// Check if file exists and if it is updated
if (file_exists($file)) {
$hostingDataFromFile = require $file;
// Check time() is UTC
if (isset($hostingDataFromFile['updated_at']) &&
isset($hostingDataFromFile['frequency']) &&
isset($hostingDataFromFile['size'])
) {
$hostingData = $hostingDataFromFile;
$time = $hostingData['updated_at'] + $hostingData['frequency'];
$diff = $time - time();
if ($time > time()) {
$log .= "You need to wait $diff seconds to update the file \n";
$updateFile = false;
}
}
}
// Now get values for total portal size
$log .= "Frequency loaded: ".$hostingData['frequency']."\n";
if ($updateFile) {
$log .= "Updating total size ... \n";
$totalSize = calculateTotalPortalSize($debug);
$log .= "Total size calculated: $totalSize \n";
$hostingData['updated_at'] = time();
$hostingData['size'] = $totalSize;
$writer = new Zend\Config\Writer\PhpArray();
$phpCode = $writer->toString($hostingData);
file_put_contents($file, $phpCode);
$log .= "File saved in $file \n";
} else {
$log .= "Total size not updated \n";
$totalSize = $hostingData['size'];
}
$result = true;
if ($totalSize > $sizeLimit) {
$log .= "Current total size of $totalSize MB is bigger than limit: $sizeLimit MB \n";
$result = false;
}
if ($debug) {
echo $log;
}
return $result;
}
/**
* @param bool $debug
*
* @return int total size in MB
*/
function calculateTotalPortalSize($debug)
{
$table = Database::get_course_table(TABLE_DOCUMENT);
// Documents
$sql = "SELECT SUM(size) total FROM $table
WHERE filetype = 'file' AND c_id <> ''";
$result = Database::query($sql);
$row = Database::fetch_array($result, 'ASSOC');
$totalSize = $row['total'];
if ($debug) {
echo "Total size in table $table ".(round($totalSize / 1024))." MB \n";
}
$table = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
$sql = "SELECT SUM(size) total FROM $table WHERE c_id <> ''";
$result = Database::query($sql);
$row = Database::fetch_array($result, 'ASSOC');
$subTotal = $row['total'];
$totalSize += $subTotal;
if ($debug) {
echo "Total size in table $table ".(round($subTotal / 1024))." MB \n";
}
$totalSize = $totalSize / 1024;
return $totalSize;
}
isTotalPortalSizeBiggerThanLimit(true);

3729
main/cron/import_csv.php Normal file

File diff suppressed because it is too large Load Diff

5
main/cron/index.html Normal file
View File

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

View File

@@ -0,0 +1,43 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Script to check that no language file has parse errors.
*
* @package chamilo.cron.lang
*/
/**
* Includes and declarations.
*/
//die();
require_once '../../inc/global.inc.php';
$path = api_get_path(SYS_LANG_PATH).'english';
ini_set('memory_limit', '128M');
/**
* Main code.
*/
$terms = [];
$list = SubLanguageManager::get_lang_folder_files_list($path);
$langs = scandir(api_get_path(SYS_LANG_PATH));
foreach ($langs as $lang) {
$dir = api_get_path(SYS_LANG_PATH).$lang;
if (is_dir($dir) && substr($lang, 0, 1) != '.' && !empty($lang)) {
echo "$lang...";
$ok = true;
foreach ($list as $entry) {
$file = $dir.'/'.$entry;
$out = [];
if (is_file($file)) {
//$terms = array_merge($terms,SubLanguageManager::get_all_language_variable_in_file($file,true));
@exec('php -l '.$file, $out);
if (substr($out[0], 0, 2) != 'No') {
echo $out[0]."\n";
$ok = false;
}
}
}
if ($ok) {
echo "OK\n";
}
}
}
echo "Done\n";

View File

@@ -0,0 +1,217 @@
<?php
/* For licensing terms, see /license.txt */
/**
* This class takes the creation and querying of an SQLite DB in charge. The
* goal of this DB is to get stats on the usage of language vars for a common
* user.
*
* @package chamilo.cron.lang
*/
/**
* This class takes the creation and querying of an SQLite DB in charge. The
* goal of this DB is to get stats on the usage of language vars for a common
* user. This class requires the SQLite extension of PHP to be installed. The
* check for the availability of sqlite_open() should be made before calling
* the constructor (preferably).
*/
class langstats
{
public $db; //database connector
public $error; //stored errors
public $db_type = 'sqlite';
public function __construct($file = '')
{
switch ($this->db_type) {
case 'sqlite':
if (!class_exists('SQLite3')) {
$this->error = 'SQLiteNotAvailable';
return false; //cannot use if sqlite not installed
}
if (empty($file)) {
$file = api_get_path(SYS_ARCHIVE_PATH).'/langstasdb';
}
if (is_file($file) && is_writeable($file)) {
$this->db = new SQLite3($file, SQLITE3_OPEN_READWRITE);
} else {
try {
$this->db = new SQLite3($file);
} catch (Exception $e) {
$this->error = 'DatabaseCreateError';
error_log('Exception: '.$e->getMessage());
return false;
}
$err = $this->db->exec(
'CREATE TABLE lang_freq ('
.' id integer PRIMARY KEY AUTOINCREMENT, ' //autoincrement in SQLITE
.' term_name text, term_file text, term_count integer default 0)'
);
if ($err === false) {
$this->error = 'CouldNotCreateTable';
return false;
}
$err = $this->db->exec(
'CREATE INDEX lang_freq_terms_idx ON lang_freq(term_name, term_file)'
);
if ($err === false) {
$this->error = 'CouldNotCreateIndex';
return false;
}
// Table and index created, move on.
}
break;
case 'mysql': //implementation not finished
if (!function_exists('mysql_connect')) {
$this->error = 'SQLiteNotAvailable';
return false; //cannot use if sqlite not installed
}
$err = Database::query('SELECT * FROM lang_freq');
if ($err === false) { //the database probably does not exist, create it
$err = Database::query(
'CREATE TABLE lang_freq ('
.' id int PRIMARY KEY AUTO_INCREMENT, '
.' term_name text, term_file text default \'\', term_count int default 0)'
);
if ($err === false) {
$this->error = 'CouldNotCreateTable';
return false;
}
} // if no error, we assume the table exists
break;
}
return $this->db;
}
/**
* Add a count for a specific term.
*
* @param string The language term used
* @param string The file from which the language term came from
*
* @return mixed
*/
public function add_use($term, $term_file = '')
{
$term = $this->db->escapeString($term);
$term_file = $this->db->escapeString($term_file);
$sql = "SELECT id, term_name, term_file, term_count FROM lang_freq WHERE term_name='$term' and term_file='$term_file'";
$ress = $this->db->query($sql);
if ($ress === false) {
$this->error = 'CouldNotQueryTermFromTable';
return false;
}
$i = 0;
while ($row = $ress->fetchArray(SQLITE3_BOTH)) {
$num = $row[3];
$num++;
$i++;
$res = $this->db->query(
'UPDATE lang_freq SET term_count = '.$num.' WHERE id = '.$row[0]
);
if ($res === false) {
$this->error = 'CouldNotUpdateTerm';
return false;
} else {
return $row[0];
}
}
if ($i == 0) {
//No term found in the table, register as new term
$resi = $this->db->query(
"INSERT INTO lang_freq(term_name, term_file, term_count) VALUES ('$term', '$term_file', 1)"
);
if ($resi === false) {
$this->error = 'CouldNotInsertRow';
return false;
} else {
return $this->db->lastInsertRowID();
}
}
return true;
}
/**
* Function to get a list of the X most-requested terms.
*
* @param int Limit of terms to show
*
* @return array List of most requested terms
*/
public function get_popular_terms($num = 1000)
{
$num = (int) $num;
$res = $this->db->query(
'SELECT * FROM lang_freq
ORDER BY term_count DESC LIMIT '.$num
);
$list = [];
while ($row = $res->fetchArray()) {
$list[] = $row;
}
return $list;
}
/**
* Clear all records in lang_freq.
*
* @return resource true
*/
public function clear_all()
{
$res = sqlite_query($this->db, 'DELETE FROM lang_freq WHERE 1=1');
return $res;
}
/**
* Returns an array of all the language variables with their corresponding
* file of origin. This function tolerates a certain rate of error due to
* the duplication of variables in language files.
*
* @return array variable => origin file
*/
public function get_variables_origin()
{
$path = api_get_path(SYS_LANG_PATH).'english/';
$vars = [];
$priority = ['trad4all'];
foreach ($priority as $file) {
$list = SubLanguageManager::get_all_language_variable_in_file(
$path.$file.'.inc.php',
true
);
foreach ($list as $var => $trad) {
$vars[$var] = $file.'.inc.php';
}
}
$files = scandir($path);
foreach ($files as $file) {
if (substr($file, 0, 1) == '.' or in_array($file, $priority)) {
continue;
}
$list = SubLanguageManager::get_all_language_variable_in_file(
$path.$file,
true
);
foreach ($list as $var => $trad) {
$vars[$var] = $file;
}
}
return $vars;
}
}

View File

@@ -0,0 +1,84 @@
<?php
/* For licensing terms, see /license.txt */
/**
* This script prints a list of most used language terms. The registration of
* frequency for language variables is a very heavy operation.
* To enable, add "$_configuration['language_measure_frequency' ] = 1;" at the
* end of main/inc/conf/configuration.php. Remove when done.
* Add ?output=1 to the URL to generate languag files in /tmp/lang/ with just
* the number of terms you want.
*/
/**
* Requires.
*/
exit();
require_once '../../inc/global.inc.php';
require_once 'langstats.class.php';
/**
* Init.
*/
$terms_limit = 10000 + 50;
$x_most_popular = 2000;
$output = false;
$ls = new langstats();
if ($ls === false) {
exit($ls->error);
}
$list = $ls->get_popular_terms($x_most_popular);
if ($_GET['output'] == 1) {
$output = true;
$variables_origin = $ls->get_variables_origin();
}
/**
* Display.
*/
if (count($list) == 0) {
echo 'No terms loaded so far';
}
if (count($list) > 0) {
$i = 1;
$j = 1;
$k = 0;
$files = [];
$trans = [];
echo 'Number of records: '.count($list).'<br />';
echo '<table><tr><th>Index</th><th>Registration order</th><th>Term</th>'.($output == 1 ? '<th>Origin</th>' : '').'<th>Count</th></tr>';
foreach ($list as $elem) {
if ($k > $terms_limit) {
break;
}
$fixed_elem = $elem;
if ($output) {
if (empty($variables_origin[$elem['term_name']]) && !empty($variables_origin['lang'.$elem['term_name']])) {
$fixed_elem = ['id' => $elem['id'], 'term_name' => 'lang'.$elem['term_name'], 'term_count' => $elem['term_count']];
}
if (empty($variables_origin[$fixed_elem['term_name']])) {
continue;
}
$files[$variables_origin[$fixed_elem['term_name']]][] = $fixed_elem['term_name'];
$translation = get_lang($fixed_elem['term_name']);
$k += str_word_count($translation);
$trans[$fixed_elem['term_name']] = $translation;
$j++;
}
echo '<tr><td>', $i,
'</td><td>', $fixed_elem['id'],
'</td><td>', $fixed_elem['term_name'];
if ($output) {
echo '</td><td>'.$variables_origin[$fixed_elem['term_name']];
}
echo '</td><td>', $fixed_elem['term_count'], '</td></tr>';
$i++;
}
echo '</table>';
if ($output) {
@mkdir('/tmp/lang');
foreach ($files as $file => $terms) {
@touch('/tmp/lang/'.$file);
file_put_contents('/tmp/lang/'.$file, "<?php".PHP_EOL);
foreach ($terms as $term) {
file_put_contents('/tmp/lang/'.$file, '$'.$term.' = "'.str_replace('"', '\"', $trans[$term]).'";'.PHP_EOL, FILE_APPEND);
}
}
}
}

View File

@@ -0,0 +1,104 @@
<?php
/* For licensing terms, see /license.txt */
/**
* This script generates a directory based on the English language variables
* but only composed of the 10,000 (can be configured) most frequent words
* used in Chamilo. This implies first using the langstats.php script, which
* in turn implies configuring an additional variable in configuration.php
* (see langstats.php for more info).
* When running the language_builder, please make sure this parameter is
* set to 0 in the configuration.php file, otherwise it will take *ages*.
*/
require_once '../../inc/global.inc.php';
require_once 'langstats.class.php';
global $_configuration;
$_configuration['language_measure_frequency'] = 0;
$langstats = new langstats();
$orig_lang = 'english';
/**
* Init.
*/
$words_limit = 10000; //change this if you want more words
$terms_limit = 3000; //change this if you think you'll need more terms
$terms = $langstats->get_popular_terms($terms_limit);
$words_counter = 0;
$i = 0;
$terms_in_limit = [];
$lang_dir = api_get_path(SYS_LANG_PATH);
$arch_dir = api_get_path(SYS_ARCHIVE_PATH);
/**
* Code run.
*/
foreach ($terms as $row) {
if ($words_counter > 10000) {
break;
}
$words = str_word_count(get_lang($row['term_name'], null, $orig_lang));
$words_counter += $words;
$terms_in_limit[$row['term_name']] = $i;
//echo "Term <b>".$row['term_name']."</b> is <b>'".get_lang($row['term_name'],null,$orig_lang)."'</b> which means $words words<br /><br />\n";
//if ($words_counter%1000 >= 0) {
//echo "Reached $words_counter words at term $i (".$row['term_name']." used ".$row['term_count']." times)...<br />\n";
//}
$i++;
}
//echo $words_counter.'<br />';
echo "Reached ".count($terms_in_limit)." terms for the $words_counter most-used words<br /><br />\n";
echo "Scanning English files, trying to find these terms...<br />\n";
if (!is_dir($arch_dir.'/langstats')) {
mkdir($arch_dir.'/langstats');
mkdir($arch_dir.'/langstats/'.$orig_lang);
}
$list_files = scandir($lang_dir.'/'.$orig_lang);
$j = 1;
$terms_found = [];
$words_found = 0;
$global_var = []; //keep the combination of all vars
$terms_in_limit = array_flip($terms_in_limit);
foreach ($list_files as $file) {
if (substr($file, 0, 1) == '.') {
continue;
}
//echo "'".substr($file,0,-8)."',<br />"; //print in a PHP array format
$vars = file($lang_dir.'/'.$orig_lang.'/'.$file);
$local_var = [];
$file_string = '<?php'."\n";
foreach ($vars as $line) {
$var = [];
$res = preg_match('/^(\$\w*)/', $line, $var);
if ($res > 0) {
//echo $var[1]."<br />";
if (in_array(substr($var[1], 1), $terms_in_limit)) {
//echo "Var ".$var[1]." was in the limit<br />";
$local_var[$var[1]] = $line;
$file_string .= $line;
$terms_found[] = substr($var[1], 1); //e.g. store Tools
$words_found += str_word_count(get_lang($var[1], null, $orig_lang));
} elseif (in_array(substr($var[1], 5), $terms_in_limit)) {
//echo "Var ".$var[1]." was in the limit<br />";
$local_var[$var[1]] = $line;
$file_string .= $line;
$terms_found[] = substr($var[1], 5); //e.g. store langTools
$words_found += str_word_count(get_lang(substr($var[1], 5), null, $orig_lang));
} //else do not care
}
}
echo "Writing ".$arch_dir.'/langstats/'.$orig_lang.'/'.$file."<br />\n";
file_put_contents($arch_dir.'/langstats/'.$orig_lang.'/'.$file, $file_string);
$global_var += $local_var;
}
$terms_diff = count($global_var) - count($terms_in_limit);
echo count(
$global_var
)." terms found in English files (summing up to $words_found words). Some terms ($terms_diff in this case) might have appeared in two different files<br />";
/**
* Display results.
*/
echo "Difference between filtered and found in English:<br />";
//print_r($terms_found);
echo "<pre>".print_r(array_diff($terms_in_limit, $terms_found), 1)."</pre>";
echo "#";

View File

@@ -0,0 +1,85 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Cron script to list used, but undefined, language variables.
*
* @package chamilo.cron
*/
/**
* Includes and declarations.
*/
exit();
require_once __DIR__.'/../../inc/global.inc.php';
$path = api_get_path(SYS_LANG_PATH).'english';
ini_set('memory_limit', '128M');
/**
* Main code.
*/
$terms = [];
$list = SubLanguageManager::get_lang_folder_files_list($path);
foreach ($list as $entry) {
$file = $path.'/'.$entry;
if (is_file($file)) {
$terms = array_merge($terms, SubLanguageManager::get_all_language_variable_in_file($file, true));
}
}
// get only the array keys (the language variables defined in language files)
$defined_terms = array_flip(array_keys($terms));
$terms = null;
$hidePlugins = !empty($_GET['hidePlugins']);
// now get all terms found in all PHP files of Chamilo (this takes some time and memory)
$undefined_terms = [];
$l = strlen(api_get_path(SYS_PATH));
$files = getAllPhpFiles(api_get_path(SYS_PATH));
foreach ($files as $file) {
$isPlugin = preg_match('#/plugin/#', $file);
if ($isPlugin && $hidePlugins) {
continue;
}
//echo 'Analyzing '.$file."<br />";
$shortfile = substr($file, $l);
$lines = file($file);
foreach ($lines as $line) {
$myterms = [];
// Find terms but ignore those starting with ->get_lang(), which are
// for plugins
$res = preg_match_all('/(?<!-\>)get_lang\(\'(\\w*)\'\)/', $line, $myterms);
if ($res > 0) {
foreach ($myterms[1] as $term) {
if (!isset($defined_terms[$term]) && !isset($defined_terms['lang'.$term])) {
$undefined_terms[$term] = $shortfile;
//echo "Undefined: $term<br />";
}
}
}
$res = 0;
$res = preg_match_all('/\{[\'"](\\w*)[\'"]\|get_lang\}/', $line, $myterms);
if ($res > 0) {
foreach ($myterms[1] as $term) {
if (!isset($defined_terms[$term]) && !isset($defined_terms['lang'.$term])) {
$undefined_terms[$term] = $shortfile;
//echo "Undefined: $term<br />";
}
}
}
}
flush();
}
//$undefined_terms = array_flip($undefined_terms);
if (count($undefined_terms) < 1) {
exit("No missing terms<br />\n");
} else {
echo "The following terms were nowhere to be found: <br />\n<table>";
}
$i = 1;
foreach ($undefined_terms as $term => $file) {
$isPlugin = substr($file, 0, 7) == 'plugin/';
echo "<tr><td>$i</td><td>$term</td><td>in $file";
if ($isPlugin) {
echo " <span style=\"color: #00ff00;\">(this one should be taken care of by the plugin's language files)</span>";
}
echo "</td></tr>\n";
$i++;
}
echo "</table>\n";

View File

@@ -0,0 +1,129 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Cron script to list unused, but defined, language variables.
*
* @package chamilo.cron.lang
*/
/**
* Includes and declarations.
*/
exit();
require_once __DIR__.'/../../inc/global.inc.php';
$path = api_get_path(SYS_LANG_PATH).'english';
ini_set('memory_limit', '128M');
/**
* Main code.
*/
$terms = [];
$list = SubLanguageManager::get_lang_folder_files_list($path);
foreach ($list as $entry) {
$file = $path.'/'.$entry;
if (is_file($file)) {
$terms = array_merge($terms, SubLanguageManager::get_all_language_variable_in_file($file, true));
}
}
// get only the array keys (the language variables defined in language files)
$defined_terms = array_flip(array_keys($terms));
$terms = null;
echo count($defined_terms)." terms were found in language files<br />";
// now get all terms found in all PHP files of Chamilo (this takes some
// time and memory)
$usedTerms = [];
$l = strlen(api_get_path(SYS_PATH));
$files = getAllPhpFiles(api_get_path(SYS_PATH));
$files[] = api_get_path(SYS_PATH).'main/install/data.sql';
// Browse files
foreach ($files as $file) {
//echo 'Analyzing '.$file."<br />";
$shortFile = substr($file, $l);
//echo 'Analyzing '.$shortFile."<br />";
$lines = file($file);
$isDataSQL = false;
if (substr($file, -21) === 'main/install/data.sql') {
$isDataSQL = true;
}
// Browse lines inside file $file
foreach ($lines as $line) {
if ($isDataSQL) {
// Check main/install/data.sql
// Should recognize stuff like
// INSERT INTO settings_current (variable, type, category, selected_value, title, comment) VALUES ('enable_profile_user_address_geolocalization', 'radio', 'User', 'false', 'EnableProfileUsersAddressGeolocalizationTitle', 'EnableProfileUsersAddressGeolocalizationComment');
// INSERT INTO settings_options (variable, value, display_text) VALUES ('enable_profile_user_address_geolocalization', 'true', 'Yes');
// ('show_teacher_data',NULL,'radio','Platform','true','ShowTeacherDataTitle','ShowTeacherDataComment',NULL,NULL, 1),
$res = 0;
$myTerms = [];
$res = preg_match_all('/\'(\w*)\',/', $line, $myTerms);
if ($res > 0) {
foreach ($myTerms[1] as $term) {
if (substr($term, 0, 4) == 'lang') {
$term = substr($term, 4);
}
$usedTerms[$term] = $shortFile;
}
}
} else {
$myTerms = [];
$res = preg_match_all('/get_lang\(\'(\\w*)\'\)/', $line, $myTerms);
if ($res > 0) {
foreach ($myTerms[1] as $term) {
if (substr($term, 0, 4) == 'lang') {
$term = substr($term, 4);
}
$usedTerms[$term] = $shortFile;
}
} else {
$res = 0;
$myTerms = [];
// Should catch:
// {{ 'CopyTextToClipboard' | get_lang }}
// {{ "HelloX" | get_lang | format(show_user_info.user_info.complete_name) }}
// {{ "StudentCourseProgressX" | get_lang | format(item.student_info.progress) }}
$res = preg_match_all('/\{\s*[\'"](\w*)[\'"]\s*\|\s*get_lang\s*(\|\s*\w*(\s*\([\w_\.,\s]*\))?\s*)?\}/', $line, $myTerms);
if ($res > 0) {
foreach ($myTerms[1] as $term) {
if (substr($term, 0, 4) == 'lang') {
$term = substr($term, 4);
}
$usedTerms[$term] = $shortFile;
}
}
// {{ display.panel('PersonalDataResponsibleOrganizationTitle' | get_lang , personal_data.responsible ) }}
// {{ display.panel('PersonalDataIntroductionTitle' | get_lang , 'PersonalDataIntroductionText' | get_lang) }}
$myTerms = [];
$res = preg_match_all('/\{\s*[\w\.]*\([\'"](\w*)[\'"]\s*\|\s*get_lang\s*(,\s*[\w_\.,\s\|\'"]*\s*)?\)\s*\}/', $line, $myTerms);
if ($res > 0) {
foreach ($myTerms[1] as $term) {
if (substr($term, 0, 4) == 'lang') {
$term = substr($term, 4);
}
$usedTerms[$term] = $shortFile;
}
}
}
}
}
flush();
}
// Compare defined terms VS used terms. Used terms should be smaller than
// defined terms, and this should prove the concept that there are much
// more variables than what we really use
if (count($usedTerms) < 1) {
exit("No used terms<br />\n");
} else {
echo "The following terms were defined but never used: <br />\n<table>";
}
$i = 1;
foreach ($defined_terms as $term => $file) {
// remove "lang" prefix just in case
if (substr($term, 0, 4) == 'lang') {
$term = substr($term, 4);
}
if (!isset($usedTerms[$term])) {
echo "<tr><td>$i</td><td>$term</td></tr>\n";
$i++;
}
}
echo "</table>\n";

View File

@@ -0,0 +1,92 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Script to switch all PHP files in Chamilo to a more Gettext-like syntax.
*
* @package chamilo.cron.lang
*/
/**
* Includes and declarations.
*/
exit();
require_once __DIR__.'/../../inc/global.inc.php';
$path = api_get_path(SYS_LANG_PATH).'english';
ini_set('memory_limit', '128M');
/**
* Main code.
*/
$terms = [];
$list = SubLanguageManager::get_lang_folder_files_list($path);
foreach ($list as $entry) {
$file = $path.'/'.$entry;
if (is_file($file)) {
$terms = array_merge($terms, SubLanguageManager::get_all_language_variable_in_file($file, true));
}
}
foreach ($terms as $index => $translation) {
$terms[$index] = trim(rtrim($translation, ';'), '"');
}
// get only the array keys (the language variables defined in language files)
$defined_terms = array_flip(array_keys($terms));
echo count($defined_terms)." terms were found in language files".PHP_EOL;
// now get all terms found in all PHP files of Chamilo (this takes some
// time and memory)
$usedTerms = [];
$l = strlen(api_get_path(SYS_PATH));
$files = getAllPhpFiles(api_get_path(SYS_PATH));
$rootLength = strlen(api_get_path(SYS_PATH));
$countFiles = 0;
$countReplaces = 0;
// Browse files
foreach ($files as $file) {
if (substr($file, $rootLength, 6) === 'vendor' || substr($file, $rootLength, 3) === 'web') {
continue;
}
//echo 'Analyzing '.$file.PHP_EOL;
$shortFile = substr($file, $l);
//echo 'Analyzing '.$shortFile.PHP_EOL;
$lines = file($file);
// Browse lines inside file $file
foreach ($lines as $line) {
$myTerms = [];
$res = preg_match_all('/get_lang\(([\'"](\\w*)[\'"])\)/m', $line, $myTerms);
if ($res > 0) {
foreach ($myTerms[2] as $term) {
echo "Found term $term - ".print_r($myTerms, 1).PHP_EOL;
if (substr($term, 0, 4) == 'lang') {
$term = substr($term, 4);
}
if (!empty($terms[$term])) {
$translation = $terms[$term];
$quotedTerm = $myTerms[1][0];
//echo "Would do sed -i \"s#$quotedTerm#'$translation'#g\" $file here\n";
system("sed -i \"s#$term#'$translation'#g\" $file");
$countReplaces++;
}
}
} else {
$res = 0;
$res = preg_match_all('/\{\s*([\'"](\\w*)[\'"])\s*\|get_lang\}/m', $line, $myTerms);
if ($res > 0) {
foreach ($myTerms[2] as $term) {
echo "Found term $term".PHP_EOL;
if (substr($term, 0, 4) == 'lang') {
$term = substr($term, 4);
}
if (!empty($terms[$term])) {
$translation = $terms[$term];
$quotedTerm = $myTerms[1][0];
//echo "Would do sed -i \"s#$quotedTerm#'$translation'#g\" $file here\n";
system("sed -i \"s#$term#'$translation'#g\" $file");
$countReplaces++;
}
}
}
}
}
$countFiles++;
flush();
}
echo "Done analyzing $countFiles files, with $countReplaces replacements!\n";

View File

@@ -0,0 +1,476 @@
<?php
/* For licensing terms, see /license.txt */
/**
* New lp reminder.
*
* @package chamilo.cron
*
* @author Carlos Alvarado <carlos.alvarado@beeznest.com>
*/
require_once __DIR__.'/../inc/global.inc.php';
// 24-hour format of an hour without leading zeros (in UTC timezone) to execute and search learning paths
$timeSlots = [
7,
16,
20,
];
/**
* Initialization.
*/
if ('cli' != php_sapi_name()) {
exit; //do not run from browser
}
$field = new ExtraField('lp');
$activeMessageNewlp = $field->get_handler_field_info_by_field_variable('notify_student_and_hrm_when_available');
if ($activeMessageNewlp == false) {
// field doesnt exist
exit();
}
if (!isset($activeMessageNewlp['default_value'])) {
// field dont have default value
exit();
}
$currentHour = (int) api_get_utc_datetime(null, false, true)->format('G');
if (!in_array($currentHour, $timeSlots)) {
exit("Execution nor allowed in this hour ($currentHour).");
}
/**
* Send the message to the intended user, manage the corresponding template and send through
* MessageManager::send_message_simple, using this for the option of human resources managers.
*
* @return bool|int
*/
function sendMessage(array $toUser, int $fromUser, string $courseName, string $lpName, string $link)
{
$toUserId = $toUser['user_id'];
$subjectTemplate = new Template(
null,
false,
false,
false,
false,
false
);
$subjectLayout = $subjectTemplate->get_template(
'mail/learning_path_reminder_subject.tpl'
);
$bodyTemplate = new Template(
null,
false,
false,
false,
false,
false
);
$bodyTemplate->assign('courseName', $courseName);
$bodyTemplate->assign('lpName', $lpName);
$bodyTemplate->assign('link', $link);
$bodyLayout = $bodyTemplate->get_template(
'mail/learning_path_reminder_body.tpl'
);
$tittle = $subjectTemplate->fetch($subjectLayout);
$content = $bodyTemplate->fetch($bodyLayout);
return MessageManager::send_message_simple(
$toUserId,
$tittle,
$content,
$fromUser,
true
);
// $drhList = UserManager::getDrhListFromUser($receiverUserId);
}
/**
* Obtains the data of the learning path and course searched by the id of the LP.
*/
function getLpDataByArrayId(array $lpid = []): array
{
if (count($lpid) == 0) {
return [];
}
$tblCourse = Database::get_main_table(TABLE_MAIN_COURSE);
$lpTable = Database::get_course_table(TABLE_LP_MAIN);
$sql = "SELECT
tblCourse.title AS course_name,
tblCourse.code AS code,
tblLp.id AS lp_id,
tblLp.c_id AS c_id,
tblLp.name AS name
FROM
$lpTable AS tblLp
INNER JOIN $tblCourse AS tblCourse ON tblLp.c_id = tblCourse.id
WHERE
tblLp.iid IN ( ".implode(',', $lpid)." )";
$result = Database::query($sql);
$return = [];
while ($element = Database::fetch_array($result)) {
$return[$element['lp_id']] = $element;
}
return $return;
}
/**
* Returns the id of the LPs that have the notification option active through the extra
* field 'notify_student_and_hrm_when_available'.
*/
function getLpIdWithNotify(): array
{
$extraFieldValuesTable = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
$extraFieldTable = Database::get_main_table(TABLE_EXTRA_FIELD);
$sql = "SELECT
tblExtraFieldValues.item_id as lp_id
FROM
$extraFieldValuesTable AS tblExtraFieldValues
INNER JOIN $extraFieldTable AS tblExtraField ON (
tblExtraFieldValues.field_id = tblExtraField.id AND
tblExtraField.variable = 'notify_student_and_hrm_when_available'
)
where
tblExtraFieldValues.value = 1";
$result = Database::query($sql);
$return = [];
while ($element = Database::fetch_array($result)) {
$return[] = $element['lp_id'];
}
return $return;
}
function getTutorIdFromCourseRelUser($cId = 0, $lpId = 0): int
{
$lpTable = Database::get_course_table(TABLE_LP_MAIN);
$tblCourseRelUser = Database::get_main_table(TABLE_MAIN_COURSE_USER);
$sql = "SELECT DISTINCT
tblCourseRelUser.user_id AS user_id
FROM
$lpTable AS tblLp
INNER JOIN $tblCourseRelUser AS tblCourseRelUser ON ( tblCourseRelUser.c_id = tblLp.c_id)
WHERE
tblCourseRelUser.user_id IS NOT NULL AND
tblCourseRelUser.status = 1 AND
tblLp.id = $lpId AND
tblLp.c_id = $cId";
$result = Database::query($sql);
$data = Database::fetch_assoc($result);
return (isset($data['user_id'])) ? (int) $data['user_id'] : 0;
}
function sendToArray(&$data, &$type, &$message, $lpId = 0)
{
foreach ($data as $user) {
$userName = $user['userInfo']['complete_name'];
$userId = $user['userInfo']['user_id'];
$fromUser = $user['fromUser'];
$courseName = $user['courseName'];
$lpName = $user['lpName'];
$send = sendMessage(
$user['userInfo'],
$fromUser,
$courseName,
$lpName,
$user['link']
);
$message .= "\n$type - Lp Id '$lpId' User Id '$userId' Sent to '$userName' Message id '$send' Lp name '$lpName'";
}
}
function getCurrentTimeSlot(int $currentHour, array $timeSlots = []): ?array
{
$index = array_search($currentHour, $timeSlots);
$yesterday = false;
if (false === $index) {
return null;
}
if (0 === $index) {
$index = count($timeSlots) - 1;
$yesterday = true;
} else {
$index--;
}
$startHour = $timeSlots[$index];
if ($yesterday) {
$startDate = api_get_utc_datetime(null, false, true)->modify("yesterday $startHour:00");
} else {
$startDate = api_get_utc_datetime(null, false, true)->modify("today $startHour:00");
}
$endDate = api_get_utc_datetime(null, false, true)->modify("today $currentHour:00");
return [$startDate, $endDate];
}
function learningPaths(int $currentHour, array $timeSlots = [])
{
$lpItems = getLpIdWithNotify();
if (count($lpItems) == 0) {
return null;
}
[$startDate, $endDate] = getCurrentTimeSlot($currentHour, $timeSlots);
$tutors = [];
$lpItemsString = implode(',', $lpItems);
$lpsData = getLpDataByArrayId($lpItems);
$itemProcessed = [];
$lpTable = Database::get_course_table(TABLE_LP_MAIN);
$tblCourseRelUser = Database::get_main_table(TABLE_MAIN_COURSE_USER);
$tblSessionCourseUser = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
$tblItempProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
/* Gets subscribed users individually in lp's by LearnpathSubscription */
$sql = "SELECT DISTINCT
tblItemProperty.session_id as session_id,
tblItemProperty.to_user_id as user_id,
tblItemProperty.insert_user_id as from_user_id,
tblLp.id AS lp_id,
tblItemProperty.lastedit_type
FROM
$tblItempProperty as tblItemProperty
INNER JOIN $lpTable as tblLp ON
(
tblLp.iid = tblItemProperty.ref AND
tblItemProperty.lastedit_type = 'LearnpathSubscription'
)
WHERE
publicated_on < '".$endDate->format('Y-m-d H:i:s')."' AND
publicated_on >= '".$startDate->format('Y-m-d H:i:s')."' AND
tblItemProperty.to_user_id IS NOT NULL AND
tblLp.id in ($lpItemsString)";
$result = Database::query($sql);
$groupUsers = [];
while ($row = Database::fetch_array($result)) {
$lpId = (int) $row['lp_id'];
$lpData = [];
if (isset($lpsData[$lpId])) {
$lpData = $lpsData[$lpId];
}
$courseName = $lpData['course_name'] ?? null;
$courseCode = $lpData['code'] ?? null;
$lpName = $lpData['name'] ?? null;
$sessionId = (int) $row['session_id'];
$toUser = (int) $row['user_id'];
$fromUser = (int) $row['from_user_id'];
$userInfo = api_get_user_info($toUser);
$href = api_get_path(WEB_CODE_PATH).
'lp/lp_controller.php?cidReq='.htmlspecialchars($courseCode).
"&id_session=$sessionId &action=view&lp_id=$lpId&gidReq=0&gradebook=0&origin=";
$link = "<a href='$href'>$href</a>";
$groupUsers[$lpId][$sessionId][$toUser] = [
'userInfo' => $userInfo,
'fromUser' => $fromUser,
'courseName' => $courseName,
'lpName' => $lpName,
'link' => $link,
];
$itemProcessed[$lpId][$sessionId]['LearnpathSubscription'][$toUser] = $groupUsers[$lpId][$sessionId][$toUser];
}
/* Gets subscribed users by classes in lp's by LearnpathSubscription */
$sql = "SELECT DISTINCT
tblItemProperty.session_id as session_id,
tblItemProperty.to_group_id as group_id,
tblUsergroupRelUser.user_id as user_id,
tblItemProperty.insert_user_id as from_user_id,
tblLp.id AS lp_id,
tblItemProperty.lastedit_type
FROM
$tblItempProperty as tblItemProperty
INNER JOIN $lpTable as tblLp ON
(
tblLp.iid = tblItemProperty.ref AND
tblItemProperty.lastedit_type = 'LearnpathSubscription'
)
INNER JOIN usergroup_rel_user as tblUsergroupRelUser on (
tblItemProperty.to_group_id = tblUsergroupRelUser.usergroup_id
)
WHERE
publicated_on < '".$endDate->format('Y-m-d H:i:s')."' AND
publicated_on >= '".$startDate->format('Y-m-d H:i:s')."' AND
tblItemProperty.to_group_id IS NOT NULL AND
tblLp.id in ($lpItemsString)";
$result = Database::query($sql);
$groupUsers = [];
while ($row = Database::fetch_array($result)) {
$lpId = (int) $row['lp_id'];
$lpData = [];
if (isset($lpsData[$lpId])) {
$lpData = $lpsData[$lpId];
}
$courseName = $lpData['course_name'] ?? null;
$courseCode = $lpData['code'] ?? null;
$lpName = $lpData['name'] ?? null;
$sessionId = (int) $row['session_id'];
$toUser = (int) $row['user_id'];
$fromUser = (int) $row['from_user_id'];
$userInfo = api_get_user_info($toUser);
$href = api_get_path(WEB_CODE_PATH).'lp/lp_controller.php?'
.api_get_cidreq_params($courseCode, $sessionId).'&'
.http_build_query(
[
'gradebook' => '0',
'origin' => '',
'lp_id' => $lpId,
'action' => 'view',
]
);
$link = "<a href='$href'>$href</a>";
$groupUsers[$lpId][$sessionId][$toUser] = [
'userInfo' => $userInfo,
'fromUser' => $fromUser,
'courseName' => $courseName,
'lpName' => $lpName,
'link' => $link,
];
$itemProcessed[$lpId][$sessionId]['LearnpathSubscription'][$toUser] = $groupUsers[$lpId][$sessionId][$toUser];
}
/* Get users who are enrolled in the course */
$sql = "SELECT DISTINCT
tblCourseRelUser.user_id AS user_id,
tblLp.id AS lp_id,
tblLp.c_id AS c_id
FROM
$lpTable AS tblLp
INNER JOIN $tblCourseRelUser AS tblCourseRelUser ON ( tblCourseRelUser.c_id = tblLp.c_id)
WHERE
publicated_on < '".$endDate->format('Y-m-d H:i:s')."' AND
publicated_on >= '".$startDate->format('Y-m-d H:i:s')."' AND
tblCourseRelUser.user_id IS NOT NULL AND
tblCourseRelUser.status = 5 AND
tblLp.id in ($lpItemsString)";
$result = Database::query($sql);
while ($row = Database::fetch_array($result)) {
$lpId = (int) $row['lp_id'];
$sessionId = 0;
if (isset($lpsData[$lpId])) {
$lpData = $lpsData[$lpId];
}
if (!isset($tutors[$row['c_id']][$row['lp_id']])) {
$tutors[$row['c_id']][$row['lp_id']] = getTutorIdFromCourseRelUser($row['c_id'], $row['lp_id']);
}
$courseName = $lpData['course_name'] ?? null;
$courseCode = $lpData['code'] ?? null;
$lpName = $lpData['name'] ?? null;
$toUser = (int) $row['user_id'];
$fromUser = $tutors[$row['c_id']][$row['lp_id']];
$userInfo = api_get_user_info($toUser);
$href = api_get_path(WEB_CODE_PATH).'lp/lp_controller.php?'
.api_get_cidreq_params($courseCode, $sessionId).'&'
.http_build_query(
[
'gradebook' => '0',
'origin' => '',
'lp_id' => $lpId,
'action' => 'view',
]
);
$link = "<a href='$href'>$href</a>";
if (!isset($itemProcessed[$lpId][$sessionId]['LearnpathSubscription'])) {
$groupUsers[$lpId][$sessionId][$toUser] = [
'userInfo' => $userInfo,
'fromUser' => $fromUser,
'courseName' => $courseName,
'lpName' => $lpName,
'link' => $link,
];
$itemProcessed[$lpId][$sessionId]['NoLpSubscription'][$toUser] = $groupUsers[$lpId][$sessionId][$toUser];
}
}
/** Get the users who are registered in the sessions */
$sql = "SELECT DISTINCT
tblSessionRelCourseRelUser.user_id AS user_id,
tblLp.id AS lp_id,
tblSessionRelCourseRelUser.session_id AS session_id,
tblLp.c_id AS c_id,
tblSessionRelCourseRelUser.status AS status
FROM
$lpTable AS tblLp
INNER JOIN $tblSessionCourseUser AS tblSessionRelCourseRelUser ON (
tblSessionRelCourseRelUser.c_id = tblLp.c_id)
WHERE
publicated_on < '".$endDate->format('Y-m-d H:i:s')."' AND
publicated_on >= '".$startDate->format('Y-m-d H:i:s')."' AND
tblSessionRelCourseRelUser.user_id IS NOT NULL AND
tblLp.id in ($lpItemsString) AND
tblSessionRelCourseRelUser.status = 0
ORDER BY tblSessionRelCourseRelUser.status";
$result = Database::query($sql);
while ($row = Database::fetch_array($result)) {
$lpId = (int) $row['lp_id'];
$sessionId = 0;
if (isset($lpsData[$lpId])) {
$lpData = $lpsData[$lpId];
}
$courseName = $lpData['course_name'] ?? null;
$courseCode = $lpData['code'] ?? null;
$lpName = $lpData['name'] ?? null;
$toUser = (int) $row['user_id'];
if (!isset($tutors[$row['c_id']][$row['lp_id']])) {
$tutors[$row['c_id']][$row['lp_id']] = getTutorIdFromCourseRelUser($row['c_id'], $row['lp_id']);
}
$fromUser = $tutors[$row['c_id']][$row['lp_id']];
$userInfo = api_get_user_info($toUser);
$href = api_get_path(WEB_CODE_PATH).'lp/lp_controller.php?'
.api_get_cidreq_params($courseCode, $sessionId).'&'
.http_build_query(
[
'gradebook' => '0',
'origin' => '',
'lp_id' => $lpId,
'action' => 'view',
]
);
$link = "<a href='$href'>$href</a>";
if (!isset($itemProcessed[$lpId][$sessionId]['LearnpathSubscription'])) {
$groupUsers[$lpId][$sessionId][$toUser] = [
'userInfo' => $userInfo,
'fromUser' => $fromUser,
'courseName' => $courseName,
'lpName' => $lpName,
'link' => $link,
];
$itemProcessed[$lpId][$sessionId]['NoLpSubscription'][$toUser] = $groupUsers[$lpId][$sessionId][$toUser];
}
}
/**
* Send the emails to the corresponding students and their DRHs, Bearing in mind that if they exist through
* LearnpathSubscription, it will not send anything in the other elements.
*/
$message = '';
foreach ($itemProcessed as $lpId => $sessions) {
foreach ($sessions as $sessionId => $types) {
foreach ($types as $type => $users) {
if ('LearnpathSubscription' == $type) {
sendToArray($users, $type, $message, $lpId);
} elseif (!isset($itemProcessed[$lpId][$sessionId]['LearnpathSubscription'])) {
sendToArray($users, $type, $message, $lpId);
}
}
}
}
echo "$message\n\n";
}
learningPaths($currentHour, $timeSlots);
exit();

View File

@@ -0,0 +1,360 @@
<?php
/* For licensing terms, see /license.txt */
/**
* New lp reminder.
*
* To add this extra field for lp option number_of_days_for_completion
* INSERT INTO extra_field (extra_field_type, field_type, variable, display_text, default_value, field_order, visible_to_self, visible_to_others, changeable, filter, created_at) VALUES
* (6, 1, 'number_of_days_for_completion', 'NumberOfDaysForCompletion', '', 0, 1, 0, 1, 0, NOW());
*
* @package chamilo.cron
*/
define('NUMBER_OF_DAYS_TO_RESEND_NOTIFICATION', 3);
require_once __DIR__.'/../inc/global.inc.php';
/**
* Initialization.
*/
if ('cli' != php_sapi_name()) {
exit; //do not run from browser
}
notifyUsersForCheckingLpCompletion();
/**
* Send the message to the intended user, manage the corresponding template and send through
* MessageManager::send_message_simple, using this for the option of human resources managers.
*
* @param $toUserId
* @param $courseId
* @param $lpProgress
* @param $registrationDate
* @param $nbRemind
*
* @return bool|int
*/
function sendMessage(
$toUserId,
$courseId,
$lpProgress,
$registrationDate,
$nbRemind
) {
$subjectTemplate = new Template(
null,
false,
false,
false,
false,
false
);
$courseInfo = api_get_course_info_by_id($courseId);
$courseName = $courseInfo['title'];
$userInfo = api_get_user_info($toUserId);
$language = $userInfo['language'];
$subjectTemplate->assign('RemindXLpCourseX', sprintf(getUserLang('RemindXLpCourseX', $language), $nbRemind, $courseName));
$subjectLayout = $subjectTemplate->get_template(
'mail/lp_progress_reminder_subject.tpl'
);
$bodyTemplate = new Template(
null,
false,
false,
false,
false,
false
);
$teachersListString = '';
$teachers = CourseManager::getTeachersFromCourse($courseId);
if (!empty($teachers)) {
$teachersList = [];
foreach ($teachers as $value) {
$teacherName = api_get_person_name($value['firstname'], $value['lastname']);
$teachersList[] = strtoupper($teacherName).': '.$value['email'];
}
$teachersListString = implode('<br/>', $teachersList);
}
$userFullName = api_get_person_name($userInfo['firstname'], $userInfo['lastname']);
$urlChamilo = api_get_path(WEB_CODE_PATH);
$urlLostPw = api_get_path(WEB_CODE_PATH).'auth/lostPassword.php';
$logoPortal = return_logo();
$bodyTemplate->assign('HelloX', sprintf(getUserLang('HelloX', $language), $userFullName));
$bodyTemplate->assign('YouAreRegCourseXFromDateX', sprintf(getUserLang('YouAreRegCourseXFromDateX', $language), $courseName, $registrationDate));
$bodyTemplate->assign('ThisMessageIsAboutX', sprintf(getUserLang('ThisMessageIsAboutX', $language), $lpProgress));
$bodyTemplate->assign('StepsToRemindX', sprintf(getUserLang('StepsToRemindX', $language), $urlChamilo, $userInfo['username'], $urlLostPw));
$bodyTemplate->assign('LpRemindFooterX', sprintf(getUserLang('LpRemindFooterX', $language), $logoPortal, $teachersListString));
$bodyLayout = $bodyTemplate->get_template(
'mail/lp_progress_reminder_body.tpl'
);
$title = $subjectTemplate->fetch($subjectLayout);
$content = $bodyTemplate->fetch($bodyLayout);
return MessageManager::send_message_simple(
$toUserId,
$title,
$content,
1,
true
);
}
/**
* Returns a translated (localized) string by user language.
*
* @param $variable
* @param $language
*
* @return mixed
*/
function getUserLang($variable, $language)
{
$languageFilesToLoad = api_get_language_files_to_load($language);
foreach ($languageFilesToLoad as $languageFile) {
include $languageFile;
}
$translate = $variable;
if (isset($$variable)) {
$langVariable = $$variable;
$translate = $langVariable;
}
return $translate;
}
/**
* Number of reminder checking the frequency from NUMBER_OF_DAYS_TO_RESEND_NOTIFICATION.
*
* @param $registrationDate
* @param $nbDaysForLpCompletion
*
* @return false|float|int
*/
function getNbReminder($registrationDate, $nbDaysForLpCompletion): int
{
$date1 = new DateTime($registrationDate);
$date1->modify("+$nbDaysForLpCompletion day");
$date2 = new DateTime('now', new DateTimeZone('UTC'));
$interval = $date1->diff($date2);
$diffDays = (int) $interval->format('%a');
$nbRemind = ceil($diffDays / NUMBER_OF_DAYS_TO_RESEND_NOTIFICATION) + 1;
return $nbRemind;
}
/**
* It checks if user has to be notified checking the current registration date and nbDaysForLpCompletion value.
*
* @param $registrationDate
* @param $nbDaysForLpCompletion
*/
function isTimeToRemindUser($registrationDate, $nbDaysForLpCompletion): bool
{
$date1 = new DateTime($registrationDate);
$date1->modify("+$nbDaysForLpCompletion day");
$startDate = $date1->format('Y-m-d');
$date2 = new DateTime('now', new DateTimeZone('UTC'));
$now = $date2->format('Y-m-d');
$reminder = false;
if ($startDate < $now) {
$interval = $date1->diff($date2);
$diffDays = (int) $interval->format('%a');
$reminder = (0 === $diffDays % NUMBER_OF_DAYS_TO_RESEND_NOTIFICATION);
} else {
$reminder = $startDate === $now;
}
return $reminder;
}
/**
* Notify users for checking Learning path completion.
*
* @return null
*/
function notifyUsersForCheckingLpCompletion()
{
$lpItems = getLpIdWithDaysForCompletion();
if (count($lpItems) == 0) {
return null;
}
$tblCourse = Database::get_main_table(TABLE_MAIN_COURSE);
$sql = "SELECT id FROM $tblCourse";
$rs = Database::query($sql);
if (Database::num_rows($rs) > 0) {
while ($row = Database::fetch_array($rs)) {
$courseId = $row['id'];
// It checks users in main course
$courseUsers = getCourseUsers($courseId);
if (!empty($courseUsers)) {
foreach ($courseUsers as $user) {
$toUserId = $user['user_id'];
$lpProgress = (int) $user['progress'];
$nbDaysForLpCompletion = $lpItems[$user['lp_id']];
$registrationDate = getUserCourseRegistrationAt($courseId, $toUserId);
$notify = isTimeToRemindUser($registrationDate, $nbDaysForLpCompletion);
if ($notify) {
$nbRemind = getNbReminder($registrationDate, $nbDaysForLpCompletion);
sendMessage($toUserId, $courseId, $lpProgress, $registrationDate, $nbRemind);
}
}
}
// It checks users in session course
$sessionCourseUsers = getCourseUsers($courseId, true);
if (!empty($sessionCourseUsers)) {
foreach ($sessionCourseUsers as $user) {
$toUserId = $user['user_id'];
$lpProgress = (int) $user['progress'];
$nbDaysForLpCompletion = $lpItems[$user['lp_id']];
$registrationDate = getUserCourseRegistrationAt($courseId, $toUserId, $user['session_id']);
$notify = isTimeToRemindUser($registrationDate, $nbDaysForLpCompletion);
if ($notify) {
$nbRemind = getNbReminder($registrationDate, $nbDaysForLpCompletion);
sendMessage($toUserId, $courseId, $lpProgress, $registrationDate, $nbRemind);
}
}
}
}
}
}
/**
* Get the users in a course also checking the session.
*
* @param int $courseId
* @param false $checkSession
*
* @return array|null
*/
function getCourseUsers($courseId, $checkSession = false)
{
$lpItems = getLpIdWithDaysForCompletion();
if (count($lpItems) == 0) {
return null;
}
$tblCourseUser = Database::get_main_table(TABLE_MAIN_COURSE_USER);
$tblSessionCourseUser = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
$tblLp = Database::get_course_table(TABLE_LP_MAIN);
$tblLpView = Database::get_course_table(TABLE_LP_VIEW);
$lpItemsString = implode(',', array_keys($lpItems));
if ($checkSession) {
$sql = "SELECT
scu.user_id,
scu.c_id,
lp.id as lp_id,
lpv.progress,
scu.session_id
FROM
$tblSessionCourseUser scu
INNER JOIN $tblLp lp ON lp.c_id = scu.c_id
LEFT JOIN $tblLpView lpv ON lpv.lp_id = lp.id AND lpv.user_id = scu.user_id
WHERE
scu.c_id = $courseId AND
(lpv.progress < 100 OR lpv.progress is null) AND
lp.id IN($lpItemsString)";
} else {
$sql = "SELECT
cu.user_id,
cu.c_id,
lp.id as lp_id,
lpv.progress
FROM
$tblCourseUser cu
INNER JOIN $tblLp lp ON (lp.c_id = cu.c_id)
LEFT JOIN $tblLpView lpv ON (lpv.lp_id = lp.id AND lpv.user_id = cu.user_id)
WHERE
cu.c_id = $courseId AND
(lpv.progress < 100 OR lpv.progress is null) AND
lp.id IN($lpItemsString)";
}
$rs = Database::query($sql);
$users = [];
if (Database::num_rows($rs) > 0) {
while ($row = Database::fetch_assoc($rs)) {
$users[] = $row;
}
}
return $users;
}
/**
* It returns the register date of a user in a course or session from track_e_default.
*
* @param int $courseId
* @param int $userId
* @param int $sessionId
*
* @return false|mixed|string|null
*/
function getUserCourseRegistrationAt($courseId, $userId, $sessionId = 0)
{
$tblTrackDefault = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DEFAULT);
$sql = "SELECT
default_date
FROM $tblTrackDefault
WHERE c_id = $courseId AND
default_value_type = 'user_object' AND
default_event_type = '".LOG_SUBSCRIBE_USER_TO_COURSE."' AND
default_value LIKE CONCAT('%s:2:\\\\\\\\\"id\\\\\\\\\";i:', $userId, ';%') AND
session_id = $sessionId";
$rs = Database::query($sql);
$registerDate = '';
if (Database::num_rows($rs) > 0) {
$registerDate = Database::result($rs, 0, 0);
}
return $registerDate;
}
/**
* Returns the id of the LPs that have days for completion the progress through the extra
* field 'number_of_days_for_completion'.
*/
function getLpIdWithDaysForCompletion(): array
{
$extraFieldValuesTable = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
$extraFieldTable = Database::get_main_table(TABLE_EXTRA_FIELD);
$sql = "SELECT
tblExtraFieldValues.item_id as lp_id,
tblExtraFieldValues.value as ndays
FROM
$extraFieldValuesTable AS tblExtraFieldValues
INNER JOIN $extraFieldTable AS tblExtraField ON (
tblExtraFieldValues.field_id = tblExtraField.id AND
tblExtraField.variable = 'number_of_days_for_completion'
)
where
tblExtraFieldValues.value > 0";
$result = Database::query($sql);
$return = [];
while ($element = Database::fetch_array($result)) {
$return[$element['lp_id']] = $element['ndays'];
}
return $return;
}
exit();

View File

@@ -0,0 +1,18 @@
<?php
/* For licensing terms, see /license.txt */
/**
* @author Julio Montoya <gugli100@gmail.com>
*/
if (PHP_SAPI !== 'cli') {
exit('Run this script through the command line or comment this line in the code');
}
require_once __DIR__.'/../inc/global.inc.php';
/**
* Notification sending.
*/
$notify = new Notification();
$notify->send();

View File

@@ -0,0 +1,170 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Course expiration reminder.
*
* @package chamilo.cron
*
* @author Imanol Losada <imanol.losada@beeznest.com>
*/
require_once __DIR__.'/../inc/global.inc.php';
/**
* Initialization.
*/
if (php_sapi_name() != 'cli') {
exit; //do not run from browser
}
$isActive = api_get_setting('cron_remind_course_expiration_activate') === 'true';
if (!$isActive) {
exit;
}
$frequency = api_get_setting('cron_remind_course_expiration_frequency');
// Days before expiration date to send reminders
$today = gmdate("Y-m-d");
$expirationDate = gmdate("Y-m-d", strtotime("$today + $frequency day"));
$gradebookTable = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
$certificateTable = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CERTIFICATE);
$sessionTable = Database::get_main_table(TABLE_MAIN_SESSION);
$sessionUserTable = Database::get_main_table(TABLE_MAIN_SESSION_USER);
$query = "
SELECT DISTINCT category.session_id, certificate.user_id
FROM $gradebookTable AS category
LEFT JOIN $certificateTable AS certificate
ON category.id = certificate.cat_id
INNER JOIN $sessionTable AS session
ON category.session_id = session.id
WHERE
session.access_end_date BETWEEN '$today' AND
'$expirationDate' AND
category.session_id IS NOT NULL";
$sessionId = 0;
$userIds = [];
$sessions = [];
$result = Database::query($query);
$urlSessionTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
$urlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
while ($row = Database::fetch_array($result)) {
if ($sessionId != $row['session_id']) {
$sessionId = $row['session_id'];
$userIds = [];
}
if (!is_null($row['user_id'])) {
array_push($userIds, $row['user_id']);
}
$sessions[$sessionId] = $userIds;
}
$usersToBeReminded = [];
foreach ($sessions as $sessionId => $userIds) {
$userId = 0;
$userIds = $userIds ? " AND sessionUser.user_id NOT IN (".implode(", ", $userIds).")" : null;
$query = "
SELECT sessionUser.session_id, sessionUser.user_id, session.name, session.access_end_date
FROM $sessionUserTable AS sessionUser
INNER JOIN $sessionTable AS session
ON sessionUser.session_id = session.id
WHERE
session_id = $sessionId$userIds";
$result = Database::query($query);
while ($row = Database::fetch_array($result)) {
$usersToBeReminded[$row['user_id']][$row['session_id']] = [
'name' => $row['name'],
'access_end_date' => $row['access_end_date'],
];
}
}
if ($usersToBeReminded) {
$today = date_create($today);
$administrator = [
'completeName' => api_get_person_name(
api_get_setting("administratorName"),
api_get_setting("administratorSurname"),
null,
PERSON_NAME_EMAIL_ADDRESS
),
'email' => api_get_setting("emailAdministrator"),
];
echo "\n======================================================================\n\n";
foreach ($usersToBeReminded as $userId => $sessions) {
$user = api_get_user_info($userId);
$userCompleteName = api_get_person_name(
$user['firstname'],
$user['lastname'],
null,
PERSON_NAME_EMAIL_ADDRESS
);
foreach ($sessions as $sessionId => $session) {
$daysRemaining = date_diff($today, date_create($session['access_end_date']));
$join = " INNER JOIN $urlSessionTable ON id = access_url_id";
$result = Database::select(
'url',
"$urlTable $join",
[
'where' => [
'session_id = ?' => [
$sessionId,
],
],
'limit' => '1',
]
);
$subjectTemplate = new Template(null, false, false, false, false, false);
$subjectTemplate->assign('session_name', $session['name']);
$subjectTemplate->assign(
'session_access_end_date',
$session['access_end_date']
);
$subjectTemplate->assign(
'remaining_days',
$daysRemaining->format("%d")
);
$subjectLayout = $subjectTemplate->get_template(
'mail/cron_remind_course_expiration_subject.tpl'
);
$bodyTemplate = new Template(null, false, false, false, false, false);
$bodyTemplate->assign('complete_user_name', $userCompleteName);
$bodyTemplate->assign('session_name', $session['name']);
$bodyTemplate->assign(
'session_access_end_date',
$session['access_end_date']
);
$bodyTemplate->assign(
'remaining_days',
$daysRemaining->format("%d")
);
$bodyLayout = $bodyTemplate->get_template(
'mail/cron_remind_course_expiration_body.tpl'
);
api_mail_html(
$userCompleteName,
$user['email'],
$subjectTemplate->fetch($subjectLayout),
$bodyTemplate->fetch($bodyLayout),
$administrator['completeName'],
$administrator['email']
);
echo "Email sent to $userCompleteName (".$user['email'].")\n";
echo "Session: ".$session['name']."\n";
echo "Date end: ".$session['access_end_date']."\n";
echo "Days remaining: ".$daysRemaining->format("%d")."\n\n";
}
echo "======================================================================\n\n";
}
} else {
echo "No users to be reminded\n";
}

View File

@@ -0,0 +1,86 @@
<?php
/* For licensing terms, see /license.txt */
require_once __DIR__.'/../inc/global.inc.php';
if (PHP_SAPI != 'cli') {
exit('Run this script through the command line or comment this line in the code');
}
$urlList = UrlManager::get_url_data();
$defaultSenderId = 1;
// Loop all portals
foreach ($urlList as $url) {
// Set access_url in order to get the correct url links and admins
$_configuration['access_url'] = $url['id'];
$sql = '';
$user_table = Database::get_main_table(TABLE_MAIN_USER);
$admin_table = Database::get_main_table(TABLE_MAIN_ADMIN);
$sql .= "SELECT u.id, v.updated_at FROM $user_table u";
// adding the filter to see the user's only of the current access_url
if (api_get_multiple_access_url()) {
$access_url_rel_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
$sql .= " INNER JOIN $access_url_rel_user_table url_rel_user
ON (u.id = url_rel_user.user_id)";
}
$extraFields = UserManager::createDataPrivacyExtraFields();
$extraFieldId = $extraFields['delete_legal'];
$extraFieldIdDeleteAccount = $extraFields['delete_account_extra_field'];
$extraFieldValue = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
$sql .= " INNER JOIN $extraFieldValue v
ON (
u.id = v.item_id AND
(field_id = $extraFieldId OR field_id = $extraFieldIdDeleteAccount) AND
v.value = 1
) ";
$sql .= " WHERE 1 = 1 ";
if (api_get_multiple_access_url()) {
$sql .= " AND url_rel_user.access_url_id = ".api_get_current_access_url_id();
}
$numberOfDays = 7;
$date = new DateTime();
$date->sub(new \DateInterval('P'.$numberOfDays.'D'));
$dateToString = $date->format('Y-m-d h:i:s');
$sql .= " AND v.updated_at < '$dateToString'";
$url = api_get_path(WEB_CODE_PATH).'admin/user_list_consent.php';
$link = Display::url($url, $url);
$subject = get_lang('UserRequestWaitingForAction');
$email = api_get_configuration_value('data_protection_officer_email');
$message = 'Checking requests from '.strip_tags(Display::dateToStringAgoAndLongDate($dateToString))."\n";
$result = Database::query($sql);
while ($user = Database::fetch_array($result, 'ASSOC')) {
$userId = $user['id'];
$userInfo = api_get_user_info($userId);
if ($userInfo) {
$content = sprintf(
get_lang('TheUserXIsWaitingForAnActionGoHereX'),
$userInfo['complete_name'],
$link
);
if (!empty($email)) {
api_mail_html('', $email, $subject, $content);
} else {
MessageManager::sendMessageToAllAdminUsers($defaultSenderId, $subject, $content);
}
$date = strip_tags(Display::dateToStringAgoAndLongDate($user['updated_at']));
$message .= "User ".$userInfo['complete_name_with_username']." is waiting for an action since $date \n";
}
}
echo $message;
}

21
main/cron/run.php Normal file
View File

@@ -0,0 +1,21 @@
<?php
/**
* This script should be called by a properly set cron process on your server.
* For more information, check the installation guide in the documentation
* folder.
* Add your own executable scripts below the inclusion of notification.php.
*
* @package chamilo.cron
*/
/**
* Settings that will influence the execution of the cron tasks.
*/
//ini_set('max_execution_time',300); //authorize execution for up to 5 minutes
//ini_set('memory_limit','100M'); //authorize script to use up to 100M RAM
/**
* Included cron-ed tasks. You might want to turn error-logging off by
* commenting the first and last line of this section.
*/
error_log('[chamilo][cronjob] Starting cron jobs as process '.getmypid());
require_once 'notification.php';
error_log('[chamilo][cronjob] Ending cron jobs of process '.getmypid());

View File

@@ -0,0 +1,14 @@
<?php
/* For licensing terms, see /license.txt */
require __DIR__.'/../inc/global.inc.php';
$urlList = UrlManager::get_url_data();
foreach ($urlList as $url) {
$urlId = $url['id'];
$_configuration['access_url'] = $urlId;
echo "Portal: # ".$urlId." - ".$url['url'].'-'.api_get_path(WEB_CODE_PATH).PHP_EOL;
$object = new ScheduledAnnouncement();
$messagesSent = $object->sendPendingMessages($urlId);
echo "Messages sent $messagesSent".PHP_EOL;
}

View File

@@ -0,0 +1,77 @@
<?php
/* For licensing terms, see /license.txt */
exit;
require_once __DIR__.'/../../app/config/auth.conf.php';
require_once __DIR__.'/../auth/external_login/ldap.inc.php';
require_once __DIR__.'/../auth/external_login/functions.inc.php';
global $extldap_config;
if (empty($extldap_config)) {
echo "$extldap_config not found";
exit;
}
$ds = extldap_connect();
if (!$ds) {
echo 'ldap not connected';
exit;
}
if (api_get_configuration_value('ldap_encrypt_admin_password')) {
$ldap_pass = api_decrypt_ldap_password($extldap_config['admin_password']);
} else {
$ldap_pass = $extldap_config['admin_password'];
}
$ldapbind = @ldap_bind($ds, $extldap_config['admin_dn'], $ldap_pass);
if ($ldapbind === false) {
echo 'EXTLDAP ERROR : cannot connect with admin login/password';
return false;
}
$table = Database::get_main_table(TABLE_MAIN_USER);
$sql = "SELECT * FROM $table WHERE auth_source = 'ldap' ";
$result = Database::query($sql);
while ($user = Database::fetch_array($result, 'ASSOC')) {
$userId = $user['id'];
$username = $user['username'];
$user_search = extldap_get_user_search_string($username);
$sr = ldap_search($ds, $extldap_config['base_dn'], $user_search);
if (!$sr) {
echo "Username not found in LDAP: ".$username.PHP_EOL;
continue;
}
$users = ldap_get_entries($ds, $sr);
$extraFieldUser = new ExtraFieldValue('user');
if (!empty($users)) {
echo "Updating user #".$userId.PHP_EOL;
for ($key = 0; $key < $users['count']; $key++) {
$ldapUser = $users[$key];
//print_r($ldapUser).PHP_EOL;
$params = [
'firstname' => $ldapUser['givenname'][0],
'lastname' => $ldapUser['sn'][0],
'email' => $ldapUser['mail'][0],
];
print_r($params).PHP_EOL;
Database::update($table, $params, ['id = ?' => $userId]);
$extraFields = [
'company' => $ldapUser['department'][0],
];
foreach ($extraFields as $variable => $value) {
$params = [
'item_id' => $userId,
'variable' => $variable,
'value' => $value,
];
print_r($params).PHP_EOL;
$extraFieldUser->save($params);
}
}
}
}

View File

@@ -0,0 +1,36 @@
<?php
/* See license terms in /license.txt */
/**
* This is a script used to automatically import a list of users from
* a CSV file into Dokeos.
* It is triggered by a cron task configured on the server.
*
* @uses /main/webservices/user_import/
*
* @author Eric Marguin <eric.marguin@dokeos.com>
*
* @package chamilo.cron
*/
/**
* Global cycle: init, execute, output.
*/
require_once __DIR__.'/../../inc/global.inc.php';
// check if this client has been called by php_cli (command line or cron)
if (php_sapi_name() != 'cli') {
echo 'You can\'t call this service through a browser';
exit();
}
// create client
$client = new nusoap_client(api_get_path(WEB_CODE_PATH).'cron/user_import/service.php');
// call import_user method
$response = $client->call(
'import_users',
[
'filepath' => api_get_path(SYS_UPLOAD_PATH)."users_import.csv",
'security_key' => api_get_configuration_value('security_key'),
]
);
echo $response;

View File

@@ -0,0 +1,35 @@
<?php
/**
* This script gets users details of a given list of users
* (given by e-mail) and prints the details in /tmp/list.txt
* To enable script, prefix the first die(); with //.
*
* @package chamilo.cron.user_import
*/
/**
* Initialization.
*/
/* Example of input file:
sam@example.com
Matthew@example.com
HERMAN@example.com
*/
exit();
//change filename depending on file containing mails list
$list = file('input.txt');
require_once '../../inc/global.inc.php';
$users = Database::get_main_table(TABLE_MAIN_USER);
$string = '';
foreach ($list as $mail) {
$mail = trim($mail);
$sql = "SELECT user_id, official_code, firstname, lastname, email FROM $users WHERE email = '$mail'\n";
$res = Database::query($sql);
if (Database::num_rows($res) == 0) {
$string .= 'No encontrado;'.$row['email'];
} else {
$row = Database::fetch_assoc($res);
$string .= $row['user_id'].';'.$row['email'].';'.$row['firstname'].';'.$row['lastname'].';'.$row['official_code']."\r\n";
}
}
echo $string;
file_put_contents('/tmp/list.txt', $string);

View File

@@ -0,0 +1,88 @@
<?php
/**
* This script updates the passwords of a given list of users
* (given by e-mail) and resends them their account creation
* confirmation e-mail.
* Note that the password generation has been simplified, which
* means the password below is not really "safe"
* To enable script, prefix the first die(); with //.
*
* @package chamilo.cron.user_import
*/
/**
* Initialization.
*/
/* Example of input file:
sam@example.com
Matthew@example.com
HERMAN@example.com
*/
exit();
//change filename depending on file containing mails list, with one e-mail per line.
$list = file('input.txt');
require_once '../../inc/global.inc.php';
$users = Database::get_main_table(TABLE_MAIN_USER);
$userManager = UserManager::getManager();
$repository = UserManager::getRepository();
/**
* E-mails list loop.
*/
foreach ($list as $mail) {
$mail = trim($mail);
$sql = "SELECT user_id, official_code, firstname, lastname, email, username, language
FROM $users WHERE email = '$mail'\n";
$res = Database::query($sql);
if ($res === false) {
echo 'Error in database with email '.$mail."\n";
}
if (Database::num_rows($res) == 0) {
echo '[Error] Email not found in database: '.$row['email']."\n";
} else {
$row = Database::fetch_assoc($res);
$pass = api_substr($row['username'], 0, 4).rand(0, 9).rand(0, 9);
if ($user) {
/** @var User $user */
$user = $repository->find($row['user_id']);
$user->setPlainPassword($pass);
$userManager->updateUser($user, true);
} else {
echo "[Error] Error updating password. Skipping $mail\n";
continue;
}
$user = [
'FirstName' => $row['firstname'],
'LastName' => $row['lastname'],
'UserName' => $row['username'],
'Password' => $pass,
'Email' => $mail,
];
$l = api_get_interface_language();
if (!empty($row['language'])) {
$l = $row['language'];
}
//This comes from main/admin/user_import.php::save_data() slightly modified
$recipient_name = api_get_person_name(
$user['FirstName'],
$user['LastName'],
null,
PERSON_NAME_EMAIL_ADDRESS
);
$emailsubject = '['.api_get_setting('siteName').'] '.get_lang('YourReg', null, $l).' '.api_get_setting('siteName');
$emailbody = get_lang('Dear', null, $l).' '.api_get_person_name($user['FirstName'], $user['LastName']).",\n\n".get_lang('YouAreReg', null, $l)." ".api_get_setting('siteName')." ".get_lang('WithTheFollowingSettings', null, $l)."\n\n".get_lang('Username', null, $l)." : ".$user['UserName']."\n".get_lang('Pass', null, $l)." : ".$user['Password']."\n\n".get_lang('Address', null, $l)." ".api_get_setting('siteName')." ".get_lang('Is', null, $l)." : ".api_get_path(WEB_PATH)." \n\n".get_lang('Problem', null, $l)."\n\n".get_lang('Formula', null, $l).",\n\n".api_get_person_name(api_get_setting('administratorName'), api_get_setting('administratorSurname'))."\n".get_lang('Manager', null, $l)." ".api_get_setting('siteName')."\nT. ".api_get_setting('administratorTelephone')."\n".get_lang('Email', null, $l)." : ".api_get_setting('emailAdministrator')."";
$sender_name = api_get_person_name(api_get_setting('administratorName'), api_get_setting('administratorSurname'), null, PERSON_NAME_EMAIL_ADDRESS);
$email_admin = api_get_setting('emailAdministrator');
@api_mail_html(
$recipient_name,
$user['Email'],
$emailsubject,
$emailbody,
$sender_name,
$email_admin
);
echo "[OK] Sent to $mail with new password $pass (encrypted:$crypass)... w/ subject: $emailsubject\n";
}
}