src/Library/TelegramBot/CandidatesPhotoTelegramBot/CandidatesPhotoTelegramBot.php line 113

Open in your IDE?
  1. <?php
  2. namespace App\Library\TelegramBot\CandidatesPhotoTelegramBot;
  3. use App\Entity\CalendarEvent;
  4. use App\Entity\Candidate;
  5. use App\Entity\CountPlusSettings;
  6. use App\Entity\Person;
  7. use App\Entity\TelegramMessage;
  8. use App\Entity\TelegramUser;
  9. use App\Entity\User;
  10. use App\Enum\Candidate\Status;
  11. use App\Exception\TelegramBot\MessageCantBeDeleted;
  12. use App\Exception\TelegramBot\MessageCantBeDeletedForEveryone;
  13. use App\Exception\TelegramBot\MessageEditedBySameTextException;
  14. use App\Exception\TelegramBot\MessageIdentifierIsNotSpecified;
  15. use App\Exception\TelegramBot\MessageToDeleteNotFoundException;
  16. use App\Exception\TelegramBot\MessageToEditNotFoundException;
  17. use App\Library\TelegramBot\BaseTelegramBot;
  18. use App\Library\TelegramBot\TelegramObject\Message;
  19. use App\Library\TelegramBot\TelegramObject\Update;
  20. use App\Library\Utils\Other\Other;
  21. use App\Library\Utils\StringUtils;
  22. use App\Service\CalendarEvent\CalendarEventService;
  23. use App\Service\Candidate\CandidateService;
  24. use App\Service\CountPlusSettings\CountPlusSettingsService;
  25. use App\Service\DeleteRemoteMessages\DeleteRemoteMessagesService;
  26. use App\Service\EntityManagerService;
  27. use App\Service\Image\ImageService;
  28. use App\Service\Person\PersonService;
  29. use App\Service\TelegramBot\TelegramBotService;
  30. use App\Service\TelegramBotChat\TelegramBotChatService;
  31. use App\Service\TelegramBotNavigation\TelegramBotNavigationService;
  32. use App\Service\TelegramChat\TelegramChatService;
  33. use App\Service\TelegramMessage\TelegramMessageService;
  34. use App\Service\TelegramUser\TelegramUserService;
  35. use App\Service\User\UserService;
  36. use Doctrine\ORM\EntityManagerInterface;
  37. use Psr\Log\LoggerInterface;
  38. use Symfony\Component\HttpKernel\KernelInterface;
  39. use App\Library\TelegramBot\CandidatesPhotoTelegramBot\Enum\Menu\Menu;
  40. use App\Library\TelegramBot\CandidatesPhotoTelegramBot\Enum\EditableMessage\EditableMessage;
  41. /*
  42.  * Настройка команд в @BotFather:
  43.    start - Начало работы
  44.    novii_podschet_plusov - Начать новый подсчет плюсов с последнего сообщения в чате
  45.    kto_ne_postavil - Список тех, кто не поставил +
  46.    ustanovit_kol_vo_uchastnikov - Установить кол-во участников в группе
  47.    avto_perezapusk_schetch_plusov - Вкл/выкл авто перезапуск счетчика плюсов
  48.    posmotret_nastroiki_bota - Посмотреть настройки бота
  49.    udalit_uchastn_bolee_48_chasov - Удалить участников из учета плюсов с активностью более 48 часов
  50.  */
  51. class CandidatesPhotoTelegramBot extends BaseTelegramBot
  52. {
  53.     /**
  54.      * @var array
  55.      */
  56.     protected $sentMessages = [];
  57.     /**
  58.      * @var TelegramChatService
  59.      */
  60.     private $telegramChatService;
  61.     /**
  62.      * @var KernelInterface
  63.      */
  64.     private $kernel;
  65.     /**
  66.      * @var TelegramBotChatService
  67.      */
  68.     private $telegramBotChatService;
  69.     /**
  70.      * @var DeleteRemoteMessagesService
  71.      */
  72.     private $deleteRemoteMessagesService;
  73.     /**
  74.      * @var TelegramUserService
  75.      */
  76.     private $telegramUserService;
  77.     /**
  78.      * @var UserService
  79.      */
  80.     private $userService;
  81.     /**
  82.      * @var CandidateService
  83.      */
  84.     private $candidateService;
  85.     /**
  86.      * @var PersonService
  87.      */
  88.     private $personService;
  89.     /**
  90.      * @var CalendarEventService
  91.      */
  92.     private $calendarEventService;
  93.     /**
  94.      * @var BotNavigation
  95.      */
  96.     public $botNavigation;
  97.     public function __construct(LoggerInterface $loggerEntityManagerInterface $emTelegramBotChatService $telegramBotChatService,
  98.                 KernelInterface $kernelTelegramMessageService $telegramMessageService,
  99.                 DeleteRemoteMessagesService $deleteRemoteMessagesService,
  100.                 TelegramUserService $telegramUserService,
  101.                 EntityManagerService $emService,
  102.                 TelegramChatService $telegramChatService,
  103.                 TelegramBotService $telegramBotServiceUserService $userService,
  104.                 CandidateService $candidateServicePersonService $personService,
  105.                 TelegramBotNavigationService $telegramBotNavigationServiceCalendarEventService $calendarEventService,
  106.                 ImageService $imageService)
  107.     {
  108.         parent::__construct($logger$em$telegramMessageService$emService$telegramBotService$telegramBotNavigationService,
  109.             $imageService);
  110.         $this->telegramBotChatService $telegramBotChatService;
  111.         $this->kernel $kernel;
  112.         $this->deleteRemoteMessagesService $deleteRemoteMessagesService;
  113.         $this->telegramUserService $telegramUserService;
  114.         $this->telegramBotService $telegramBotService;
  115.         $this->userService $userService;
  116.         $this->candidateService $candidateService;
  117.         $this->personService $personService;
  118.         $this->calendarEventService $calendarEventService;
  119.         $this->setApiToken($_ENV["CANDIDATES_PHOTO_TELEGRAM_BOT_API_TOKEN"]);
  120.         // $this->setBotTelegramIds([/*dev*/ "6871142341", /*prod*/ "6341096966"]);
  121.         $this->setInnerBotId("candidate_photos_bot");
  122.         $this->telegramChatService $telegramChatService;
  123.         $this->botNavigation = new BotNavigation($this$calendarEventService$userService$candidateService);
  124.     }
  125.     public function handleUpdate($update)
  126.     {
  127.         $chatId $update->getData()["message"]["chat"]["id"] ?? null;
  128.         $text $update->getData()["message"]["text"] ?? null;
  129.         $username $update->getData()["message"]["from"]["username"] ?? "";
  130.         $userId $update->getData()["message"]["from"]["id"] ?? null;
  131.         $firstName $update->getData()["message"]["from"]["first_name"] ?? "";
  132.         $lastName $update->getData()["message"]["from"]["last_name"] ?? "";
  133.         $isCallbackQuery = isset($update->getData()['callback_query']);
  134.         if (!isset($update->getData()['message'])
  135.                 && (!$isCallbackQuery || !isset($update->getData()['callback_query']['message']))) {
  136.             return;
  137.         }
  138.         $messageData = ($isCallbackQuery
  139.             $update->getData()['callback_query']['message']
  140.             : $update->getData()['message']);
  141.         $message $this->telegramMessageService->createOrGet($messageDatafalse);
  142.         $user $this->telegramUserService->createOrGet($isCallbackQuery
  143.             $update->getData()['callback_query']['from']
  144.             : $messageData["from"]);
  145.         $this->handleMessage($update$message$user$isCallbackQuery);
  146.     }
  147.     // private function checkPhotoEditableMessageExists(TelegramUser $user, string $chatId): bool
  148.     // {
  149.     //     $editableMessageId = $this->getEditableMessageId($user, EditableMessage::EDITABLE_MESSAGE_ID__PHOTO);
  150.     //     if ($editableMessageId) {
  151.     //         return $this->checkRemoteMessageExists($chatId, $editableMessageId);
  152.     //     }
  153.     //     return false;
  154.     // }
  155.     /**
  156.      * @var Candidate
  157.      */
  158.     public $candidate;
  159.     /**
  160.      * @var TelegramUser
  161.      */
  162.     public $telegramUser;
  163.     /**
  164.     * @var User
  165.     */
  166.     public $user;
  167.     public function handleMessage(Update $updateTelegramMessage $messageTelegramUser $userbool $isCallbackQuery false)
  168.     {
  169.         $botOrGroupChatId $message->getChatId();
  170.         $messageObj $isCallbackQuery $update->getCallbackQuery()->getMessage() : $update->getMessage();
  171.         $navSelectedMenuItem null;
  172.         $navMenuId null;
  173.         if ($isCallbackQuery) {
  174.             $this->setNavigationSelectedItemIdByUpdate($user$update);
  175.             $navMenuId $this->getNavigationMenuIdByUpdate($update);
  176.             $navSelectedMenuItem $this->getNavigationSelectedItem($user$navMenuId);
  177.         }
  178.         $text $isCallbackQuery
  179.             $update->getCallbackQuery()->getDataField()
  180.             : $messageObj->getText();
  181.         $username $user->getUsername();
  182.         // if ($update->getMessage() && $update->getMessage()->getFrom()) {
  183.         //     /** @var TelegramUser|null $user */
  184.         //     $user = $this->telegramUserService->createOrGet($update->getMessage()->getFrom()->getData());
  185.         // }
  186.         //todo redo
  187.         // if ($botOrGroupChatId != "172060981") {
  188.         //     return;
  189.         // }
  190.         $sendMessages = [];
  191.         $appUser $this->userService->getFirst([
  192.             "telegramUserId" => $user->getUserId()
  193.         ]);
  194.         if (!$appUser) {
  195.             $sendMessages[] = $user->getName() . ", мы Вас не узнали 🙂. Пожалуйста, обратитесь к администратору.";
  196.         } else if ($appUser) {
  197.             $this->telegramUser $user;
  198.             $this->user $appUser;
  199.             $candidate $this->candidateService->getLastDraft($appUser);
  200.             if (!$candidate) {
  201.                 $navItemIds $this->botNavigation->createCandidateFieldsMenu()['navItemIds'];
  202.                 $this->botNavigation->resetCandidateFieldNamedNav($user,
  203.                     ($messageObj->getPhoto() ? $navItemIds[Menu::PHOTO_MENU_ID] : $navItemIds[Menu::PERSON_MENU_ID]));
  204.                 $candidate $this->candidateService->createDraft($appUser);
  205.             }
  206.             $this->candidate $candidate;
  207.             if ($navSelectedMenuItem) {
  208.                 $this->botNavigation->onAnyBotMenuItemSelect($botOrGroupChatId$user$navMenuId$navSelectedMenuItem);
  209.             } else if ($messageObj && ($text || $messageObj->getPhoto())) {
  210.                 $navItem $this->getNavigationSelectedItem($userMenu::CANDIDATE_FIELD_MENU_ID);
  211.                 $lastSelectedCandidateFieldId $navItem $navItem['id'] : null;
  212.                 if ($messageObj->getPhoto() && $lastSelectedCandidateFieldId != Menu::PHOTO_MENU_ID) {
  213.                     $lastSelectedCandidateFieldId Menu::PHOTO_MENU_ID;
  214.                 } else if ($text && !$messageObj->getPhoto() && !in_array($lastSelectedCandidateFieldId, [
  215.                             Menu::PERSON_MENU_ID,
  216.                             Menu::COMMENT_MENU_ID,
  217.                             Menu::REVIEW_APPROVE_COMMENT_MENU_ID,
  218.                             Menu::DATE_MENU_ID,
  219.                         ])) {
  220.                     $lastSelectedCandidateFieldId Menu::PERSON_MENU_ID;
  221.                 }
  222.                 $this->onContentSend($botOrGroupChatId$messageObj$user$update$lastSelectedCandidateFieldId$text);
  223.             }
  224.             // $candidate = $this->candidateService->getDefault([
  225.             //     "firstName" =>
  226.             // ]);
  227.             // $imagePath = $this->downloadMessagePhoto($update);
  228.             // dump($imagePath);
  229.         }
  230.         foreach ($sendMessages as $sendMessage) {
  231.             $this->sendMessage($botOrGroupChatId$sendMessage);
  232.         }
  233.     }
  234.     private function onContentSend($chatId$messageObjTelegramUser $userUpdate $update$lastSelectedCandidateFieldId$text)
  235.     {
  236.         switch ($lastSelectedCandidateFieldId) {
  237.             case Menu::PERSON_MENU_ID:
  238.                 if ($text) {
  239.                     try {
  240.                         $this->deleteRemoteMessage($chatId$messageObj->getMessageId());
  241.                     } catch (\Throwable $exception) {
  242.                         //ignore
  243.                     }
  244.                     $persons $this->personService->findByTelegramText($text);
  245.                     if ($persons) {
  246.                         $this->botNavigation->sendSelectPersonMenu($chatId$user$persons$text);
  247.                         return;
  248.                     } else {
  249.                         $msg "По вашему запросу \""
  250.                             htmlspecialchars($text) . "\" участник не найден. Пожалуйста, проверьте правильность написания"
  251.                             " имени или фамилии.\n\n"
  252.                             "🙍‍♂️ Введите имя участника заново:";
  253.                         $this->botNavigation->sendSelectCandidateFieldMenu($chatId$user$msg);
  254.                         return;
  255.                     }
  256.                 }
  257.                 break;
  258.             case Menu::COMMENT_MENU_ID:
  259.                 if ($text) {
  260.                     try {
  261.                         $this->deleteRemoteMessage($chatId$messageObj->getMessageId());
  262.                     } catch (\Throwable $exception) {
  263.                         //ignore
  264.                     }
  265.                     $this->candidate->setComment($text);
  266.                     $this->em->flush();
  267.                     $this->botNavigation->sendSelectCandidateFieldMenu($chatId$user);
  268.                 }
  269.                 break;
  270.             case Menu::REVIEW_APPROVE_COMMENT_MENU_ID:
  271.                 if ($text) {
  272.                     try {
  273.                         $this->deleteRemoteMessage($chatId$messageObj->getMessageId());
  274.                     } catch (\Throwable $exception) {
  275.                         //ignore
  276.                     }
  277.                     $this->candidate->setReviewApproveComment($text);
  278.                     $this->em->flush();
  279.                     $this->botNavigation->sendSelectCandidateFieldMenu($chatId$user);
  280.                 }
  281.                 break;
  282.             case Menu::DATE_MENU_ID:
  283.                 if ($text) {
  284.                     try {
  285.                         $this->deleteRemoteMessage($chatId$messageObj->getMessageId());
  286.                     } catch (\Throwable $exception) {
  287.                         //ignore
  288.                     }
  289.                     $date null;
  290.                     try {
  291.                         $date = new \DateTime($text . (new \DateTime())->format(" H:i:s"));
  292.                     } catch (\Throwable $exception) {
  293.                         //ignore
  294.                     }
  295.                     if (!$date) {
  296.                         $msg "❌ Неверный формат даты. Пожалуйста, введите дату в формате ДД.ММ.ГГГГ"
  297.                             " (например, 27.11.2025):";
  298.                         $this->botNavigation->sendSelectCandidateFieldMenu($chatId$user$msg);
  299.                         return;
  300.                     }
  301.                     $this->candidate->setCreatedAt($date);
  302.                     $this->em->flush();
  303.                     $this->botNavigation->sendSelectCandidateFieldMenu($chatId$user);
  304.                 }
  305.                 break;
  306.             case Menu::PHOTO_MENU_ID:
  307.                 $image $this->downloadMessagePhoto($update);
  308.                 $this->candidate->setImage($image);
  309.                 $this->em->flush();
  310.                 $this->updateCandidatePhoto($chatId$update->getMessage()->getLastPhoto()->getFileId(), $messageObj);
  311.                 $this->botNavigation->sendSelectCandidateFieldMenu($chatId$user);
  312.                 break;
  313.             default:
  314.                 throw new \Exception("Unknown: " $lastSelectedCandidateFieldId);
  315.         }
  316.     }
  317.     public function updateCandidatePhoto($chatId$fileIdMessage $messageToDelete null)
  318.     {
  319.         $isPhotoChanged false;
  320.         $telegramMessageId $this->getEditableMessageId($this->telegramUser,
  321.             EditableMessage::EDITABLE_MESSAGE_ID__PHOTO);
  322.         if ($telegramMessageId) {
  323.             $isPhotoChanged true;
  324.             try {
  325.                 $this->editRemoteMessage($chatId$telegramMessageIdnullnull$fileId);
  326.             } catch (MessageEditedBySameTextException $exception) {
  327.                 //ignore
  328.                 $isPhotoChanged false;
  329.             } catch (MessageToEditNotFoundException $exception) {
  330.                 $isPhotoChanged false;
  331.             }
  332.         }
  333.         if (!$isPhotoChanged) {
  334.             $this->botNavigation->deleteMainEditableMessage($this->telegramUser$chatId);
  335.             $this->botNavigation->editOrSendPhotoEditableMessage($this->telegramUser$chatId$fileId);
  336.         }
  337.         if ($messageToDelete) {
  338.             try {
  339.                 $this->deleteRemoteMessage($chatId$messageToDelete->getMessageId());
  340.             } catch (\Throwable $exception) {
  341.                 //ignore
  342.             }
  343.         }
  344.     }
  345.     public function onPersonMenuItemSelect($chatIdTelegramUser $user$selectedItemId$navSelectedMenuItem)
  346.     {
  347.         /**
  348.          * @var Person
  349.          */
  350.         $person $this->personService->getBaseService()->get($navSelectedMenuItem['id']);
  351.         $this->candidate->setPerson($person);
  352.         $this->em->flush();
  353.         $this->botNavigation->sendSelectCandidateFieldMenu($chatId$user);
  354.     }
  355.     public function onCalendarEventMenuItemSelect($chatIdTelegramUser $user$selectedItemId$navSelectedMenuItem)
  356.     {
  357.         /**
  358.          * @var CalendarEvent
  359.          */
  360.         $event $this->calendarEventService->getBaseService()->get($navSelectedMenuItem['id']);
  361.         $this->candidate->setCalendarEvent($event);
  362.         $this->em->flush();
  363.         $this->botNavigation->sendSelectCandidateFieldMenu($chatId$user);
  364.     }
  365.     public function onAuthorMenuItemSelect($chatIdTelegramUser $user$selectedItemId$navSelectedMenuItem)
  366.     {
  367.         /**
  368.          * @var User
  369.          */
  370.         $author $this->userService->getBaseService()->get($navSelectedMenuItem['id']);
  371.         $this->candidate->setCurator($author);
  372.         $this->em->persist($this->candidate);
  373.         $this->em->persist($author);
  374.         $this->em->flush();
  375.         $this->botNavigation->sendSelectCandidateFieldMenu($chatId$user);
  376.     }
  377.     public function onStatusMenuItemSelect($chatIdTelegramUser $user$selectedItemId$navSelectedMenuItem)
  378.     {
  379.         //do nothing. Status is set on confirm
  380.         $this->botNavigation->sendSelectCandidateFieldMenu($chatId$user);
  381.     }
  382.     public function onCandidateConfirmMenuItemSelect($chatIdTelegramUser $user)
  383.     {
  384.         if ($this->candidateService->existsSame($this->candidate)) {
  385.             $msg "❌ Кандидат с таким именем уже зарегистрирован для данного мероприятия."
  386.                 " Пожалуйста, измените имя кандидата или мероприятие.";
  387.             $this->botNavigation->sendSelectCandidateFieldMenu($chatId$user$msg);
  388.             return;
  389.         }
  390.         $navStatusSelectedItem $this->getNavigationSelectedItem($user,
  391.             Menu::STATUS_MENU_ID);
  392.         $confirmResult $this->candidateService->confirmCandidate($this->candidate,
  393.             ($navStatusSelectedItem $navStatusSelectedItem['id'] : Status::STATUS_NEW));
  394.         if ($confirmResult['result']) {
  395.             if ($this->candidate->getImage()) {
  396.                 $this->personService->setPersonImage($this->candidate->getPerson(), $this->candidate->getImage());
  397.             }
  398.             $this->botNavigation->sendAfterCandidateSendMenu($chatId$user);
  399.             $this->botNavigation->resetEditableMessages($user);
  400.         } else {
  401.             $needFieldsText array_reduce($confirmResult['needFields'], function($carry$item) {
  402.                 return $carry . ($carry ", " "") . $item['text'];
  403.             }, "");
  404.             $needFieldsText StringUtils::addDot($needFieldsText);
  405.             $msg "❌ Невозможно отправить"
  406.                 " анкету. Не все данные введены или не соответствуют требованиям: $needFieldsText Выберите поле анкеты участника для изменения:";
  407.             $this->botNavigation->sendSelectCandidateFieldMenu($chatId$user$msg);
  408.             return;
  409.         }
  410.     }
  411.     public function sendMenuById($chatIdTelegramUser $user$menuId$msg null)
  412.     {
  413.         switch ($menuId) {
  414.             case Menu::CALENDAR_EVENT_MENU_ID:
  415.                 $this->botNavigation->sendSelectCalendarEventMenu($chatId$user);
  416.                 break;
  417.             // case Menu::PERSON_MENU_ID:
  418.             //     $this->botNavigation->sendSelectPersonMenu($chatId, $user);
  419.             //     break;
  420.             case Menu::AUTHOR_MENU_ID:
  421.                 $this->botNavigation->sendSelectAuthorMenu($chatId$user);
  422.                 break;
  423.             case Menu::STATUS_MENU_ID:
  424.                 $this->botNavigation->sendSelectStatusMenu($chatId$user);
  425.                 break;
  426.             case Menu::CANDIDATE_FIELD_MENU_ID:
  427.                 $this->botNavigation->sendSelectCandidateFieldMenu($chatId$user$msg);
  428.                 break;
  429.             case Menu::OTHER_MENU_ID:
  430.                 $this->botNavigation->sendSelectOtherMenu($chatId$user$msg);
  431.                 break;
  432.             default:
  433.                 throw new \Exception("Unknown: " $menuId);
  434.         }
  435.     }
  436.     public function onCopyLastCandidateMenuItemSelect($chatIdTelegramUser $user$navSelectedMenuItem$sendNextMenuId null)
  437.     {
  438.         $lastCandidate $this->candidateService->getLastNonDraftCandidate($this->user);
  439.         if (!$sendNextMenuId) {
  440.             $sendNextMenuId Menu::OTHER_MENU_ID;
  441.         }
  442.         if ($lastCandidate) {
  443.             $this->candidateService->copyCandidateDataToDraft($lastCandidate$this->candidate);
  444.             if ($lastCandidate->getImage()) {
  445.                 $clonedImage $this->imageService->cloneImage($lastCandidate->getImage());
  446.                 $messageData $this->sendImage($chatId,
  447.                     $this->imageService->getRealPath($clonedImage));
  448.                 $this->updateCandidatePhoto($chatId,
  449.                     $messageData->getLastPhoto()->getFileId(), $messageData);
  450.                 $this->candidate->setImage($clonedImage);
  451.                 $this->em->flush();
  452.             }
  453.             $msg "✅ Анкета последнего участника скопирована в черновик."
  454.                 " Теперь вы можете изменить необходимые поля или подтвердить регистрацию участника.";
  455.             $this->sendMenuById($chatId$user$sendNextMenuId$msg);
  456.         } else {
  457.             $this->sendMenuById($chatId$user$sendNextMenuId"❌ У Вас нет ранее зарегистрированных участников.");
  458.         }
  459.     }
  460.     public function onResetCandidateMenuItemSelect($chatIdTelegramUser $user$navSelectedMenuItem$sendNextMenuId null)
  461.     {
  462.         $image $this->candidate->getImage();
  463.         if ($image) {
  464.             $this->candidate->setImage(null);
  465.             $this->imageService->delete($imagefalse);
  466.         }
  467.         $this->candidate
  468.             ->setPerson(null)
  469.             ->setCalendarEvent(null)
  470.             ->setImage(null)
  471.             ->setCurator(null)
  472.             ->setComment(null)
  473.             ->setReviewApproveComment(null)
  474.         ;
  475.         $this->em->flush();
  476.         if ($this->getEditableMessageId($user,
  477.             EditableMessage::EDITABLE_MESSAGE_ID__PHOTO)) {
  478.             try {
  479.                 $this->deleteRemoteMessage($chatId$this->getEditableMessageId($user,
  480.                     EditableMessage::EDITABLE_MESSAGE_ID__PHOTO));
  481.             } catch (\Throwable $exception) {
  482.                 //ignore
  483.             }
  484.         }
  485.         $msg "✅ Анкета сброшена.";
  486.         $this->sendMenuById($chatId$user$sendNextMenuId$msg);
  487.     }
  488.     public function onUpdatesHandled()
  489.     {
  490.         if ($this->sentMessages) {
  491.             foreach ($this->sentMessages as $message) {
  492.                 $this->em->persist($message);
  493.             }
  494.             $this->em->flush();
  495.             $this->sentMessages = [];
  496.         }
  497.     }
  498.     private function runBotCommandStartNewPlusCounter(CountPlusSettings $countPlusSettings, &$sendMessagesTelegramUser $user$text$chatId$adminChatId)
  499.     {
  500.         if (!$user->getWaitBotCommandParam()) {
  501.             $user->changeWaitBotCommandParam(["novii_podschet_plusov" => "askYesNo"]);
  502.             $this->emService->save($user);
  503.             $sendMessages[] = "Уверены? Введите \"да\" или \"нет\" (без кавычек)";
  504.             return;
  505.         } else {
  506.             $result $this->checkCommandParamType($text"string"$adminChatId$usernullnullfalse,
  507.                 nulltrue);
  508.             if ($result === "yes") {
  509.                 $this->startNewPlusCounter($chatId$countPlusSettings$sendMessages);
  510.                 $user->clearWaitBotCommandParam();
  511.                 $this->emService->save($user);
  512.                 return;
  513.             } else if ($result === "no") {
  514.                 $user->clearWaitBotCommandParam();
  515.                 $this->emService->save($user);
  516.                 $sendMessages[] = "Команда отменена";
  517.                 return;
  518.             }
  519.         }
  520.     }
  521.     public function startNewPlusCounter($chatIdCountPlusSettings $countPlusSettings, &$sendMessages,
  522.                                         $includeLastPlusMessage false)
  523.     {
  524.         if ($countPlusSettings->getUsersListMessageId() &&
  525.             $countPlusSettings->getCountAfterMessageId())
  526.         {
  527.             $statistics $this->telegramMessageService->getPlusMessagesStatistics($chatId$countPlusSettings,
  528.                 falsefalse);
  529.             $statistics .= "\n\nПодсчет завершен";
  530.             $statistics .= "\n-----";
  531.             if ($countPlusSettings->getUsersListMessageId()) {
  532.                 $usersListMessage $this->telegramMessageService->getUsersListMessage($chatId,
  533.                     $countPlusSettings);
  534.                 if ($usersListMessage) {
  535.                     $this->editRemoteMessage($chatId$usersListMessage->getMessageId(),
  536.                         "💫💫💫💫💫️ Спасибо, все участники отметились!");
  537.                     $removeAt = (new \DateTime())->setTime($countPlusSettings->getAutoRestartTime()->format("H"),
  538.                         $countPlusSettings->getAutoRestartTime()->format("i"));
  539.                     $removeAfterMins null;
  540.                     if (new \DateTime() >= $removeAt) {
  541.                         $removeAt null;
  542.                         $removeAfterMins 1;
  543.                     }
  544.                     $this->deleteRemoteMessagesService->create(
  545.                         $usersListMessage$removeAfterMins$removeAt);
  546.                 }
  547.             }
  548.             $sendMessages[] = $statistics;
  549.             $countPlusSettings->setUsersListMessageId(null);
  550.             $this->em->flush();
  551.         }
  552.         $q $this->em->getRepository(TelegramMessage::class)->createQueryBuilder('tm');
  553.         $q
  554.             ->where("tm.chatId = :chatId")
  555. //            ->andWhere("tm.isDeleted != true") //не ставить!
  556.             ->setParameter("chatId"$chatId)
  557.             ->setMaxResults($includeLastPlusMessage 1)
  558.             ->orderBy("tm.id""DESC");
  559.         $message $q->getQuery()->getResult();
  560.         /** @var TelegramMessage $message */
  561.         if ($message) {
  562.             $message $message[!$includeLastPlusMessage : (count($message) > 0)];
  563.             $countPlusSettings->setCountAfterMessageId($message->getId());
  564. //            if ($message->getText()) {
  565. //                $sendMessages[] = "Последнее сообщение {$message->getDateTime()->format("H:i")}" .
  566. //                    " от {$message->getName()}: " . $message->getText();
  567. //            }
  568.         }
  569.         $countPlusSettings->setStartedAt(new \DateTime());
  570.         $this->em->flush();
  571.         $sendMessages[] = "Новый счетчик плюсов создан!";
  572.     }
  573.     public function onMessageSend($message)
  574.     {
  575.         $this->sentMessages[] = $message;
  576.     }
  577.     private function ktoNePostavil($chatId$countPlusSettings, array &$sendMessages)
  578.     {
  579.         $allChatUsers $this->telegramMessageService
  580.             ->getAllChatUsers($chatId);
  581.         /** @var TelegramMessage[] $plusUsers */
  582.         $plusUsers $this->telegramMessageService->getPlusMessages($chatId$countPlusSettings);
  583.         $usersDidntSendPlus array_filter($allChatUsers, function ($cur) use ($plusUsers) {
  584.             foreach ($plusUsers as $plusUser) {
  585.                 if ((int)$plusUser->getUserId() == (int)$cur['userId']) {
  586.                     return false;
  587.                 }
  588.             }
  589.             return true;
  590.         });
  591.         $usersDidntSentPlusStatistics "Список не отметившихся (нажмите на имя, чтобы перейти в чат):\n\n";
  592.         $usersDidntSendPlusStr array_map(function ($cur) {return "<a href=\"tg://user?id=" $cur['userId'] . "\">" trim($cur['name']) . "</a>";},
  593.             $usersDidntSendPlus);
  594.         $usersDidntSendPlusStr array_reduce($usersDidntSendPlusStr,
  595.             function ($cur$all) {return $all . ($all "\n" "") . $cur;});
  596.         $all Other::getSettings("allUsers"true);
  597.         $all explode("\r\n"$all);
  598.         $plusMessageUserNames $this->telegramMessageService->getPlusMessages($chatId$countPlusSettings);
  599.         $plusMessageUserNames array_map(function ($cur) {return "<a href=\"tg://user?id=" $cur->getUserId() . "\">" trim($cur->getName()) . "</a>'";}, $plusMessageUserNames);
  600.         $usersDidntSentPlusStatistics .= $usersDidntSendPlusStr;
  601.         $usersDidntSentPlusStatistics .= "\nНайдено: " count($usersDidntSendPlus) . " из " count($allChatUsers) . "\n";
  602. //        $manualList = array_diff($all, $plusMessageUserNames);
  603. //        $usersDidntSentPlusStatistics .= "\nСравнение с ручным списком:\n\n" .
  604. //            array_reduce($manualList, function ($c, $a) {return $a . "\n". $c;});
  605. //        $usersDidntSentPlusStatistics .= "\nНайдено: " . count($manualList) . "\n";
  606.         $sendMessages[] = $usersDidntSentPlusStatistics;
  607.     }
  608.     private function avtoPerezapuskSchetchPlusov(CountPlusSettings $countPlusSettings, array &$sendMessages)
  609.     {
  610.         if (!$countPlusSettings->getChatUsersCount()) {
  611.             $sendMessages[] = "Сначала необходимо ввести кол-во участников группы с " .
  612.                 "помощью команды /ustanovit_kol_vo_uchastnikov";
  613.             return;
  614.         }
  615.         $countPlusSettings->toggleAutoRestartPlusCounter();
  616.         $this->emService->save($countPlusSettings);
  617.         $sendMessages[] = "Авто перезапуск счетчика плюсов при достижении" .
  618.             " плюсов в кол-ве " $countPlusSettings->getChatUsersCount() .
  619.             " " $countPlusSettings->getAutoRestartPlusCounterText() .
  620.                 ($countPlusSettings->getAutoRestartPlusCounter() ?
  621.                     ".\nВнимание! При встулении или выходе из группы участников," .
  622.                 " необходимо заново установить вручную кол-во участников группы" .
  623.                 " для правильного срабатывания авто перезапуска счетчика плюсов, с пом." .
  624.                     " команды /ustanovit_kol_vo_uchastnikov!" "");
  625.     }
  626.     private function ustanovitKolVoUchastnikov(CountPlusSettings $countPlusSettings, array &$sendMessagesTelegramUser $user$text,
  627.             $chatId)
  628.     {
  629.         if ($user->getWaitBotCommandParam() ==
  630.             ["ustanovit_kol_vo_uchastnikov" => "usersCount"])
  631.         {
  632.             $result $this->checkCommandParamType($text"int"$chatId$user1);
  633.             if ($result === false || $result === "canceled") {
  634.                 return;
  635.             }
  636.             $countPlusSettings->setChatUsersCount((int)$text);
  637.             $user->setWaitBotCommandParam(null);
  638.             $this->emService->save($countPlusSettings$user);
  639.             $sendMessages[] = "Установлено кол-во участников группы: " $text;
  640.             return;
  641.         }
  642.         $sendMessages[] = "Введите кол-во участников группы. Либо введите слово \"отмена\""
  643.             " (без кавычек) для отмены ввода";
  644.         $user->setWaitBotCommandParam(["ustanovit_kol_vo_uchastnikov" => "usersCount"]);
  645.         $this->emService->save($user);
  646.     }
  647.     private function posmotretNastroikiBota(CountPlusSettings $countPlusSettings, array &$sendMessages)
  648.     {
  649.         $result "Настройки бота:
  650. - Введенное кол-во участников группы: {$countPlusSettings->getChatUsersCountText()}
  651. - Авто перезапуск счетчика плюсов (при достижении плюсов в кол-ве: " .
  652.             "{$countPlusSettings->getChatUsersCountText()}): "
  653.             "{$countPlusSettings->getAutoRestartPlusCounterText()}";
  654.         $sendMessages[] = $result;
  655.     }
  656.     /**
  657.      * @param array|null|TelegramUser[] $admins
  658.      * @param CountPlusSettings $countPlusSettings
  659.      * @param $chatId
  660.      * @param TelegramUser $user
  661.      * @param TelegramMessage $message
  662.      * @param $isPlusMessage
  663.      * @return void
  664.      * @throws MessageIdentifierIsNotSpecified
  665.      */
  666.     private function handleNonAdminMessage(?array $adminsCountPlusSettings $countPlusSettings$chatIdTelegramUser $userTelegramMessage $message,
  667.                                                   $isPlusMessage)
  668.     {
  669.         if (!$isPlusMessage) {
  670.             return;
  671.         }
  672.         $sendMessages = [];
  673.         if ($countPlusSettings->getStartedAt() &&
  674.             new \DateTime() > (clone $countPlusSettings->getStartedAt())->modify("+48 hour")
  675.         ) {
  676.             return;
  677.         }
  678.         $result null;
  679.         if ($message->getMessageId() != 0) {
  680.             try {
  681.                 $result $this->deleteRemoteMessage($message->getChatId(), $message->getMessageId());
  682.             } catch (MessageToDeleteNotFoundException|MessageCantBeDeleted|MessageCantBeDeletedForEveryone
  683.                 $exception)
  684.             {
  685.                 $result = ["result" => true];
  686.             }
  687.         } else if ($message->getMessageId() == 0) {
  688.             $result = ["result" => true];
  689.         }
  690.         if ($result["result"] === true) {
  691.             $message->setIsDeleted(true);
  692.             $this->em->flush();
  693.         }
  694.         $this->restartPlusCounterOnTimeOutIfNeeded($admins$chatId$countPlusSettings);
  695.         if ($this->telegramMessageService->isMessageWithPlusWasAlreadySend(
  696.             $countPlusSettings$message->getUserId()))
  697.         {
  698.             $result $this->sendMessage($chatId"✔️ Спасибо, {$user->getName()}, ваша отметка уже была учтена." .
  699.                 " (данное сообщение автоматически удалится через 1 мин.)");
  700.         } else {
  701.             $result $this->sendMessage($chatId"✔️ Спасибо, {$user->getName()}, ваша отметка учтена." .
  702.                 " (данное сообщение автоматически удалится через 1 мин.)");
  703.         }
  704.         $this->deleteRemoteMessagesService->create($result1);
  705.         $this->updatePlusList($countPlusSettings$chatId);
  706.         foreach ($sendMessages as $sendMessage) {
  707.             $this->sendMessage($chatId$sendMessage);
  708.         }
  709.         if ($isPlusMessage && $countPlusSettings->getChatUsersCount() &&
  710.             $countPlusSettings->getAutoRestartPlusCounter())
  711.         {
  712.             $this->restartPlusCounterIfComplete($chatId$countPlusSettings$admins);
  713.         }
  714.     }
  715.     private function restartPlusCounterOnTimeOutIfNeeded($admins$chatIdCountPlusSettings $countPlusSettings): void
  716.     {
  717.         $autoRestartTime null;
  718.         if ($countPlusSettings->getAutoRestartTime() && $countPlusSettings->getStartedAt()) {
  719.             $autoRestartTime = (clone $countPlusSettings->getStartedAt())
  720.                 ->modify("+1 day")
  721.                 ->setTime($countPlusSettings->getAutoRestartTime()->format("H"),
  722.                 $countPlusSettings->getAutoRestartTime()->format("i"));
  723.         }
  724.         $isPlusCounterRestartTime $autoRestartTime && (new \DateTime() >= $autoRestartTime);
  725.         if ($isPlusCounterRestartTime) {
  726.             $adminMsg "Срабтал автоматический перезапуск счетчика плюсов по времени: " .
  727.                 $countPlusSettings->getAutoRestartTime()->format("H:i");
  728.             $this->restartPlusCounter($admins$adminMsg$chatId$countPlusSettingstrue);
  729.         }
  730.     }
  731.     private function isPlusCounterComplete(CountPlusSettings $countPlusSettings$chatId): bool
  732.     {
  733.         return $countPlusSettings->getChatUsersCount() ==
  734.             count($this->telegramMessageService->getPlusMessages($chatId$countPlusSettings));
  735.     }
  736.     private function restartPlusCounterIfComplete($chatIdCountPlusSettings $countPlusSettings$admins)
  737.     {
  738.         $isPlusCounterComplete $this->isPlusCounterComplete($countPlusSettings$chatId);
  739.         $adminMsg null;
  740.         if ($isPlusCounterComplete) {
  741.             $adminMsg "Кол-во плюсов достигло кол-ва участников в группе: " .
  742.                 $countPlusSettings->getChatUsersCount();
  743.         }
  744.         if ($isPlusCounterComplete)
  745.         {
  746.             $this->restartPlusCounter($admins$adminMsg$chatId$countPlusSettings);
  747.         }
  748.     }
  749.     private function restartPlusCounter($admins$adminMsg$chatIdCountPlusSettings $countPlusSettings,
  750.                                         $includeLastPlusMessage false)
  751.     {
  752.         foreach ($admins as $admin) {
  753.             try {
  754.                 $this->sendMessage($admin->getUserId(), $adminMsg);
  755.                 $this->startNewPlusCounter($chatId$countPlusSettings$tmpSendMessages$includeLastPlusMessage);
  756.                 foreach ($tmpSendMessages as $tmpSendMessage) {
  757.                     $this->sendMessage($admin->getUserId(), $tmpSendMessage);
  758.                 }
  759.             } catch (\Throwable $e) {
  760.                 $this->logger->error("Error sending message to admin: " $e->getMessage());
  761.             }
  762.         }
  763.     }
  764.     public function updatePlusList(CountPlusSettings $countPlusSettings$chatId)
  765.     {
  766.         $statistics $this->telegramMessageService->getPlusMessagesStatistics($chatId$countPlusSettings);
  767.         if (!$countPlusSettings->getUsersListMessageId()) {
  768.             $result $this->sendMessage($chatId$statistics);
  769.             $countPlusSettings->setUsersListMessageId($result->getMessageId());
  770.             $this->em->flush();
  771.         } else {
  772.             try {
  773.                 $this->editRemoteMessage($chatId$countPlusSettings->getUsersListMessageId(),
  774.                     $statistics);
  775.             } catch (MessageEditedBySameTextException $exception) {
  776.                 //do nothing
  777.             } catch (MessageToEditNotFoundException $exception) {
  778.                 $result $this->sendMessage($chatId$statistics);
  779.                 $countPlusSettings->setUsersListMessageId($result->getMessageId());
  780.                 $this->em->flush();
  781.             }
  782.         }
  783.     }
  784.     protected function onBotAddedToGroup(Update $updatestring $chatIdstring $userId)
  785.     {
  786.         $user $this->telegramUserService->createOrGet($update->getMessage()->getFrom()->getData());
  787.         $group $this->telegramChatService->createOrGetDefault([
  788.             "chatId" => $update->getMessage()->getChat()->getId(),
  789.             "title" => $update->getMessage()->getChat()->getTitle(),
  790.             "type" => $update->getMessage()->getChat()->getType(),
  791.         ]);
  792.         $this->telegramUserService->addAdministratesChat($user$group);
  793.         $bot $this->getTelegramBotEntity();
  794.         $this->telegramBotService->addBotToChat($bot$group);
  795.     }
  796. }