<?php
namespace App\Command;
use App\Model\UserModel;
use DateTime;
use Pimcore\Db;
use GuzzleHttp\Client;
use Pimcore\Log\Simple;
use App\Service\RedisCache;
use App\Model\LocationModel;
use GuzzleHttp\Psr7\Request;
use App\Service\EmailService;
use Pimcore\Model\DataObject;
use App\Model\EwsNotificationModel;
use App\Service\NCMWeatherAPIService;
use App\Service\MeteomaticsWeatherService;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Templating\EngineInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use App\C2IntegrationBundle\Service\C2Service;
use App\Service\RichService;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Pimcore\Model\DataObject\FetchSentEwsEmail;
use Symfony\Contracts\Translation\TranslatorInterface;
use Pimcore\Log\ApplicationLogger;
use Pimcore\Model\DataObject\Customer;
class StoreMannedToEwsAlertCommand extends Command
{
protected static $defaultName = 'app:get-manned-in-ews-alerts';
private EmailService $emailService;
private EngineInterface $templating;
private NCMWeatherAPIService $ncmWeatherAPIService;
private RedisCache $redisCache;
private LocationModel $locationModel;
private EwsNotificationModel $ewsNotificationModel;
private $userModel;
private C2Service $c2Service;
private RichService $richService;
private HttpClientInterface $httpClient;
private TranslatorInterface $translator;
private ApplicationLogger $logger;
public function __construct(
EngineInterface $templating,
RedisCache $redisCache,
RichService $richService,
HttpClientInterface $httpClient,
TranslatorInterface $translator,
ApplicationLogger $logger
) {
parent::__construct();
$this->templating = $templating;
$this->redisCache = $redisCache;
$this->richService = $richService;
$this->httpClient = $httpClient;
$this->translator = $translator;
$this->logger = $logger;
$this->ncmWeatherAPIService = new NCMWeatherAPIService($redisCache, $httpClient);
$this->locationModel = new LocationModel();
$this->ewsNotificationModel = new EwsNotificationModel();
$this->userModel = new UserModel();
$this->c2Service = new C2Service();
$this->emailService = new EmailService();
}
protected function configure(): void
{
$this->setDescription('Retrieve manned alerts by location and store in EwsNotification object');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$alerts = $this->ncmWeatherAPIService->getAlerts();
if (!$alerts) {
$output->writeln('No alerts found.');
return Command::SUCCESS;
}
foreach ($alerts as $alert) {
try {
$ewsAlert = $this->createOrUpdateAlertNotification($alert);
if (!$ewsAlert) {
$output->writeln('Nothing updated on notification = ' . $alert['id']);
continue;
}
if ($_ENV['SEND_EMAIL_NOTIFICATION'] === "false") {
$output->writeln('Email notifications are disabled in this environment.');
continue;
}
if (!$ewsAlert->getIsSent()) {
$this->processSubscriptionsForAlert($alert, $ewsAlert, $output);
}
$ewsAlert->setIsSent(true);
$ewsAlert->save();
} catch (\Exception $ex) {
$output->writeln('Error processing alert ID ' . $alert['id'] . ': ' . $ex->getMessage());
$this->logger->error($ex->getMessage());
}
}
return Command::SUCCESS;
}
private function processSubscriptionsForAlert(array $alert, DataObject\EwsNotification $ewsAlert, OutputInterface $output): void
{
$subscriptions = new DataObject\MannedAlertSubscription\Listing();
$subscriptions->setOrderKey('o_creationDate');
$subscriptions->setOrder('desc');
foreach ($subscriptions as $subscription) {
if ($subscription->getIsPublic() === true) {
continue; // skip public subscriptions
}
if (!$this->subscriptionMatchesAlert($subscription, $alert)) {
continue;
}
// Send notifications based on subscription settings
if ($subscription->getNotifyEmail()) {
$users = $this->getUsersFromSubscription($subscription);
foreach ($users as $user) {
if ($user instanceof \Pimcore\Model\DataObject\Customer && $user->getSevereWeatherAlert()) {
$this->sendEmailNotification($user, $alert, null, true, $ewsAlert);
}
}
}
// SMS Notifications
if ($subscription->getNotifySms()) {
$users = $this->getUsersFromSubscription($subscription);
foreach ($users as $user) {
if ($user instanceof \Pimcore\Model\DataObject\Customer && $user->getSevereWeatherAlert()) {
$this->sendAlertSMS($ewsAlert, $alert, $user);
}
}
}
}
}
private function subscriptionMatchesAlert(DataObject\MannedAlertSubscription $subscription, array $alert): bool
{
// Region check
$regionMatch = false;
if ($region = $subscription->getRegion()) {
$regionMatch = ($region->getRegionId() == $alert['regionID']);
}
// Alert type check
$alertTypeMatch = false;
if ($alertTypes = $subscription->getAlertType()) {
foreach ($alertTypes as $alertType) {
if ($alertType->getAlertTypeId() == $alert['alertType']) {
$alertTypeMatch = true;
break;
}
}
}
// Governorate check
$governorateMatch = false;
$alertGovernorateIds = array_column($alert['governorates'], 'id');
if ($governorates = $subscription->getGovernorate()) {
foreach ($governorates as $governorate) {
if (in_array($governorate->getGovernoteId(), $alertGovernorateIds)) {
$governorateMatch = true;
break;
}
}
}
// Alert status check (phenomena)
$phenomenaMatch = false;
if ($alertStatuses = $subscription->getAlertStatus()) {
foreach ($alertStatuses as $status) {
if ($status->getAlertStatusId() == $alert['alertStatusID']) {
$phenomenaMatch = true;
break;
}
}
}
return $regionMatch && $alertTypeMatch && $governorateMatch && $phenomenaMatch;
}
private function getUsersFromSubscription(DataObject\MannedAlertSubscription $subscription): array
{
$owner = $subscription->getCreator();
$subscribers = $subscription->getSubscribers();
$users = [];
if ($owner) {
$users[] = $owner;
}
if (is_array($subscribers) || $subscribers instanceof \Traversable) {
foreach ($subscribers as $subscriber) {
$users[] = $subscriber;
}
}
return $users;
}
private function sendEmailNotification($user, array $alert, ?string $email = null, bool $actualUser = false, DataObject\EwsNotification $alertObject): ?bool
{
if (!$alert) {
return null;
}
$governorates = array_map(fn($g) => $g['nameEn'], $alert['governorates'] ?? []);
$alertHazardsEn = [];
$alertHazardsAr = [];
foreach ($alert['alertHazards'] ?? [] as $hazard) {
$alertHazardsEn[] = $hazard['descriptionEn'];
$alertHazardsAr[] = ['nameAr' => $hazard['descriptionAr']];
}
$alertActions = array_map(fn($action) => $action['descriptionEn'], $alert['alertActions'] ?? []);
//$subject = $alert['alertStatusAr'] . ' - ' . $alert['regionAR'];
$subject = 'الإنذار - ' . ($alert['regionAR'] ?? '') . ' - ' . ($alert['id'] ?? '');
$data = $alert;
$data['sender'] = 'National Center for Meteorology';
if ($user) {
$entityUserSubscriptionMain = $this->userModel->getEntitySubscription($user);
$packageExpiredMain = $entityUserSubscriptionMain ? (new \DateTime() > $entityUserSubscriptionMain->getEndDate() ? true : false) : false;
$subActiveMain = $entityUserSubscriptionMain ? $entityUserSubscriptionMain->getIsActive() : false;
$subUserMain = $subActiveMain && !$packageExpiredMain;
if ($subUserMain) {
$data['name'] = $email ?? $user->getName();
$alertTypeObj = \Pimcore\Model\DataObject\AlertType::getByAlertTypeId($alert['alertType'], true);
$alertColor = $alertTypeObj ? $alertTypeObj->getColor() : '';
$alert['user_name'] = $email ?? $user->getName();
$alert['host'] = API_BASE_URL;
$alert['alertColor'] = $alertColor;
$currentDate = new DateTime($alert['fromDate']);
$alert['searchEwsIdAr'] = 'النظام الالي للإنذار المبكر | ' . $currentDate->format('dmY') . '-' . $alert['id'] . ' | ' . $alert['alertTypeAr'] . ' | ' . $alert['alertStatusAr'];
$alert['alertHazard'] = $alertHazardsAr;
$alert['last_modified_date'] = $alert['lastModified'];
if ($actualUser) {
$token = \App\Lib\Utility::getUnSubscribeToken($user->getId());
$alert['tokenURL'] = BASE_URL . '/unsubscribe/email?token=' . $token;
} else {
$alert['tokenURL'] = null;
}
$alert['mannedAlertDatailUrl'] = "https://ncm.gov.sa/Ar/alert/Pages/MapDetail.aspx?AlertId=" . $alert['id'];
$html = $this->templating->render('web2print/_manned_alert_notification_ar.html.twig', $alert);
$mannedAlert = \Pimcore\Model\DataObject\EwsNotification::getByAlertId($alert['id'], true);
$purpose = MANNED_ALERT_MESSAGE;
if ($email) {
$mailSent = $this->c2Service->sendDefaultEmail($_ENV['EWS_MAIL_TEMPLATE'], $mannedAlert->getId(), $email, $html, $subject, $purpose);
} else {
$mailSent = $this->c2Service->sendNotificationEmail($_ENV['EWS_MAIL_TEMPLATE'], $mannedAlert->getId(), $user->getId(), $html, $subject, $purpose);
}
}
return $mailSent ?? null;
}
return null;
}
// Send SMS alert
private function sendAlertSMS(DataObject\EwsNotification $alertObject, array $alert, Customer $user): void
{
$entityUserSubscriptionMain = $this->userModel->getEntitySubscription($user);
$packageExpiredMain = $entityUserSubscriptionMain ? (new \DateTime() > $entityUserSubscriptionMain->getEndDate() ? true : false) : false;
$subActiveMain = $entityUserSubscriptionMain ? $entityUserSubscriptionMain->getIsActive() : false;
$subUserMain = $subActiveMain && !$packageExpiredMain;
if ($subUserMain) {
if ($alertObject->getEnableSmsNotification() && $user->getPhoneNo() && strlen($user->getPhoneNo()) === 9 && $user->getEmail() == 'ismat.waseem@centricdxb.com') {
$smsTemplate = \Pimcore\Model\WebsiteSetting::getByName('MANNED_ALERT', null);
if ($smsTemplate?->getData()) {
$purpose = MANNED_ALERT_MESSAGE;
$alertTypeObj = \Pimcore\Model\DataObject\AlertType::getByAlertTypeId($alert['alertType'], true);
$alertColor = $alertTypeObj ? $alertTypeObj->getColor() : '';
$messageSMS = sprintf(SMS_MESSAGE["MANNED_ALERT"], strtoupper($alertColor) . " alert raised in " . $alert['regionAR'] . ' for ' . $alert['alertStatusAr'] . " event");
try {
$responseSMS = $this->richService->sendMannedAlertNotificationSMS($alertObject, $user, $purpose, $messageSMS);
if (!$responseSMS) {
$this->logger->error('Failed to send SMS to ' . SAUDI_CALL_CODE . $user->getPhoneNo());
}
p_r("sms sent");
} catch (\Exception $e) {
$this->logger->error('Exception while sending SMS: ' . $e->getMessage());
}
}
}
}
}
private function createOrUpdateAlertNotification(array $alert): ?DataObject\EwsNotification
{
// Generate the hash for the current alert data
$alertHash = md5(json_encode($alert));
// Retrieve the existing EwsNotification object by alert ID
$ewsNotification = \Pimcore\Model\DataObject\EwsNotification::getByAlertId($alert['id'], true);
// Check if the ews alert already exists
if ($ewsNotification && $ewsNotification->getHash() === $alertHash) {
return null; // No changes detected
}
if (!$ewsNotification) {
$ewsNotification = new DataObject\EwsNotification();
$ewsNotification->setKey($alert['id']);
$date = date('Y-m-d', strtotime($alert['fromDate']));
$ewsNotification->setParent(\Pimcore\Model\DataObject\Service::createFolderByPath('/MannedAlert/Master/EWSNotification/' . $date));
$ewsNotification->setGuid(\App\Lib\Utility::getUUID()->toRfc4122());
}
$ewsNotification->setIsManned(true);
$ewsNotification->setAlertId($alert['id']);
$ewsNotification->setTitle($alert['title']);
$ewsNotification->setAlertType($this->getAlertType($alert['alertType'], $alert['alertTypeAr'], $alert['alertTypeEn']));
$fromDate = \Carbon\Carbon::createFromFormat('m/d/Y h:i:s A', $alert['fromDate']);
$toDate = \Carbon\Carbon::createFromFormat('m/d/Y h:i:s A', $alert['toDate']);
$lastModified = \Carbon\Carbon::createFromFormat('m/d/Y h:i:s A', $alert['lastModified']);
$ewsNotification->setStartDate($fromDate);
$ewsNotification->setEndDate($toDate);
$ewsNotification->setLastModifiedDate($lastModified);
$ewsNotification->setAlertStatusCategory($this->getAlertStatusCategory($alert['alertStatusCategory'])); // need to fix
$ewsNotification->setStatus("active");
if ($alertStatus = $this->getAlertStatus($alert['alertStatusID'], $alert['alertStatusAr'], $alert['alertStatusEn'])) {
$ewsNotification->setAlertStatus($alertStatus);
}
$alertHazards = [];
foreach ($alert['alertHazards'] ?? [] as $hazard) {
$alertHazards[] = $this->getAlertHazard($hazard['id'], $hazard['descriptionAr'], $hazard['descriptionEn']);
}
$ewsNotification->setAlertHazard(array_filter($alertHazards));
$ewsNotification->setRegion($this->getRegion($alert['regionID'], $alert['regionAR'], $alert['regionEn']));
$governorates = [];
foreach ($alert['governorates'] ?? [] as $gov) {
$governorates[] = $this->getGovernorates($gov['id'], $gov['nameAr'], $gov['nameEn'], $gov['longitude'], $gov['latitude']);
}
$ewsNotification->setGovernorate(array_filter($governorates));
$ewsNotification->setOtherLocation($alert['otherLocationsEn'], 'en');
$ewsNotification->setOtherLocation($alert['otherLocationsAr'], 'ar');
if (!empty($alert['otherLocationsAr'])) {
$otherLocation = \Pimcore\Model\DataObject\EwsOtherLocation::getByName($alert['otherLocationsAr'], 'en', true);
$ewsNotification->setEwsOtherLocations($otherLocation);
}
$ewsNotification->setTweetID($alert['tweetID'] ?? null);
$alertActions = [];
foreach ($alert['alertActions'] ?? [] as $action) {
$alertActions[] = $this->getAlertAction($action['id'], $action['descriptionAr'], $action['descriptionEn']);
}
$ewsNotification->setAlertAction(array_filter($alertActions));
$ewsNotification->setHash($alertHash);
$ewsNotification->setRawText(json_encode($alert));
$ewsNotification->setIsSent(false);
$ewsNotification->setOmitMandatoryCheck(true);
$ewsNotification->save();
$currentDate = new DateTime();
$formattedDate = $currentDate->format('dmY') . '-' . $ewsNotification->getId();
$searchIdEn = 'Early Warning System | ' . $formattedDate . ' | ' . ucfirst($ewsNotification->getAlertType()?->getColor()) . ' Alert | ' . $ewsNotification->getAlertStatus()?->getName("en");
$searchIdAr = $this->translator->trans('Early Warning System', [], null, "ar") . ' | ' . $formattedDate . ' | ' . $this->translator->trans(ucfirst($ewsNotification->getAlertType()?->getColor()) . ' Alert', [], null, "ar") . ' | ' . $ewsNotification->getAlertStatus()?->getName("ar");
$ewsNotification->setEwsSearchId($searchIdEn, 'en');
$ewsNotification->setEwsSearchId($searchIdAr, 'ar');
$ewsNotification->setPublished(true);
$ewsNotification->save();
return $ewsNotification;
}
private function getAlertType($id, $nameAr, $nameEn): DataObject\AlertType
{
$alertType = \Pimcore\Model\DataObject\AlertType::getByAlertTypeId($id, true);
if (!$alertType) {
$alertType = new \Pimcore\Model\DataObject\AlertType();
$alertType->setKey($id);
$alertType->setParent(\Pimcore\Model\DataObject\Service::createFolderByPath('/MannedAlert/Master/AlertType'));
$alertType->setAlertTypeId($id);
$alertType->setName($nameAr, 'ar');
$alertType->setName($nameEn, 'en');
$alertType->setPublished(true);
$alertType->save();
}
return $alertType;
}
private function getAlertStatusCategory(string $name): DataObject\AlertStatusCategory
{
$category = \Pimcore\Model\DataObject\AlertStatusCategory::getByName($name, true);
if (!$category) {
$category = new \Pimcore\Model\DataObject\AlertStatusCategory();
$category->setParent(\Pimcore\Model\DataObject\Service::createFolderByPath('/MannedAlert/Master/AlertStatusCategory'));
$category->setKey($name);
$category->setName($name);
$category->setPublished(true);
$category->save();
}
return $category;
}
private function getAlertStatus($id, $nameAr, $nameEn): ?DataObject\AlertStatus
{
$status = \Pimcore\Model\DataObject\AlertStatus::getByAlertStatusId($id, true);
if (!$status) {
$status = new \Pimcore\Model\DataObject\AlertStatus();
$status->setKey($id);
$status->setParent(\Pimcore\Model\DataObject\Service::createFolderByPath('/MannedAlert/Master/AlertStatus'));
$status->setAlertStatusId($id);
$status->setName($nameAr, 'ar');
$status->setName($nameEn, 'en');
$status->setPublished(true);
$status->save();
}
return $status;
}
private function getAlertHazard($id, $descriptionAr, $descriptionEn): DataObject\AlertHazard
{
$hazard = \Pimcore\Model\DataObject\AlertHazard::getByAlertHazardId($id, true);
if (!$hazard) {
$hazard = new \Pimcore\Model\DataObject\AlertHazard();
$hazard->setKey($id);
$hazard->setParent(\Pimcore\Model\DataObject\Service::createFolderByPath('/MannedAlert/Master/AlertHazard'));
$hazard->setAlertHazardId($id);
$hazard->setName($descriptionAr, 'ar');
$hazard->setName($descriptionEn, 'en');
$hazard->setPublished(true);
$hazard->save();
} else {
$hazard->setName($descriptionAr, 'ar');
$hazard->setName($descriptionEn, 'en');
$hazard->save();
}
return $hazard;
}
private function getRegion($id, $nameAr, $nameEn): DataObject\Region
{
$region = \Pimcore\Model\DataObject\Region::getByRegionId($id, true);
if (!$region) {
$region = new \Pimcore\Model\DataObject\Region();
$region->setKey($id);
$region->setParent(\Pimcore\Model\DataObject\Service::createFolderByPath('/MannedAlert/Master/Region'));
$region->setRegionId($id);
$region->setName($nameAr, 'ar');
$region->setName($nameEn, 'en');
$region->setPublished(true);
$region->save();
}
return $region;
}
private function getGovernorates($id, $nameAr, $nameEn, $longitude, $latitude): DataObject\Governorate
{
$governorate = \Pimcore\Model\DataObject\Governorate::getByGovernoteId($id, true);
if (!$governorate) {
$governorate = new \Pimcore\Model\DataObject\Governorate();
$governorate->setKey($id);
$governorate->setParent(\Pimcore\Model\DataObject\Service::createFolderByPath('/MannedAlert/Master/Governorate'));
$governorate->setGovernoteId($id);
$governorate->setName($nameAr, 'ar');
$governorate->setName($nameEn, 'en');
$governorate->setLongitude($longitude);
$governorate->setLatitude($latitude);
$governorate->setPublished(true);
$governorate->save();
}
return $governorate;
}
private function getAlertAction($id, $descriptionAr, $descriptionEn): DataObject\AlertAction
{
$alertAction = \Pimcore\Model\DataObject\AlertAction::getByAlertActionId($id, true);
if (!$alertAction) {
$alertAction = new \Pimcore\Model\DataObject\AlertAction();
$alertAction->setKey($id);
$alertAction->setParent(\Pimcore\Model\DataObject\Service::createFolderByPath('/MannedAlert/Master/AlertAction'));
$alertAction->setAlertActionId($id);
$alertAction->setName($descriptionAr, 'ar');
$alertAction->setName($descriptionEn, 'en');
$alertAction->setPublished(true);
$alertAction->save();
}
return $alertAction;
}
}