| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 |
- <?php
-
- declare(strict_types=1);
-
- namespace App\Service;
-
- use App\Presentation\PortfolioPresenter;
- use App\Service\TelegramNotifier;
- use PhpImap\Exceptions\ConnectionException;
- use PhpImap\IncomingMail;
- use Psr\Log\LoggerInterface;
- use SecIT\ImapBundle\Connection\ConnectionInterface;
- use Symfony\Component\DependencyInjection\Attribute\Target;
-
- readonly class MailFetcher
- {
- public function __construct(
- #[Target('finfollowConnection')]
- private ConnectionInterface $connection,
- private XmlParser $xmlParser,
- private PortfolioManager $portfolioManager,
- private LoggerInterface $logger,
- private TelegramNotifier $telegramNotifier,
- private PortfolioPresenter $portfolioPresenter,
- private AttachmentProcessor $attachmentProcessor,
- private string $validEmailSubject,
- private string $validEmailSender,
- )
- {
- }
-
- public function fetchNewEmails(): void
- {
- $mailbox = $this->connection->getMailbox();
- try {
- $mailsIds = $mailbox->searchMailbox('ALL');
- } catch (ConnectionException $ex) {
- $this->logger->error("IMAP connection failed: " . implode(",", $ex->getErrors('all')));
- throw new \RuntimeException('IMAP connection failed', 0, $ex);
- }
-
- if (!$mailsIds) {
- $this->logger->info('Mailbox is empty');
-
- return;
- }
-
- foreach ($mailsIds as $mailId) {
- $mail = $mailbox->getMail($mailId);
-
- $this->logger->debug(print_r([
- 'date' => $mail->date,
- 'message_id' => $mail->messageId,
- 'from' => $mail->fromAddress,
- 'subject' => $mail->subject,
- 'hasAttachments' => $mail->hasAttachments(),
- ], true));
-
- if ($this->canProcessMail($mail)) {
- $this->processMail($mail);
- $mailbox->deleteMail($mailId);
- $this->logger->debug("Deleted email with id=" . $mailId);
- } else {
- $this->logger->debug("Skipped mail with id=" . $mailId);
- }
- }
- }
-
- private function canProcessMail(IncomingMail $mail): bool
- {
- if (!$mail->hasAttachments()) {
- return false;
- }
-
- if (mb_stripos($mail->subject, $this->validEmailSubject) === false) {
- return false;
- }
-
- if (mb_stripos($mail->fromAddress, $this->validEmailSender) === false) {
- return false;
- }
-
- return true;
- }
-
- private function processMail(IncomingMail $mail): void
- {
- foreach ($mail->getAttachments() as $attachment) {
- $xmlString = $this->attachmentProcessor->extractXmlFromAttachment($attachment);
- if ($xmlString === null) {
- continue;
- }
-
- $xml = simplexml_load_string($xmlString);
- if ($xml === false) {
- $this->logger->error('Invalid XML from attachment');
- continue;
- }
-
- $parsedPortfolio = $this->xmlParser->processXml($xml);
-
- if ($this->portfolioManager->updatePortfolio($parsedPortfolio, $xmlString)) {
- $pngFilename = tempnam(sys_get_temp_dir(), 'finfollow-portfolio-');
- $this->portfolioPresenter->toImage($parsedPortfolio, $pngFilename);
- $this->telegramNotifier->notify('', $pngFilename);
- }
- }
- }
- }
|