parent
976c59d307
commit
cbff80577d
@ -1,215 +0,0 @@ |
||||
<?php |
||||
|
||||
/* For licensing terms, see /license.txt */ |
||||
|
||||
/** |
||||
* This script send notification messages to users that have reminders from an event in their agenda. |
||||
*/ |
||||
|
||||
use Chamilo\CoreBundle\Entity\AgendaReminder; |
||||
use Chamilo\CoreBundle\Entity\CourseRelUser; |
||||
use Chamilo\CoreBundle\Entity\SessionRelCourseRelUser; |
||||
use Chamilo\CourseBundle\Entity\CCalendarEvent; |
||||
|
||||
require_once __DIR__.'/../../main/inc/global.inc.php'; |
||||
|
||||
if ('cli' != php_sapi_name()) { |
||||
exit; //do not run from browser |
||||
} |
||||
|
||||
$batchCounter = 0; |
||||
$batchSize = 100; |
||||
|
||||
$now = new DateTime('now', new DateTimeZone('UTC')); |
||||
|
||||
$em = Database::getManager(); |
||||
$remindersRepo = $em->getRepository(AgendaReminder::class); |
||||
|
||||
/** @var array<AgendaReminder> $reminders */ |
||||
$reminders = $remindersRepo->findBy(['sent' => false]); |
||||
|
||||
$senderId = (int) api_get_setting('agenda.agenda_reminders_sender_id'); |
||||
|
||||
if (empty($senderId)) { |
||||
$firstAdmin = current(UserManager::get_all_administrators()); |
||||
$senderId = $firstAdmin['user_id']; |
||||
} |
||||
|
||||
foreach ($reminders as $reminder) { |
||||
$event = $reminder->getEvent(); |
||||
|
||||
if (null === $event) { |
||||
continue; |
||||
} |
||||
|
||||
$notificationDate = clone $event->getStartDate(); |
||||
$notificationDate->sub($reminder->getDateInterval()); |
||||
|
||||
if ($notificationDate > $now) { |
||||
continue; |
||||
} |
||||
|
||||
if ('course' !== $event->determineType()) { |
||||
$eventDetails = []; |
||||
$eventDetails[] = '<p><strong>'.$event->getTitle().'</strong></p>'; |
||||
|
||||
if ($event->isAllDay()) { |
||||
$eventDetails[] = '<p class="small">'.get_lang('All day').'</p>'; |
||||
} else { |
||||
$eventDetails[] = sprintf( |
||||
'<p class="small">'.get_lang('From %s').'</p>', |
||||
api_get_local_time($event->getStartDate(), null, null, false, true, true) |
||||
); |
||||
|
||||
if (!empty($event->getEnddate())) { |
||||
$eventDetails[] = sprintf( |
||||
'<p class="small">'.get_lang('Until %s').'</p>', |
||||
api_get_local_time($event->getEnddate(), null, null, false, true, true) |
||||
); |
||||
} |
||||
} |
||||
|
||||
if (!empty($event->getContent())) { |
||||
$eventDetails[] = $event->getContent(); |
||||
} |
||||
|
||||
$messageSubject = sprintf(get_lang('Reminder for event : %s'), $event->getTitle()); |
||||
$messageContent = implode(PHP_EOL, $eventDetails); |
||||
|
||||
MessageManager::send_message_simple( |
||||
$event->getResourceNode()->getCreator()->getId(), |
||||
$messageSubject, |
||||
$messageContent, |
||||
$event->getResourceNode()->getCreator()->getId() |
||||
); |
||||
|
||||
$getInviteesForEvent = function (?CCalendarEvent $event) use ($em) { |
||||
if (!$event) { |
||||
return []; |
||||
} |
||||
|
||||
$resourceLinks = $event->getResourceNode()->getResourceLinks(); |
||||
$inviteeList = []; |
||||
foreach ($resourceLinks as $resourceLink) { |
||||
$user = $resourceLink->getUser(); |
||||
if ($user) { |
||||
$inviteeList[] = [ |
||||
'id' => $user->getId(), |
||||
'name' => $user->getFullname(), |
||||
]; |
||||
} |
||||
} |
||||
|
||||
return $inviteeList; |
||||
}; |
||||
|
||||
$invitees = $getInviteesForEvent($reminder->getEvent()); |
||||
$inviteesIdList = array_column($invitees, 'id'); |
||||
foreach ($inviteesIdList as $userId) { |
||||
MessageManager::send_message_simple( |
||||
$userId, |
||||
$messageSubject, |
||||
$messageContent, |
||||
$event->getResourceNode()->getCreator()->getId() |
||||
); |
||||
} |
||||
} else { |
||||
$eventDetails = [ |
||||
sprintf('<p><strong>%s</strong></p>', $event->getTitle()), |
||||
$event->isAllDay() ? '<p class="small">All Day</p>' : sprintf( |
||||
'<p class="small">From %s</p>', |
||||
$event->getStartDate()->format('Y-m-d H:i:s') |
||||
) |
||||
]; |
||||
|
||||
if ($event->getEndDate()) { |
||||
$eventDetails[] = sprintf( |
||||
'<p class="small">Until %s</p>', |
||||
$event->getEndDate()->format('Y-m-d H:i:s') |
||||
); |
||||
} |
||||
|
||||
if ($event->getContent()) { |
||||
$eventDetails[] = $event->getContent(); |
||||
} |
||||
|
||||
if ($event->getComment()) { |
||||
$eventDetails[] = sprintf('<p class="small">%s</p>', $event->getComment()); |
||||
} |
||||
|
||||
$messageSubject = sprintf('Reminder: %s', $event->getTitle()); |
||||
$messageContent = implode(PHP_EOL, $eventDetails); |
||||
|
||||
$resourceLinks = $event->getResourceNode()->getResourceLinks(); |
||||
$userIdList = []; |
||||
$groupUserIdList = []; |
||||
|
||||
foreach ($resourceLinks as $resourceLink) { |
||||
if ($resourceLink->getUser()) { |
||||
$userIdList[] = $resourceLink->getUser()->getId(); |
||||
} elseif ($resourceLink->getGroup()) { |
||||
$groupUsers = GroupManager::get_users( |
||||
$resourceLink->getGroup()->getIid(), |
||||
false, |
||||
null, |
||||
null, |
||||
false, |
||||
$resourceLink->getCourse()?->getId() |
||||
); |
||||
foreach ($groupUsers as $groupUserId) { |
||||
$groupUserIdList[] = $groupUserId; |
||||
} |
||||
} else { |
||||
$course = $resourceLink->getCourse(); |
||||
|
||||
if ($session = $resourceLink->getSession()) { |
||||
$userSubscriptions = $session->getSessionRelCourseRelUserInCourse($course)->getValues(); |
||||
|
||||
$userIdList = array_map( |
||||
fn(SessionRelCourseRelUser $sessionCourseUserSubscription) => $sessionCourseUserSubscription->getUser()->getId(), |
||||
$userSubscriptions |
||||
); |
||||
} else { |
||||
$userSubscriptions = $course->getUsers()->getValues(); |
||||
|
||||
$userIdList = array_map( |
||||
fn(CourseRelUser $courseUserSubscription) => $courseUserSubscription->getUser()->getId(), |
||||
$userSubscriptions |
||||
); |
||||
} |
||||
} |
||||
} |
||||
|
||||
$userIdList = array_unique($userIdList); |
||||
$groupUserIdList = array_unique($groupUserIdList); |
||||
|
||||
foreach ($userIdList as $userId) { |
||||
MessageManager::send_message_simple( |
||||
$userId, |
||||
$messageSubject, |
||||
$messageContent, |
||||
$senderId |
||||
); |
||||
} |
||||
|
||||
foreach ($groupUserIdList as $groupUserId) { |
||||
MessageManager::send_message_simple( |
||||
$groupUserId, |
||||
$messageSubject, |
||||
$messageContent, |
||||
$senderId |
||||
); |
||||
} |
||||
} |
||||
|
||||
$reminder->setSent(true); |
||||
|
||||
$batchCounter++; |
||||
|
||||
if (($batchCounter % $batchSize) === 0) { |
||||
$em->flush(); |
||||
} |
||||
} |
||||
|
||||
$em->flush(); |
||||
$em->clear(); |
@ -1,89 +0,0 @@ |
||||
<?php |
||||
|
||||
/* For licensing terms, see /license.txt */ |
||||
/** |
||||
* 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 ('cli' != php_sapi_name()) { |
||||
exit; //do not run from browser |
||||
} |
||||
|
||||
$isActive = 'true' === api_get_setting('cron_remind_course_expiration_activate'); |
||||
|
||||
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'); |
||||
|
||||
$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->getTitle()); |
||||
|
||||
$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->getTitle()); |
||||
|
||||
$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->getTitle()}".PHP_EOL; |
||||
echo "End date: {$session->getAccessEndDate()->format('Y-m-d h:i')}".PHP_EOL; |
||||
} |
||||
} |
@ -1,16 +0,0 @@ |
||||
<?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(); |
@ -1,168 +0,0 @@ |
||||
<?php |
||||
/* For licensing terms, see /license.txt */ |
||||
/** |
||||
* Course expiration reminder. |
||||
* |
||||
* @author Imanol Losada <imanol.losada@beeznest.com> |
||||
*/ |
||||
require_once __DIR__.'/../inc/global.inc.php'; |
||||
|
||||
/** |
||||
* Initialization. |
||||
*/ |
||||
if ('cli' != php_sapi_name()) { |
||||
exit; //do not run from browser |
||||
} |
||||
|
||||
$isActive = 'true' === api_get_setting('cron_remind_course_expiration_activate'); |
||||
|
||||
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"; |
||||
} |
@ -1,88 +0,0 @@ |
||||
<?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 AND u.active <> ".USER_SOFT_DELETED; |
||||
|
||||
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('A user is waiting for an action about his/her personal data request'); |
||||
|
||||
$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_assoc($result)) { |
||||
$userId = $user['id']; |
||||
$userInfo = api_get_user_info($userId); |
||||
if ($userInfo) { |
||||
$content = sprintf( |
||||
get_lang('The user %s is waiting for an action about it\'s personal data request. |
||||
|
||||
To manage personal data requests you can follow this link : %s'), |
||||
$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; |
||||
} |
@ -1,58 +0,0 @@ |
||||
<?php |
||||
|
||||
/* For licensing terms, see /license.txt */ |
||||
|
||||
require_once __DIR__.'/../inc/global.inc.php'; |
||||
|
||||
$test = true; |
||||
|
||||
$em = Database::getManager(); |
||||
$table = Database::get_main_table(TABLE_MAIN_SESSION); |
||||
$sql = "SELECT * FROM $table "; |
||||
$result = Database::query($sql); |
||||
$now = api_get_utc_datetime(); |
||||
|
||||
$line = PHP_SAPI === 'cli' ? PHP_EOL : '<br />'; |
||||
echo 'Today is : '.$now.$line; |
||||
|
||||
while ($session = Database::fetch_array($result, 'ASSOC')) { |
||||
$id = $session['id']; |
||||
$start = $session['display_start_date']; |
||||
$end = $session['display_end_date']; |
||||
//$userCount = (int) $session['nbr_users']; |
||||
$userCount = (int) SessionManager::get_users_by_session($id, 0, true); |
||||
|
||||
// 1. Si une session a lieu dans le futur, c’est à dire que la date de début est supérieur à la date du |
||||
//jour alors elle est prévue |
||||
$status = 0; |
||||
if ($start > $now) { |
||||
$status = SessionManager::STATUS_PLANNED; |
||||
} |
||||
|
||||
// 2. Si une session a plus de 2 apprenants et que la date de début est inférieur ou égale à la date |
||||
// du jour et que la date de fin n'est pas passée alors mettre le statut en cours |
||||
if ($userCount >= 2 && $start <= $now && $end > $now) { |
||||
$status = SessionManager::STATUS_PROGRESS; |
||||
} |
||||
|
||||
// 3. Si une session n’a pas d’apprenant et que la date de début est passée alors mettre le statut à |
||||
//annulée. |
||||
if ($userCount === 0 && $now > $start) { |
||||
$status = SessionManager::STATUS_CANCELLED; |
||||
} |
||||
|
||||
// 4. Si la date de fin d'une session est dépassée et qu'elle a plus de 2 apprenants alors passer le |
||||
//statut à terminée |
||||
if ($now > $end && $userCount >= 2) { |
||||
$status = SessionManager::STATUS_FINISHED; |
||||
} |
||||
|
||||
$params = [ |
||||
'status' => $status, |
||||
]; |
||||
if ($test != true) { |
||||
Database::update($table, $params, ['id = ?' => $id]); |
||||
} |
||||
|
||||
echo "Session #$id updated. Status = ".SessionManager::getStatusLabel($status)."($status) User count= $userCount: Start date: $start - End date: $end".$line; |
||||
} |
@ -0,0 +1,190 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
/* For licensing terms, see /license.txt */ |
||||
|
||||
namespace Chamilo\CoreBundle\Command; |
||||
|
||||
use Chamilo\CoreBundle\Framework\Container; |
||||
use Chamilo\CoreBundle\Settings\SettingsManager; |
||||
use Database; |
||||
use DateTime; |
||||
use DateInterval; |
||||
use Doctrine\DBAL\Connection; |
||||
use Doctrine\ORM\EntityManager; |
||||
use MessageManager; |
||||
use Symfony\Component\Console\Command\Command; |
||||
use Symfony\Component\Console\Input\InputInterface; |
||||
use Symfony\Component\Console\Input\InputOption; |
||||
use Symfony\Component\Console\Output\OutputInterface; |
||||
use Symfony\Component\Console\Style\SymfonyStyle; |
||||
use Chamilo\CoreBundle\ServiceHelper\AccessUrlHelper; |
||||
use Chamilo\CoreBundle\Entity\User; |
||||
use Symfony\Component\Mailer\MailerInterface; |
||||
use Symfony\Bridge\Twig\Mime\TemplatedEmail; |
||||
use Symfony\Contracts\Translation\TranslatorInterface; |
||||
use UserManager; |
||||
|
||||
class ProcessUserDataRequestsCommand extends Command |
||||
{ |
||||
protected static $defaultName = 'app:process-user-data-requests'; |
||||
|
||||
public function __construct( |
||||
private readonly Connection $connection, |
||||
private readonly AccessUrlHelper $accessUrlHelper, |
||||
private readonly SettingsManager $settingsManager, |
||||
private readonly MailerInterface $mailer, |
||||
private readonly EntityManager $em, |
||||
private readonly TranslatorInterface $translator |
||||
) { |
||||
parent::__construct(); |
||||
} |
||||
|
||||
protected function configure(): void |
||||
{ |
||||
$this |
||||
->setDescription('Process user data requests for personal data actions.') |
||||
->addOption('debug', null, InputOption::VALUE_NONE, 'Enable debug mode') |
||||
->setHelp('This command processes user data requests that require administrative action.'); |
||||
} |
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int |
||||
{ |
||||
Database::setManager($this->em); |
||||
|
||||
$container = $this->getApplication()->getKernel()->getContainer(); |
||||
Container::setContainer($container); |
||||
|
||||
$io = new SymfonyStyle($input, $output); |
||||
$debug = $input->getOption('debug'); |
||||
|
||||
if ($debug) { |
||||
$io->note('Debug mode activated'); |
||||
} |
||||
|
||||
$defaultSenderId = 1; |
||||
$accessUrl = $this->accessUrlHelper->getCurrent(); |
||||
$numberOfDays = 7; |
||||
$date = new DateTime(); |
||||
$date->sub(new DateInterval('P' . $numberOfDays . 'D')); |
||||
$dateToString = $date->format('Y-m-d H:i:s'); |
||||
|
||||
if ($accessUrl) { |
||||
$message = $this->processUrlData($accessUrl->getId(), $defaultSenderId, $dateToString, $io, $debug); |
||||
if ($debug) { |
||||
$io->success($message); |
||||
} |
||||
} |
||||
|
||||
return Command::SUCCESS; |
||||
} |
||||
|
||||
private function processUrlData( |
||||
int $accessUrlId, |
||||
int $defaultSenderId, |
||||
string $dateToString, |
||||
SymfonyStyle $io, |
||||
bool $debug |
||||
): string { |
||||
|
||||
$sql = " |
||||
SELECT u.id, v.updated_at |
||||
FROM user AS u |
||||
INNER JOIN extra_field_values AS v ON u.id = v.item_id |
||||
WHERE (v.field_id IN (:deleteLegal, :deleteAccount)) |
||||
AND v.field_value = 1 |
||||
AND u.active <> :userSoftDeleted |
||||
AND v.updated_at < :dateToString |
||||
"; |
||||
|
||||
if ($this->accessUrlHelper->isMultiple()) { |
||||
$sql .= " AND EXISTS ( |
||||
SELECT 1 FROM access_url_rel_user rel |
||||
WHERE u.id = rel.user_id |
||||
AND rel.access_url_id = :accessUrlId)"; |
||||
} |
||||
|
||||
$extraFields = UserManager::createDataPrivacyExtraFields(); |
||||
$params = [ |
||||
'deleteLegal' => $extraFields['delete_legal'], |
||||
'deleteAccount' => $extraFields['delete_account_extra_field'], |
||||
'userSoftDeleted' => User::SOFT_DELETED, |
||||
'dateToString' => $dateToString, |
||||
'accessUrlId' => $accessUrlId |
||||
]; |
||||
|
||||
$result = $this->connection->fetchAllAssociative($sql, $params); |
||||
$usersToBeProcessed = []; |
||||
|
||||
foreach ($result as $user) { |
||||
$usersToBeProcessed[] = $user; |
||||
} |
||||
|
||||
if (empty($usersToBeProcessed)) { |
||||
return "No users waiting for data actions for Access URL ID: {$accessUrlId}"; |
||||
} |
||||
|
||||
return $this->processUsers($usersToBeProcessed, $defaultSenderId, $io, $debug); |
||||
} |
||||
|
||||
private function processUsers( |
||||
array $users, |
||||
int $defaultSenderId, |
||||
SymfonyStyle $io, |
||||
bool $debug |
||||
): string { |
||||
|
||||
$administrator = [ |
||||
'completeName' => $this->settingsManager->getSetting('admin.administrator_name'), |
||||
'email' => $this->settingsManager->getSetting('admin.administrator_email'), |
||||
]; |
||||
|
||||
$rootweb = $this->settingsManager->getSetting('platform.institution_url'); |
||||
$link = $rootweb . '/main/admin/user_list_consent.php'; |
||||
$subject = $this->translator->trans('A user is waiting for an action about his/her personal data request'); |
||||
$email = $this->settingsManager->getSetting('profile.data_protection_officer_email'); |
||||
$message = ''; |
||||
|
||||
foreach ($users as $user) { |
||||
$userId = $user['id']; |
||||
$userInfo = $this->connection->fetchAssociative("SELECT * FROM user WHERE id = ?", [$userId]); |
||||
$userInfo['complete_name'] = $userInfo['firstname'] . ' ' . $userInfo['lastname']; |
||||
$userInfo['complete_name_with_username'] = $userInfo['complete_name'].' ('.$userInfo['username'].')'; |
||||
|
||||
if (!$userInfo) { |
||||
continue; |
||||
} |
||||
|
||||
$content = $this->translator->trans( |
||||
'The user %name% is waiting for an action about his/her personal data request. To manage personal data requests you can follow this link: %link%', |
||||
['%name%' => $userInfo['complete_name'], '%link%' => $link] |
||||
); |
||||
|
||||
if ($email) { |
||||
$emailMessage = (new TemplatedEmail()) |
||||
->from($administrator['email']) |
||||
->to($email) |
||||
->subject($subject) |
||||
->html($content); |
||||
|
||||
$this->mailer->send($emailMessage); |
||||
} else { |
||||
MessageManager::sendMessageToAllAdminUsers($defaultSenderId, $subject, $content); |
||||
} |
||||
|
||||
$date = (new DateTime($user['updated_at']))->format('Y-m-d H:i:s'); |
||||
$message .= sprintf( |
||||
"User %s is waiting for an action since %s \n", |
||||
$userInfo['complete_name_with_username'], |
||||
$date |
||||
); |
||||
|
||||
if ($debug) { |
||||
$io->note("Processed user {$userInfo['complete_name']} with ID: {$userId}"); |
||||
} |
||||
} |
||||
|
||||
return $message; |
||||
} |
||||
} |
@ -0,0 +1,142 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
/* For licensing terms, see /license.txt */ |
||||
|
||||
namespace Chamilo\CoreBundle\Command; |
||||
|
||||
use Chamilo\CoreBundle\Entity\Session; |
||||
use Chamilo\CoreBundle\Entity\User; |
||||
use Chamilo\CoreBundle\Settings\SettingsManager; |
||||
use DateTime; |
||||
use DateTimeZone; |
||||
use Doctrine\ORM\EntityManagerInterface; |
||||
use Symfony\Component\Console\Command\Command; |
||||
use Symfony\Component\Console\Input\InputInterface; |
||||
use Symfony\Component\Console\Input\InputOption; |
||||
use Symfony\Component\Console\Output\OutputInterface; |
||||
use Symfony\Component\Console\Style\SymfonyStyle; |
||||
use Symfony\Component\Mailer\MailerInterface; |
||||
use Symfony\Component\Mime\Email; |
||||
use Twig\Environment; |
||||
use UserManager; |
||||
|
||||
class SendCourseExpirationEmailsCommand extends Command |
||||
{ |
||||
protected static $defaultName = 'app:send-course-expiration-emails'; |
||||
|
||||
public function __construct( |
||||
private readonly EntityManagerInterface $entityManager, |
||||
private readonly SettingsManager $settingsManager, |
||||
private readonly MailerInterface $mailer, |
||||
private readonly Environment $twig |
||||
) { |
||||
parent::__construct(); |
||||
} |
||||
|
||||
protected function configure(): void |
||||
{ |
||||
$this |
||||
->setDescription('Send an email to users when their course is finished.') |
||||
->addOption('debug', null, InputOption::VALUE_NONE, 'Enable debug mode') |
||||
->setHelp('This command sends an email to users whose course session is expiring today.'); |
||||
} |
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int |
||||
{ |
||||
$io = new SymfonyStyle($input, $output); |
||||
$debug = $input->getOption('debug'); |
||||
$now = new DateTime('now', new DateTimeZone('UTC')); |
||||
$endDate = $now->format('Y-m-d'); |
||||
|
||||
if ($debug) { |
||||
error_log('Debug mode activated'); |
||||
$io->note('Debug mode activated'); |
||||
} |
||||
|
||||
$isActive = 'true' === $this->settingsManager->getSetting('crons.cron_remind_course_expiration_activate'); |
||||
|
||||
if (!$isActive) { |
||||
if ($debug) { |
||||
error_log('Cron job for course expiration emails is not active.'); |
||||
$io->note('Cron job for course expiration emails is not active.'); |
||||
} |
||||
return Command::SUCCESS; |
||||
} |
||||
|
||||
$sessionRepo = $this->entityManager->getRepository(Session::class); |
||||
$sessions = $sessionRepo->createQueryBuilder('s') |
||||
->where('s.accessEndDate LIKE :date') |
||||
->setParameter('date', "$endDate%") |
||||
->getQuery() |
||||
->getResult(); |
||||
|
||||
if (empty($sessions)) { |
||||
$io->success("No sessions finishing today $endDate"); |
||||
return Command::SUCCESS; |
||||
} |
||||
|
||||
$administrator = [ |
||||
'complete_name' => $this->getAdministratorName(), |
||||
'email' => $this->settingsManager->getSetting('admin.administrator_email'), |
||||
]; |
||||
|
||||
foreach ($sessions as $session) { |
||||
$sessionUsers = $session->getUsers(); |
||||
|
||||
if (empty($sessionUsers)) { |
||||
$io->warning('No users to send mail for session: ' . $session->getTitle()); |
||||
continue; |
||||
} |
||||
|
||||
foreach ($sessionUsers as $sessionUser) { |
||||
$user = $sessionUser->getUser(); |
||||
$this->sendEmailToUser($user, $session, $administrator, $io, $debug); |
||||
} |
||||
} |
||||
|
||||
$io->success('Emails sent successfully for sessions expiring today.'); |
||||
return Command::SUCCESS; |
||||
} |
||||
|
||||
private function getAdministratorName(): string |
||||
{ |
||||
return api_get_person_name( |
||||
$this->settingsManager->getSetting('admin.administrator_name'), |
||||
$this->settingsManager->getSetting('admin.administrator_surname'), |
||||
null, |
||||
PERSON_NAME_EMAIL_ADDRESS |
||||
); |
||||
} |
||||
|
||||
private function sendEmailToUser(User $user, Session $session, array $administrator, SymfonyStyle $io, bool $debug): void |
||||
{ |
||||
$siteName = $this->settingsManager->getSetting('platform.site_name'); |
||||
|
||||
$subject = $this->twig->render('@ChamiloCore/Mailer/Legacy/cron_course_finished_subject.html.twig', [ |
||||
'session_name' => $session->getTitle(), |
||||
]); |
||||
|
||||
$body = $this->twig->render('@ChamiloCore/Mailer/Legacy/cron_course_finished_body.html.twig', [ |
||||
'complete_user_name' => UserManager::formatUserFullName($user), |
||||
'session_name' => $session->getTitle(), |
||||
'site_name' => $siteName, |
||||
]); |
||||
|
||||
$email = (new Email()) |
||||
->from($administrator['email']) |
||||
->to($user->getEmail()) |
||||
->subject($subject) |
||||
->html($body); |
||||
|
||||
$this->mailer->send($email); |
||||
|
||||
if ($debug) { |
||||
error_log("Email sent to: " . UserManager::formatUserFullName($user) . " ({$user->getEmail()})"); |
||||
$io->note("Email sent to: " . UserManager::formatUserFullName($user) . " ({$user->getEmail()})"); |
||||
$io->note("Session: {$session->getTitle()}"); |
||||
$io->note("End date: {$session->getAccessEndDate()->format('Y-m-d h:i')}"); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,146 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
/* For licensing terms, see /license.txt */ |
||||
|
||||
namespace Chamilo\CoreBundle\Command; |
||||
|
||||
use DateInterval; |
||||
use DateTime; |
||||
use DateTimeZone; |
||||
use Doctrine\DBAL\Connection; |
||||
use Symfony\Component\Console\Command\Command; |
||||
use Symfony\Component\Console\Input\InputInterface; |
||||
use Symfony\Component\Console\Input\InputOption; |
||||
use Symfony\Component\Console\Output\OutputInterface; |
||||
use Symfony\Component\Console\Style\SymfonyStyle; |
||||
use Symfony\Component\Mailer\Exception\TransportExceptionInterface; |
||||
use Symfony\Component\Mailer\MailerInterface; |
||||
use Symfony\Bridge\Twig\Mime\TemplatedEmail; |
||||
use Chamilo\CoreBundle\Settings\SettingsManager; |
||||
|
||||
class SendCourseExpirationRemindersCommand extends Command |
||||
{ |
||||
protected static $defaultName = 'app:send-course-expiration-reminders'; |
||||
|
||||
public function __construct( |
||||
private readonly Connection $connection, |
||||
private readonly MailerInterface $mailer, |
||||
private readonly SettingsManager $settingsManager |
||||
) { |
||||
parent::__construct(); |
||||
} |
||||
|
||||
protected function configure(): void |
||||
{ |
||||
$this |
||||
->setDescription('Send course expiration reminders to users.') |
||||
->addOption('debug', null, InputOption::VALUE_NONE, 'Enable debug mode') |
||||
->setHelp('This command sends email reminders to users before their course access expires.'); |
||||
} |
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int |
||||
{ |
||||
$io = new SymfonyStyle($input, $output); |
||||
$debug = $input->getOption('debug'); |
||||
|
||||
if ($debug) { |
||||
$io->note('Debug mode activated'); |
||||
} |
||||
|
||||
$isActive = 'true' === $this->settingsManager->getSetting('crons.cron_remind_course_expiration_activate'); |
||||
if (!$isActive) { |
||||
$io->warning('Course expiration reminder cron is not active.'); |
||||
return Command::SUCCESS; |
||||
} |
||||
|
||||
$frequency = (int) $this->settingsManager->getSetting('crons.cron_remind_course_expiration_frequency'); |
||||
$today = new DateTime('now', new DateTimeZone('UTC')); |
||||
$expirationDate = (clone $today)->add(new DateInterval("P{$frequency}D"))->format('Y-m-d'); |
||||
|
||||
$sessions = $this->getSessionsExpiringBetween($today->format('Y-m-d'), $expirationDate); |
||||
|
||||
if (empty($sessions)) { |
||||
$io->success("No users to be reminded."); |
||||
return Command::SUCCESS; |
||||
} |
||||
|
||||
foreach ($sessions as $session) { |
||||
$this->sendReminder($session, $io, $debug); |
||||
} |
||||
|
||||
$io->success('Course expiration reminders sent successfully.'); |
||||
return Command::SUCCESS; |
||||
} |
||||
|
||||
private function getSessionsExpiringBetween(string $today, string $expirationDate): array |
||||
{ |
||||
$sql = " |
||||
SELECT DISTINCT category.session_id, certificate.user_id, session.access_end_date, session.title as name |
||||
FROM gradebook_category AS category |
||||
LEFT JOIN gradebook_certificate AS certificate ON category.id = certificate.cat_id |
||||
INNER JOIN session AS session ON category.session_id = session.id |
||||
WHERE session.access_end_date BETWEEN :today AND :expirationDate |
||||
AND category.session_id IS NOT NULL AND certificate.user_id IS NOT NULL |
||||
"; |
||||
|
||||
return $this->connection->fetchAllAssociative($sql, [ |
||||
'today' => $today, |
||||
'expirationDate' => $expirationDate |
||||
]); |
||||
} |
||||
|
||||
|
||||
private function sendReminder(array $session, SymfonyStyle $io, bool $debug): void |
||||
{ |
||||
$userInfo = $this->getUserInfo((int) $session['user_id']); |
||||
$userInfo['complete_name'] = $userInfo['firstname'] . ' ' . $userInfo['lastname']; |
||||
$remainingDays = $this->calculateRemainingDays($session['access_end_date']); |
||||
|
||||
$administrator = [ |
||||
'completeName' => $this->settingsManager->getSetting('admin.administrator_name'), |
||||
'email' => $this->settingsManager->getSetting('admin.administrator_email'), |
||||
]; |
||||
|
||||
$institution = $this->settingsManager->getSetting('platform.institution'); |
||||
$rootWeb = $this->settingsManager->getSetting('platform.institution_url'); |
||||
|
||||
$email = (new TemplatedEmail()) |
||||
->from($administrator['email']) |
||||
->to($userInfo['email']) |
||||
->subject('Course Expiration Reminder') |
||||
->htmlTemplate('@ChamiloCore/Mailer/Legacy/cron_remind_course_expiration_body.html.twig') |
||||
->context([ |
||||
'complete_user_name' => $userInfo['complete_name'], |
||||
'session_name' => $session['name'], |
||||
'session_access_end_date' => $session['access_end_date'], |
||||
'remaining_days' => $remainingDays, |
||||
'institution' => $institution, |
||||
'root_web' => $rootWeb, |
||||
]); |
||||
|
||||
try { |
||||
$this->mailer->send($email); |
||||
|
||||
if ($debug) { |
||||
$io->note("Reminder sent to {$userInfo['complete_name']} ({$userInfo['email']}) for session: {$session['name']}"); |
||||
} |
||||
} catch (TransportExceptionInterface $e) { |
||||
$io->error("Failed to send reminder: {$e->getMessage()}"); |
||||
} |
||||
} |
||||
|
||||
private function getUserInfo(int $userId): array |
||||
{ |
||||
$sql = "SELECT * FROM user WHERE id = :userId"; |
||||
return $this->connection->fetchAssociative($sql, ['userId' => $userId]); |
||||
} |
||||
|
||||
private function calculateRemainingDays(string $accessEndDate): string |
||||
{ |
||||
$today = new DateTime('now', new DateTimeZone('UTC')); |
||||
$endDate = new DateTime($accessEndDate); |
||||
return $today->diff($endDate)->format('%d'); |
||||
} |
||||
} |
@ -0,0 +1,171 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
/* For licensing terms, see /license.txt */ |
||||
|
||||
namespace Chamilo\CoreBundle\Command; |
||||
|
||||
use Chamilo\CoreBundle\Entity\AgendaReminder; |
||||
use Chamilo\CoreBundle\Entity\User; |
||||
use Chamilo\CoreBundle\Settings\SettingsManager; |
||||
use Chamilo\CourseBundle\Entity\CCalendarEvent; |
||||
use Doctrine\ORM\EntityManagerInterface; |
||||
use MessageManager; |
||||
use Symfony\Component\Console\Command\Command; |
||||
use Symfony\Component\Console\Input\InputInterface; |
||||
use Symfony\Component\Console\Input\InputOption; |
||||
use Symfony\Component\Console\Output\OutputInterface; |
||||
use Symfony\Component\Console\Style\SymfonyStyle; |
||||
use DateTime; |
||||
use DateTimeZone; |
||||
|
||||
class SendEventRemindersCommand extends Command |
||||
{ |
||||
protected static $defaultName = 'app:send-event-reminders'; |
||||
|
||||
public function __construct( |
||||
private readonly EntityManagerInterface $entityManager, |
||||
private readonly SettingsManager $settingsManager |
||||
) { |
||||
parent::__construct(); |
||||
} |
||||
|
||||
protected function configure(): void |
||||
{ |
||||
$this |
||||
->setDescription('Send notification messages to users that have reminders from events in their agenda.') |
||||
->addOption('debug', null, InputOption::VALUE_NONE, 'Enable debug mode') |
||||
->setHelp('This command sends notifications to users who have pending reminders for calendar events.'); |
||||
} |
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int |
||||
{ |
||||
$io = new SymfonyStyle($input, $output); |
||||
$debug = $input->getOption('debug'); |
||||
$now = new DateTime('now', new DateTimeZone('UTC')); |
||||
|
||||
if ($debug) { |
||||
error_log('Debug mode activated'); |
||||
$io->note('Debug mode activated'); |
||||
} |
||||
|
||||
$remindersRepo = $this->entityManager->getRepository(AgendaReminder::class); |
||||
$reminders = $remindersRepo->findBy(['sent' => false]); |
||||
|
||||
$senderId = $this->settingsManager->getSetting('agenda.agenda_reminders_sender_id'); |
||||
$senderId = (int) $senderId ?: $this->getFirstAdminId(); |
||||
|
||||
$batchCounter = 0; |
||||
$batchSize = 100; |
||||
|
||||
foreach ($reminders as $reminder) { |
||||
$event = $reminder->getEvent(); |
||||
|
||||
if (!$event) { |
||||
if ($debug) { |
||||
error_log('No event found for reminder ID: ' . $reminder->getId()); |
||||
$io->note('No event found for reminder ID: ' . $reminder->getId()); |
||||
} |
||||
continue; |
||||
} |
||||
|
||||
$eventId = $event->getIid(); |
||||
$eventEntity = $this->entityManager->getRepository(CCalendarEvent::class)->find($eventId); |
||||
|
||||
if (!$eventEntity) { |
||||
if ($debug) { |
||||
error_log('No event entity found for event ID: ' . $eventId); |
||||
$io->note('No event entity found for event ID: ' . $eventId); |
||||
} |
||||
continue; |
||||
} |
||||
|
||||
$notificationDate = clone $event->getStartDate(); |
||||
$notificationDate->sub($reminder->getDateInterval()); |
||||
if ($notificationDate > $now) { |
||||
continue; |
||||
} |
||||
|
||||
$messageSubject = sprintf('Reminder for event: %s', $event->getTitle()); |
||||
$messageContent = $this->generateEventDetails($event); |
||||
$invitees = $this->getInviteesForEvent($event); |
||||
|
||||
foreach ($invitees as $userId) { |
||||
MessageManager::send_message_simple( |
||||
$userId, |
||||
$messageSubject, |
||||
$messageContent, |
||||
$senderId |
||||
); |
||||
|
||||
if ($debug) { |
||||
error_log("Message sent to user ID: $userId for event: " . $event->getTitle()); |
||||
$io->note("Message sent to user ID: $userId for event: " . $event->getTitle()); |
||||
} |
||||
} |
||||
|
||||
$reminder->setSent(true); |
||||
$batchCounter++; |
||||
|
||||
if (($batchCounter % $batchSize) === 0) { |
||||
$this->entityManager->flush(); |
||||
|
||||
if ($debug) { |
||||
error_log('Batch of reminders flushed'); |
||||
$io->note('Batch of reminders flushed'); |
||||
} |
||||
} |
||||
} |
||||
|
||||
$this->entityManager->flush(); |
||||
if ($debug) { |
||||
error_log('Final batch of reminders flushed'); |
||||
$io->note('Final batch of reminders flushed'); |
||||
} |
||||
|
||||
$io->success('Event reminders have been sent successfully.'); |
||||
|
||||
return Command::SUCCESS; |
||||
} |
||||
|
||||
private function getFirstAdminId(): int |
||||
{ |
||||
$admin = $this->entityManager->getRepository(User::class)->findOneByRole('ROLE_ADMIN'); |
||||
return $admin ? $admin->getId() : 1; |
||||
} |
||||
|
||||
private function generateEventDetails(CCalendarEvent $event): string |
||||
{ |
||||
$details = []; |
||||
$details[] = sprintf('<p><strong>%s</strong></p>', $event->getTitle()); |
||||
|
||||
if ($event->isAllDay()) { |
||||
$details[] = '<p class="small">All Day</p>'; |
||||
} else { |
||||
$details[] = sprintf('<p class="small">From %s</p>', $event->getStartDate()->format('Y-m-d H:i:s')); |
||||
if ($event->getEndDate()) { |
||||
$details[] = sprintf('<p class="small">Until %s</p>', $event->getEndDate()->format('Y-m-d H:i:s')); |
||||
} |
||||
} |
||||
|
||||
if ($event->getContent()) { |
||||
$details[] = $event->getContent(); |
||||
} |
||||
|
||||
return implode(PHP_EOL, $details); |
||||
} |
||||
|
||||
private function getInviteesForEvent(CCalendarEvent $event): array |
||||
{ |
||||
$inviteeList = []; |
||||
|
||||
foreach ($event->getResourceNode()->getResourceLinks() as $resourceLink) { |
||||
if ($user = $resourceLink->getUser()) { |
||||
$inviteeList[] = $user->getId(); |
||||
} |
||||
} |
||||
|
||||
return $inviteeList; |
||||
} |
||||
} |
@ -0,0 +1,62 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
/* For licensing terms, see /license.txt */ |
||||
|
||||
namespace Chamilo\CoreBundle\Command; |
||||
|
||||
use Chamilo\CoreBundle\Framework\Container; |
||||
use Database; |
||||
use Doctrine\ORM\EntityManager; |
||||
use Notification; |
||||
use Symfony\Component\Console\Command\Command; |
||||
use Symfony\Component\Console\Input\InputInterface; |
||||
use Symfony\Component\Console\Input\InputOption; |
||||
use Symfony\Component\Console\Output\OutputInterface; |
||||
use Symfony\Component\Console\Style\SymfonyStyle; |
||||
|
||||
class SendNotificationsCommand extends Command |
||||
{ |
||||
protected static $defaultName = 'app:send-notifications'; |
||||
|
||||
public function __construct( |
||||
private readonly EntityManager $em |
||||
) { |
||||
parent::__construct(); |
||||
} |
||||
|
||||
protected function configure(): void |
||||
{ |
||||
$this |
||||
->setDescription('Send notifications') |
||||
->addOption('debug', null, InputOption::VALUE_NONE, 'Enable debug mode') |
||||
->setHelp('This command sends notifications using the Notification class.'); |
||||
} |
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int |
||||
{ |
||||
Database::setManager($this->em); |
||||
|
||||
$container = $this->getApplication()->getKernel()->getContainer(); |
||||
Container::setContainer($container); |
||||
|
||||
$io = new SymfonyStyle($input, $output); |
||||
$debug = $input->getOption('debug'); |
||||
|
||||
if ($debug) { |
||||
error_log('Debug mode activated'); |
||||
$io->note('Debug mode activated'); |
||||
} |
||||
|
||||
$notification = new Notification(); |
||||
$notification->send(); |
||||
|
||||
if ($debug) { |
||||
error_log('Notifications have been sent.'); |
||||
$io->success('Notifications have been sent successfully.'); |
||||
} |
||||
|
||||
return Command::SUCCESS; |
||||
} |
||||
} |
@ -0,0 +1,100 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
/* For licensing terms, see /license.txt */ |
||||
|
||||
namespace Chamilo\CoreBundle\Command; |
||||
|
||||
use Chamilo\CoreBundle\Entity\Session; |
||||
use Chamilo\CoreBundle\Repository\SessionRepository; |
||||
use Doctrine\ORM\EntityManagerInterface; |
||||
use Symfony\Component\Console\Command\Command; |
||||
use Symfony\Component\Console\Input\InputInterface; |
||||
use Symfony\Component\Console\Output\OutputInterface; |
||||
use Symfony\Component\Console\Input\InputOption; |
||||
use Symfony\Component\Console\Style\SymfonyStyle; |
||||
use DateTime; |
||||
|
||||
class UpdateSessionStatusCommand extends Command |
||||
{ |
||||
protected static $defaultName = 'app:update-session-status'; |
||||
|
||||
public function __construct( |
||||
private readonly EntityManagerInterface $entityManager, |
||||
private readonly SessionRepository $sessionRepository |
||||
) |
||||
{ |
||||
parent::__construct(); |
||||
} |
||||
|
||||
protected function configure(): void |
||||
{ |
||||
$this |
||||
->setDescription('Updates the status of training sessions based on their dates and user count.') |
||||
->addOption('debug', null, InputOption::VALUE_NONE, 'Enable debug mode'); |
||||
} |
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int |
||||
{ |
||||
$io = new SymfonyStyle($input, $output); |
||||
$debug = $input->getOption('debug'); |
||||
$lineBreak = PHP_SAPI === 'cli' ? PHP_EOL : '<br />'; |
||||
|
||||
$now = new DateTime('now', new \DateTimeZone('UTC')); |
||||
$io->text('Today is: ' . $now->format('Y-m-d H:i:s') . $lineBreak); |
||||
|
||||
$sessions = $this->sessionRepository->findAll(); |
||||
|
||||
foreach ($sessions as $session) { |
||||
$id = $session->getId(); |
||||
$start = $session->getDisplayStartDate(); |
||||
$end = $session->getDisplayEndDate(); |
||||
$userCount = $this->sessionRepository->countUsersBySession($session->getId()); |
||||
|
||||
$status = $this->determineSessionStatus($start, $end, $userCount, $now); |
||||
|
||||
if ($debug) { |
||||
$startFormatted = $start ? $start->format('Y-m-d H:i:s') : 'N/A'; |
||||
$endFormatted = $end ? $end->format('Y-m-d H:i:s') : 'N/A'; |
||||
$io->note("Session #$id: Start date: {$startFormatted} - End date: {$endFormatted}"); |
||||
} |
||||
|
||||
$session->setStatus($status); |
||||
$this->sessionRepository->update($session); |
||||
} |
||||
|
||||
if ($debug) { |
||||
$io->success('Session statuses have been updated in debug mode (changes are not saved).'); |
||||
} else { |
||||
$this->entityManager->flush(); |
||||
$io->success('Session statuses have been updated successfully.'); |
||||
} |
||||
|
||||
return Command::SUCCESS; |
||||
} |
||||
|
||||
/** |
||||
* Determines the status of a session based on its start/end dates and user count. |
||||
*/ |
||||
private function determineSessionStatus(?DateTime $start, ?DateTime $end, int $userCount, DateTime $now): int |
||||
{ |
||||
if ($start > $now) { |
||||
return Session::STATUS_PLANNED; |
||||
} |
||||
|
||||
if ($userCount >= 2 && $start <= $now && $end > $now) { |
||||
return Session::STATUS_PROGRESS; |
||||
} |
||||
|
||||
if ($userCount === 0 && $now > $start) { |
||||
return Session::STATUS_CANCELLED; |
||||
} |
||||
|
||||
if ($now > $end && $userCount >= 2) { |
||||
return Session::STATUS_FINISHED; |
||||
} |
||||
|
||||
return Session::STATUS_UNKNOWN; |
||||
} |
||||
} |
@ -1 +1 @@ |
||||
<p>{{ 'MailCronCourseFinishedBody'|trans|format(complete_user_name, session_name, session_name, _s.site_name) }}</p> |
||||
<p>{{ 'MailCronCourseFinishedBody'|trans|format(complete_user_name, session_name, session_name, site_name) }}</p> |
||||
|
@ -1 +1 @@ |
||||
<p>{{ 'MailCronCourseExpirationReminderBody'|trans|format(complete_user_name, session_name, session_access_end_date, remaining_days, _p.web, _s.institution) }}</p> |
||||
<p>{{ 'MailCronCourseExpirationReminderBody'|trans|format(complete_user_name, session_name, session_access_end_date, remaining_days, root_web, institution) }}</p> |
||||
|
Loading…
Reference in new issue