<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use App\Entity\Menu;
use App\Entity\User;
use App\Entity\UserToken;
use App\Entity\NotificationTokens;
use App\Entity\Notification;
use App\Entity\MassiveNotification;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use App\Service\AppApiService;
use App\Service\FirebaseService;
use App\Service\NotificationService;
use App\Entity\AppPersonalAccount;
use App\Entity\MediaObject;
use App\Entity\AppCounterReading;
use App\Entity\DataReception;
use App\Entity\Accounts;
use App\Entity\ServiceOrderHistory;
use Symfony\Component\HttpKernel\KernelInterface;
use Psr\Log\LoggerInterface;
use Sentry;
use App\Repository\NotificationRepository;
use App\Message\NotificationMessage;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Messenger\Bridge\Amqp\Transport\AmqpStamp;
use Symfony\Component\Messenger\Stamp\SentStamp;
use Symfony\Component\Messenger\Exception\TransportExceptionInterface;
use Symfony\Component\Security\Core\Security;
class NotificationController extends AbstractController
{
public $datetime;
public $entityManager;
public $passwordEncoder;
public $appApiService;
public $firebaseService;
public $notificationService;
public $notifications;
private $kernel;
private LoggerInterface $logger;
private $bus;
private Security $security;
public function __construct(
?\DateTimeInterface $datetime,
EntityManagerInterface $entityManager,
AppApiService $appApiService,
KernelInterface $kernel,
FirebaseService $firebaseService,
NotificationService $notificationService,
LoggerInterface $logger,
NotificationRepository $notifications,
MessageBusInterface $bus,
Security $security
){
$this->datetime = $datetime;
$this->entityManager = $entityManager;
$this->appApiService = $appApiService;
$this->firebaseService = $firebaseService;
$this->notificationService = $notificationService;
$this->kernel = $kernel;
$this->logger = $logger;
$this->notifications = $notifications;
$this->bus = $bus;
$this->security = $security;
}
public function valid($requestFilds, $requiredFilds){
$errors = '';
foreach($requiredFilds as $f){
if(!isset($requestFilds[$f]))
$errors .= " $f";
}
return $errors;
}
private function customAuth($request){
$validUser = 'loe';
$validPassword = 'GE2666Mh4maRa79iMs5igRPD';
$login = $request->server->get('PHP_AUTH_USER');
$password = $request->server->get('PHP_AUTH_PW');
if ($login !== $validUser || $password !== $validPassword) {
return false;
}
return true;
}
#[Route('/api/create-notfication', name: 'create_notfication', methods: ['POST'])]
public function create_notfication(Request $request)
{
if (!$this->customAuth($request)) {
return new JsonResponse(['message' => 'Unauthorized'], 401, [
'WWW-Authenticate' => 'Basic realm="API Access"',
]);
}
$data = json_decode($request->getContent(), true);
file_put_contents('/var/www/symfony_docker/var/log/errorrrrrr.log', "\n\n\n" . print_r($data, true) . "\n", FILE_APPEND);
$valid = $this->valid( $data, ['user', 'title', 'body'] );
if( empty($valid) ){
$find = $this->entityManager->getRepository(User::class)->findOneBy(['id' => $data['user']]);
if($find){
$notification = new Notification();
$notification->setUsers($find);
$notification->setTitle( $data['title']);
$notification->setBody( $data['body']);
if(!empty($data['type']))
$notification->setType( $data['type']);
else
$notification->setType('text');
$notification->setDateEntered( new \DateTime() );
$notification->setStatus('new');
$this->entityManager->persist($notification);
$this->entityManager->flush();
$rez = ['rez' => true, 'id' => $notification->getId()];
// }else{
// $rez = ['registered' => false, $res];
// }
}else{
$rez = ['rez' => false, 'error' => "Користувача не знайдено"];
}
}else{
$rez = ['rez' => false, 'error' => "Не задано поля: $valid"];
}
$response = new JsonResponse();
$response->setData($rez);
return $response;
}
#[Route('/api/send-notfication', name: 'send_notfication', methods: ['GET'])]
public function send_notfication(Request $request)
{
$send = 0;
$err = 0;
$notifications = $this->entityManager->getRepository(Notification::class)->findBy(['status' => 'new']);
if($notifications){
file_put_contents('/var/www/symfony_docker/var/log/notification.log', "NOTIFICATIONS ************************ " . date('Y-m-d H:i:s') . "\n", FILE_APPEND);
// Витягуємо всі ID
$notificationIds = array_map(fn($n) => $n->getId(), $notifications);
// Масове оновлення статусу та дати
$this->entityManager->createQuery(
'UPDATE App\Entity\Notification n
SET n.status = :newStatus,
n.dateSend = :now
WHERE n.id IN (:ids)'
)
->setParameter('newStatus', 'in_progress')
->setParameter('now', new \DateTime())
->setParameter('ids', $notificationIds)
->execute();
// file_put_contents('/var/www/symfony_docker/var/log/errorrrrrr.log', "2222222222" . date('H:i:s') . "\n", FILE_APPEND);
// Тепер можна знову вибрати тільки оновлені
// $notifications = $this->entityManager
// ->getRepository(Notification::class)
// ->findBy(['id' => $notificationIds]);
foreach($notifications as $notification){
$send = 0;
$user = $notification->getUsers();
$tokensArr = [];
if($user){
file_put_contents('/var/www/symfony_docker/var/log/notification.log', "id:" . $user->getId() . " phone:" . $user->getUsername() . " notification:" . $notification->getId() . "\n", FILE_APPEND);
$tokens = $user->getUserTokens();
if(!empty($tokens) AND count($tokens) > 0){
}else{
$device_id = $user->getDeviceId();
$tokens = $this->entityManager->getRepository(UserToken::class)->findBy(['device_id' => $device_id, 'active' => true]);
}
$search_dublicate_tokens = [];
foreach($tokens as $token){
if(!$token->isActive())
continue;
// if(!isset($search_dublicate_tokens[$token->getTokenFcm()]))
// $search_dublicate_tokens[$token->getTokenFcm()] = true;
// else
// continue;
if(in_array($token->getTokenFcm(), $tokensArr)){
$token->setDateModified( new \DateTime() );
$token->setErrorDescription( "Дублюючий ключ" );
$token->setActive(false);
$this->entityManager->persist($token);
// $this->entityManager->persist($notification);
$this->entityManager->flush();
continue;
}
$tokensArr[] = $token->getTokenFcm();
$data = [
'id' => $notification->getId(),
'token' => $token->getTokenFcm(),
'title' => $notification->getTitle(),
'body' => $notification->getBody(),
'type' => $notification->getType(),
];
// file_put_contents('/var/www/symfony_docker/var/log/notification.log', print_r($data, true) . "st - " . date('H:i:s') . "\n", FILE_APPEND);
$resultJson = $this->firebaseService->sendCurl($data);
// file_put_contents('/var/www/symfony_docker/var/log/notification.log', $resultJson . "\n", FILE_APPEND);
// file_put_contents('/var/www/symfony_docker/var/log/errorrrrrr.log', " - " . date('H:i:s') . "\n", FILE_APPEND);
$notification->setDateSend( new \DateTime() );
$result = json_decode($resultJson, true);
if(!empty( $result['res'] )){
$send = 1;
$notification->setStatus('send');
$send++;
}elseif(!empty( $result['err'] )){
$send = 2;
// $token->setActive(false);
$notification->setStatus('error');
$notification->setError($notification->getError() . "\n" . date('Y-m-d H:i:s') . $token->getTokenFcm() . "\n" . $resultJson);
$err++;
if($result['err'] == 'Requested entity was not found.' OR $result['err'] == 'The registration token is not a valid FCM registration token'){
$token->setDateModified( new \DateTime() );
$token->setErrorDescription( $result['err'] );
$token->setActive(false);
}
}else{
$send = 3;
// $token->setActive(false);
$notification->setStatus('error');
$notification->setError($notification->getError() . "\n" . date('Y-m-d H:i:s') . $token->getTokenFcm() . "\n" . $resultJson);
$err++;
}
$this->entityManager->persist($token);
$this->entityManager->persist($notification);
}
}
/** Якщо ключа нема */
if($send == 0){
$notification->setStatus('not_token');
$notification->setError($notification->getError() . "\n" . date('Y-m-d H:i:s') . " Ключ не знайдено \n");
$this->entityManager->persist($notification);
}
$this->entityManager->flush();
}
file_put_contents('/var/www/symfony_docker/var/log/notification.log', "***********END************* " . date('H:i:s') . "\n", FILE_APPEND);
}else{
$rez = ['rez' => false, 'error' => "Незнайдено нових сповіщень!"];
}
$response = new JsonResponse();
$response->setData(['send' => $send, 'err' => $err]);
return $response;
}
#[Route('/api/create-notfication-actions', name: 'create_notfication_account', methods: ['POST'])]
public function create_notfication_account(Request $request)
{
$user = $this->security->getUser();
if(!$user OR !in_array('ROLE_ADMIN', $user->getRoles()) ){
if (!$this->customAuth($request) ) {
return new JsonResponse(['message' => 'Unauthorized'], 401, [
'WWW-Authenticate' => 'Basic realm="API Access"',
]);
}
}
$data = json_decode($request->getContent(), true);
$send = [];
$err = '';
$valid = $this->valid( $data, ['sender', 'msg-data'] );
if( empty($valid) ){
// $title = $data['msg-data']['title'];
if(isset($data['msg-data']['receivers']) OR isset($data['msg-data']['content'])){
switch ($data['msg-type']) {
case 'from-ns':
$send = $this->notificationService->fromNs($data);
break;
case 'number-phone':
$send = $this->notificationService->numberPhone($data);
break;
case 'notification-yur':
$send = $this->notificationService->notificationYur($data);
break;
case 'notification-all':
$send = $this->notificationService->notificationAll($data);
break;
}
$rez = ['rez' => true, 'send' => $send , 'error' => ""];
}else{
$rez = ['rez' => false, 'error' => "Не задано поля receivers або content"];
}
}else{
$rez = ['rez' => false, 'error' => "Не задано поля: $valid"];
}
$response = new JsonResponse();
$response->setData($rez);
return $response;
}
#[Route('/api/create-data-reception', name: 'create_notfication_data_reception', methods: ['POST'])]
public function create_notfication_data_reception(Request $request)
{
if (!$this->customAuth($request)) {
return new JsonResponse(['message' => 'Unauthorized'], 401, [
'WWW-Authenticate' => 'Basic realm="API Access"',
]);
}
$data = json_decode($request->getContent(), true);
// file_put_contents('/var/www/symfony_docker/var/log/errorrrrrr.log', "\n\n\n" . print_r($data, true) . "\n", FILE_APPEND);
$valid = $this->valid( $data, ['method', 'data'] );
if( empty($valid) ){
$DataReception = new DataReception();
$DataReception->setType( $data['method']);
$DataReception->setData( $data['data']);
$DataReception->setDateEntered( new \DateTime() );
$DataReception->setStatus('new');
$this->entityManager->persist($DataReception);
$this->entityManager->flush();
$rez = ['rez' => true, 'id' => $DataReception->getId()];
}else{
$rez = ['rez' => false, 'error' => "Не задано поля: $valid"];
}
$response = new JsonResponse();
$response->setData($rez);
return $response;
}
public function updateStatus($inf, $name='statusPlanning', $status = 'planned'){
$query = $this->entityManager->createQuery(
'UPDATE App\Entity\Accounts d
SET d.'.$name.' = :new_status
WHERE d.eic IN (:ids)'
);
$query->setParameter('new_status', $status);
$query->setParameter('ids', $inf); // Масив ID
$query->execute();
}
public function updateClearStatusPlan(){
$query = $this->entityManager->createQuery(
'UPDATE App\Entity\Accounts d SET d.statusPlanning = :new_status'
);
$query->setParameter('new_status', 'not_pllaned');
$query->execute();
$this->entityManager->clear();
}
#[Route('/cron-get-planned', name: 'cron_get_pllanned', methods: ['GET'])]
public function cron_get_pllanned(Request $request)
{
/** Дивлюся чи є планові на сьогодні */
$qb = $this->entityManager->createQueryBuilder();
$qb->select('d.id', 'd.dateEntered', 'd.type', 'd.status')
->from(DataReception::class, 'd')
->where('d.dateEntered >= :start')
->andWhere('d.dateEntered < :end')
->setParameter('start', (new \DateTime('today'))->setTime(0, 0, 0))
->setParameter('end', (new \DateTime('today'))->setTime(23, 59, 59));
$result = $qb->getQuery()->getArrayResult();
/** Якщо плнові на сьогодні відсутні тоді оновлюю всі записи */
if(count($result) == 0)
$this->updateClearStatusPlan();
/** Вибираю нові планові дані */
$DataReception = $this->entityManager->getRepository(DataReception::class)->findBy(['type' => 'planned', 'status' => 'new']);
/** Якщо відсутні нові дані тоді вихід */
if(empty($DataReception) AND count($DataReception) == 0)
die('No data');
/** Очищаю всі планові статуси щоб задати нові*/
$this->updateClearStatusPlan();
$eic = [];
foreach($DataReception as $data){
$infos = json_decode($data->getData(), true);
if(!is_array($infos))
continue;
foreach($infos as $acc_id => $inf){
if(count($inf) > 0)
array_push($eic, $inf[0]);
if(count($eic) == 500){
$this->updateStatus($eic);
$eic = [];
}
}
if(count($eic) > 0)
$this->updateStatus($eic);
// $this->entityManager->clear();
$data->setStatus('complate');
$this->entityManager->persist($data);
$this->entityManager->flush();
// print_r($infos);
}
echo count($DataReception); die;
}
#[Route('/cron-get-planned-status', name: 'cron_get_pllanned_status', methods: ['GET'])]
public function cron_get_pllanned_status(Request $request)
{
// $type = $request->query->get('type');
// $status = $request->query->get('status');
$query = $this->entityManager->createQuery(
'UPDATE App\Entity\Accounts d SET d.statusLight = :new_status'
);
$query->setParameter('new_status', 'enabled');
// disabled
// $query->setParameter('old_status', 'new');
// echo '<pre>';
$query->execute();
$this->entityManager->clear();
$DataReception = $this->entityManager->getRepository(DataReception::class)->findBy(['type' => 'all_acounts_light_data', 'status' => 'new']);
$eic = [];
foreach($DataReception as $data){
$infos = json_decode($data->getData(), true);
foreach($infos as $acc_id => $inf){
$code = array_keys($inf);
print_r($code[0]);
var_dump($inf[$code[0]]);
print_r($eic);
echo "<br>";
echo "<br>";
echo "<br>";
if(count($inf) > 0)
if($inf[$code[0]]){
array_push($eic, $code[0]);
}
if(count($eic) == 500){
$this->updateStatus($eic, 'statusLight', 'disabled');
$eic = [];
}
}
if(count($eic) > 0)
$this->updateStatus($eic, 'statusLight', 'disabled');
$data->setStatus('complate');
$this->entityManager->persist($data);
$this->entityManager->flush();
// print_r($infos);
}
echo count($DataReception); die;
}
#[Route('/api/get-account-all-data', name: 'get_account_all_data', methods: ['GET'])]
public function get_account_all_data(Request $request):Response
{
set_time_limit(0);
// echo '<pre>';
$i = 0;
$AppPersonalAccount = $this->entityManager->getRepository(AppPersonalAccount::class)->findBy(['counter' => null]);
foreach($AppPersonalAccount as $account){
// if(!empty( $account->getEic() ))
// continue;
$i++;
$data = [
'account' => trim( $account->getNumber() )
];
// echo $account->getId() . "<br>";
// echo $account->getNumber() . "<br>";
$res = json_decode( $this->appApiService->account_all_data($data) , true );
// print_r( $res );
// if($i > 5)
// die;
if(isset($res['rez']) AND $res['rez'] == 1 AND isset($res['data'][0])){
file_put_contents('/var/www/symfony_docker/var/log/errorrrrrr.log', print_r($res, true) . "\n", FILE_APPEND);
$account->setEic($res['data'][0]['eic_kod']);
$account->setCounter($res['data'][0]['counter']);
$this->entityManager->persist($account);
$this->entityManager->flush();
}
}
return new Response('1');
}
/** Додавання id crm LOE */
#[Route('/api/update-service-id', name: 'update_service_id', methods: ['POST'])]
public function update_service_id(Request $request)
{
if (!$this->customAuth($request)) {
return new JsonResponse(['message' => 'Unauthorized'], 401, [
'WWW-Authenticate' => 'Basic realm="API Access"',
]);
}
$data = json_decode($request->getContent(), true);
// file_put_contents('/var/www/symfony_docker/var/log/errorrrrrr.log', "\n\n\n" . print_r($data, true) . "\n", FILE_APPEND);
$valid = $this->valid( $data, ['id', 'id_crm'] );
if( empty($valid) ){
$ServiceOrderHistory = false;
if(is_int($data['id']))
$ServiceOrderHistory = $this->entityManager->getRepository(ServiceOrderHistory::class)->findOneBy(['id' => $data['id']]);
if(!$ServiceOrderHistory AND !empty($data['id_crm']))
$ServiceOrderHistory = $this->entityManager->getRepository(ServiceOrderHistory::class)->findOneBy(['idCrm' => $data['id_crm']]);
if($ServiceOrderHistory){
$ServiceOrderHistory->setIdCrm( $data['id_crm']);
if(!empty( $data['status'] ))
$ServiceOrderHistory->setStatus( $data['status'] );
else
$ServiceOrderHistory->setStatus( 'in_process' );
if(!empty( $data['description'] ))
$ServiceOrderHistory->setDescription( $data['description'] );
if(!empty( $data['message'] ))
$ServiceOrderHistory->setMessage( $data['message'] );
$ServiceOrderHistory->setDateModified( new \DateTime() );
// $ServiceOrderHistory->setStatus('new');
$this->entityManager->persist($ServiceOrderHistory);
$this->entityManager->flush();
$rez = ['rez' => true, 'id' => $ServiceOrderHistory->getId()];
}else{
$rez = ['false' => false, 'error' => "Заявку не знайдено id не вірне"];
}
}else{
$rez = ['rez' => false, 'error' => "Не задано поля: $valid"];
}
$response = new JsonResponse();
$response->setData($rez);
return $response;
}
/** Додавання id crm LOE */
#[Route('/api/get-service-id', name: 'get_service_id', methods: ['GET', 'POST'])]
public function get_service_id(Request $request)
{
if (!$this->customAuth($request)) {
return new JsonResponse(['message' => 'Unauthorized'], 401, [
'WWW-Authenticate' => 'Basic realm="API Access"',
]);
}
$arr = [];
$ServiceOrderHistory = $this->entityManager->getRepository(ServiceOrderHistory::class)->findBy(['status' => 'in_process']);
foreach($ServiceOrderHistory as $service){
$arr[] = [
'id' => $service->getId(),
'id_crm' => $service->getIdCrm(),
];
}
$rez = ['rez' => true, 'data' => $arr];
$response = new JsonResponse();
$response->setData($rez);
return $response;
}
/** Історія заявок з сторонніх систем */
#[Route('/api/create-order-history', name: 'create_order_history', methods: ['POST'])]
public function create_order_history(Request $request)
{
if (!$this->customAuth($request)) {
return new JsonResponse(['message' => 'Unauthorized'], 401, [
'WWW-Authenticate' => 'Basic realm="API Access"',
]);
}
$data = json_decode($request->getContent(), true);
$valid = $this->valid( $data, ['phone', 'account', 'service_code', 'status', 'id_crm'] );
if( empty($valid) ){
$find = $this->entityManager->getRepository(User::class)->findOneBy(['phone' => $data['phone']]);
if($find){
$arr = [];
$orderNames = [
9 => "Встановлення зонного лічильника",
10 => "Лічильник не працює",
21 => "Неправильний показ",
32 => "Зміна власника",
35 => "Підключення електроустановок замовника після виконання ТУ",
63 => "Звернення щодо підозри на крадіжку",
79 => "Заміна автоматичного вимикача, який опломбований ОСР",
85 => "Відсутність пломб на засобі обліку",
86 => "Закриття особового рахунку",
200 => "Попередній запис в електронну чергу",
];
$account = false;
foreach($find->getAppPersonalAccounts() as $acc){
if(trim( $acc->getNumber() ) == $data['account'])
$account = $acc;
}
if(!$account AND count($find->getAppPersonalAccounts()) > 0){
$account = $find->getAppPersonalAccounts()[0];
}
if($account){
$ServiceOrderHistory = new ServiceOrderHistory();
$ServiceOrderHistory->setName($orderNames[$data['service_code']]);
$ServiceOrderHistory->setDateEntered( new \DateTime() );
$ServiceOrderHistory->setType($data['service_code']);
$ServiceOrderHistory->setStatus('new');
$ServiceOrderHistory->setPersonalAccount($account);
if(!empty( $data['id_crm'] ))
$ServiceOrderHistory->setIdCrm( $data['id_crm']);
if(!empty( $data['status'] ))
$ServiceOrderHistory->setStatus( $data['status'] );
else
$ServiceOrderHistory->setStatus( 'in_process' );
if(!empty( $data['description'] ))
$ServiceOrderHistory->setDescription( $data['description'] );
if($data['service_code'] == 200){
$ServiceOrderHistory->setStatus('-100');
$ServiceOrderHistory->setDescription('Виконано');
}
$ServiceOrderHistory->setPersonalAccount($account);
$this->entityManager->persist($ServiceOrderHistory);
$this->entityManager->flush();
$data["id"] = $ServiceOrderHistory->getId();
$rez = ['rez' => true, 'data' => [
'id' => $ServiceOrderHistory->getId()
]];
}else{
$rez = ['rezult' => false, 'error' => "Нема жодного особового рахунку"];
}
}else{
$rez = ['rezult' => false, 'error' => "Користувача не знайдено!"];
}
}else{
$rez = ['rez' => false, 'error' => "Не задано поля: $valid"];
}
$response = new JsonResponse();
$response->setData($rez);
return $response;
}
#[Route('/notifications/health', name: 'notifications_health', methods: ['GET'])]
public function notifications_health(): JsonResponse
{
$now = new \DateTimeImmutable('now');
// За поточний день (з 00:00 локального часу сервера)
$startOfDay = $now->setTime(0, 0, 0);
// За останню годину
$lastHour = $now->modify('-1 hour');
$dayAgg = $this->notifications->getTotalsFrom($startOfDay);
$hourAgg = $this->notifications->getTotalsFrom($lastHour);
$makeCheck = static function (int $total, int $errors): array {
$errorRate = $total > 0 ? $errors / $total : 0.0;
return [
'total' => $total,
'errors' => $errors,
'errorRate' => round($errorRate, 4), // 0.3142 => 31.42%
'over10' => $total > 10,
'over30pct' => $errorRate > 0.60,
'alert' => ($total > 10) && ($errorRate > 0.30),
];
};
$h = $makeCheck($hourAgg['total'], $hourAgg['errors']);
$d = $makeCheck($hourAgg['total'], $hourAgg['errors']);
// echo $_ENV['WHATSAPP_CHAT_ID']; die;
if($h['total'] > 10 AND $h['over30pct'] ){
$time = date('Y-m-d H:i:s');
$from = 'instance98373';
// відправка повідомлення
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://bot.inneti.com/whatsapp_group/loe_report_2.php');
curl_setopt($ch, CURLOPT_TIMEOUT, 120);
curl_setopt($ch, CURLOPT_BUFFERSIZE, 128);
curl_setopt(
$ch,
CURLOPT_POSTFIELDS,
[
"msg_text" => 'Увага! В базі знайдено більше 30% ненадісланих сповіщень за останню годину! ('.$h['errors'].' з '.$h['total'].')',
"from" => $from,
"whatsapp_chat_id" => $_ENV['WHATSAPP_CHAT_ID'],
"token" =>"pg9n1fef6pkesrsl",
"time" => $time,
"hash" => hash_hmac('md5', "$from;$time;", "$time;asdINNasd;$time"),
'mm_type' => 'text',
]
);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_PROXY, "");
$answer = curl_exec($ch);
$error = curl_error($ch);
curl_close($ch);
}
$result = [
'now' => $now->format(DATE_ATOM),
'day' => $d,
'hour' => $h,
'thresholds' => [
'minTotal' => 10,
'maxErrorRate'=> 0.30,
'errorStatuses'=> ['error','failed','warning'],
],
];
return $this->json($result);
}
#[Route('/notification/test', name: 'notification_test', methods: ['GET'])]
public function notification_test(): JsonResponse
{
$userIds = [
// 42,
// 31,
// 33,
// // 34,
// 35,
// 37,
// 38,
];
$h = date('H');
if($h < 12){
$t= " Гарного ранку ❤️";
}elseif($h < 15){
$t= " Гарного дня ❤️";
}elseif($h < 22){
$t= " Гарного вечора ❤️";
}else{
$t= " Спите ? 😊😊😊";
}
foreach($userIds as $userId){
$find = $this->entityManager->getRepository(User::class)->findOneBy(['id' => $userId]);
if($find){
$notification = new Notification();
$notification->setUsers($find);
$notification->setTitle('Тестове сповіщення!');
$notification->setBody( date('Y-m-d H:i:s') . "\n Тестове сповіщення! \n Система розсилки повідомлень працює коректно. \n Якщо ви це читаєте, значить все добре! \n $t");
$notification->setType('text');
$notification->setDateEntered( new \DateTime() );
$notification->setStatus('new');
$this->entityManager->persist($notification);
$this->entityManager->flush();
}
}
return $this->json(['status' => 'ok']);
}
#[Route('/notification/test2', name: 'notification_test_t', methods: ['GET'])]
public function notification_test_t(): JsonResponse
{
$userIds = [
31,
];
foreach($userIds as $userId){
$find = $this->entityManager->getRepository(User::class)->findOneBy(['id' => $userId]);
if($find){
$notification = new Notification();
$notification->setUsers($find);
$notification->setTitle('Тестове сповіщення!');
$notification->setBody( date('Y-m-d H:i:s') . "\n TEST 3 ");
$notification->setType('text');
$notification->setDateEntered( new \DateTime() );
$notification->setStatus('new');
$this->entityManager->persist($notification);
$this->entityManager->flush();
}
}
return $this->json(['status' => 'ok']);
}
/** Додавання сповіщень в чергу з статусом "new" */
#[Route('/api/add-notification-in-queue', name: 'add_notification_in_queue', methods: ['GET'])]
public function add_notification_in_queue(Request $request)
{
if(file_exists('/var/www/symfony_docker/var/log/notificationCron.log')){
$logCron = file_get_contents('/var/www/symfony_docker/var/log/notificationCron.log');
if(!empty( $logCron )){
$fileContents = json_decode($logCron, true);
$lastRunTime = isset($fileContents['start']) ? strtotime($fileContents['start']) : 0;
$currentTime = time();
if( $fileContents['cron'] == 'Start' ){
// Якщо останній запуск був менше ніж 5 хвилин тому, завершуємо виконання
echo "$currentTime - $lastRunTime = " . ($currentTime - $lastRunTime);
if (($currentTime - $lastRunTime) > 300) {
$logCron = json_encode([
'cron' => 'Stop',
'stop' => date('Y-m-d H:i:s'),
'info' => 'The cron job was run less than 5 minutes ago. Exiting to prevent overlap.'
]);
file_put_contents('/var/www/symfony_docker/var/log/notificationCron.log', $logCron);
}
var_dump($logCron);
die;
}
}
}
file_put_contents('/var/www/symfony_docker/var/log/notificationCron.log', json_encode([
'cron' => 'Start',
'start' => date('Y-m-d H:i:s'),
'info' => 'Start notification cron'
]));
// file_put_contents('/var/www/symfony_docker/var/log/notificationCron.log');
$send = 0;
$err = 0;
/** Витягую всі ід сповіщень */
$notifications = $this->entityManager->createQuery(
'SELECT n.id FROM App\Entity\Notification n WHERE n.status = :status'
)
->setParameter('status', 'new')
->getScalarResult();
$ids = array_map(fn($r) => (int)$r['id'], $notifications);
if($ids AND count($ids) > 0){
$dateStart = date('Y-m-d H:i:s');
file_put_contents('/var/www/symfony_docker/var/log/notification.log', "\n\n\n\nSTART-QUEUE-rabbitmq***************************** " . $dateStart . "\n", FILE_APPEND);
file_put_contents('/var/www/symfony_docker/var/log/notification.log', "new ids - " . implode(',', $ids) . "\n", FILE_APPEND);
// Масове оновлення статусу та дати
$this->entityManager->createQuery(
'UPDATE App\Entity\Notification n
SET n.status = :newStatus,
n.dateSend = :now
WHERE n.id IN (:ids)'
)
->setParameter('newStatus', 'in_progress')
->setParameter('now', new \DateTime())
->setParameter('ids', $ids)
->execute();
foreach($ids as $id){
$send = 0;
$priority = 1;
file_put_contents('/var/www/symfony_docker/var/log/notification.log', "#{$id} add to rabbitmq - " . date('H:i:s.u') . "\n", FILE_APPEND);
$queued = false;
$error = null;
try {
$env = $this->bus->dispatch(new NotificationMessage($id, [], 'send-notification', $priority));
// Якщо повідомлення надіслано у транспорт — з’являться SentStamp-и
$sentStamps = $env->all(SentStamp::class);
if (!empty($sentStamps)) {
$send++;
file_put_contents('/var/www/symfony_docker/var/log/notification.log', "#{$id} rabbitmq-success " . date('H:i:s.u') . "\n", FILE_APPEND);
$queued = true;
// для логів можна подивитись куди саме:
$targets = array_map(fn(SentStamp $s) => $s->getSenderAlias() ?? $s->getTransportName(), $sentStamps);
file_put_contents('/var/www/symfony_docker/var/log/notification.log', 'Sent to: '.implode(', ', $targets).PHP_EOL, FILE_APPEND);
} else {
$err++;
// це означає, що роутінг не відправив у транспорт (наприклад, sync bus)
$queued = false;
$error = 'No SentStamp: message was not routed to a transport';
file_put_contents('/var/www/symfony_docker/var/log/notification.log', "#{$id} rabbitmq-error " . date('H:i:s.u') . " - No SentStamp: message was not routed to a transport\n", FILE_APPEND);
}
} catch (TransportExceptionInterface $e) {
// Помилки транспорту/брокера (у т.ч. коли confirm_publish=true і брокер не підтвердив)
$queued = false;
$error = $e->getMessage();
$err++;
file_put_contents('/var/www/symfony_docker/var/log/notification.log', "#{$id} rabbitmq-TransportExceptionInterface " . date('H:i:s.u') . " - " . $e->getMessage() . "\n", FILE_APPEND);
} catch (\Throwable $e) {
// будь-яка інша помилка
$queued = false;
$error = $e->getMessage();
$err++;
file_put_contents('/var/www/symfony_docker/var/log/notification.log', "#{$id} rabbitmq-Throwable " . date('H:i:s.u') . " - " . $e->getMessage() . "\n", FILE_APPEND);
}
}
file_put_contents('/var/www/symfony_docker/var/log/notification.log', "END-QUEUE-rabbitmq***************************** start-$dateStart end-" . date('Y-m-d H:i:s') . "\n", FILE_APPEND);
file_put_contents('/var/www/symfony_docker/var/log/notification.log', "22222222222222222222\n", FILE_APPEND);
}else{
$rez = ['rez' => false, 'error' => "Незнайдено нових сповіщень!"];
}
$logCron = json_encode([
'cron' => 'Stop',
'stop' => date('Y-m-d H:i:s'),
'info' => 'Notification cron complete'
]);
file_put_contents('/var/www/symfony_docker/var/log/notificationCron.log', $logCron);
$response = new JsonResponse();
$response->setData(['send' => $send, 'err' => $err]);
return $response;
}
}