Files
emails/api/common/Service/Attachments.php

329 lines
12 KiB
PHP
Raw Normal View History

2022-11-25 20:52:52 -03:00
<?php
namespace ProVM\Common\Service;
2023-06-08 20:49:27 -04:00
use ProVM\Common\Exception\Database\BlankResult;
use Psr\Log\LoggerInterface;
2022-11-25 20:52:52 -03:00
use Ddeboer\Imap\Message\AttachmentInterface;
use Ddeboer\Imap\MessageInterface;
2023-06-08 20:49:27 -04:00
use Safe\Exceptions\FilesystemException;
2022-11-28 22:56:21 -03:00
use ProVM\Common\Exception\Message\NoAttachments;
2022-11-25 20:52:52 -03:00
use ProVM\Emails\Model\Message;
2022-11-28 22:56:21 -03:00
use ProVM\Emails\Repository\Attachment;
2023-06-08 20:49:27 -04:00
use function Safe\{file_get_contents,file_put_contents};
2022-11-25 20:52:52 -03:00
2022-11-28 22:56:21 -03:00
class Attachments extends Base
2022-11-25 20:52:52 -03:00
{
2022-11-28 22:56:21 -03:00
public function __construct(Messages $messages, Attachment $repository, Remote\Attachments $remoteService,
Decrypt $decrypt, string $attachments_folder, LoggerInterface $logger)
2022-11-25 20:52:52 -03:00
{
2022-11-28 22:56:21 -03:00
$this->setMessages($messages)
->setRepository($repository)
->setRemoteService($remoteService)
->setDecrypt($decrypt)
->setFolder($attachments_folder)
->setLogger($logger);
2022-11-25 20:52:52 -03:00
}
2022-11-28 22:56:21 -03:00
protected Messages $messages;
protected Attachment $repository;
protected Remote\Attachments $remoteService;
2022-11-25 20:52:52 -03:00
protected Decrypt $decrypt;
2022-11-28 22:56:21 -03:00
protected string $folder;
2022-11-25 20:52:52 -03:00
2022-11-28 22:56:21 -03:00
public function getMessages(): Messages
2022-11-25 20:52:52 -03:00
{
2022-11-28 22:56:21 -03:00
return $this->messages;
}
public function getRepository(): Attachment
{
return $this->repository;
}
public function getRemoteService(): Remote\Attachments
{
return $this->remoteService;
2022-11-25 20:52:52 -03:00
}
public function getDecrypt(): Decrypt
{
return $this->decrypt;
}
2022-11-28 22:56:21 -03:00
public function getFolder(): string
2022-11-25 20:52:52 -03:00
{
2022-11-28 22:56:21 -03:00
return $this->folder;
2022-11-25 20:52:52 -03:00
}
2022-11-28 22:56:21 -03:00
public function setMessages(Messages $messages): Attachments
2022-11-25 20:52:52 -03:00
{
2022-11-28 22:56:21 -03:00
$this->messages = $messages;
2022-11-25 20:52:52 -03:00
return $this;
}
2022-11-28 22:56:21 -03:00
public function setRepository(Attachment $repository): Attachments
2022-11-25 20:52:52 -03:00
{
2022-11-28 22:56:21 -03:00
$this->repository = $repository;
2022-11-25 20:52:52 -03:00
return $this;
}
2022-11-28 22:56:21 -03:00
public function setRemoteService(Remote\Attachments $service): Attachments
2022-11-25 20:52:52 -03:00
{
2022-11-28 22:56:21 -03:00
$this->remoteService = $service;
2022-11-25 20:52:52 -03:00
return $this;
}
2022-11-28 22:56:21 -03:00
public function setDecrypt(Decrypt $decrypt): Attachments
2022-11-25 20:52:52 -03:00
{
2022-11-28 22:56:21 -03:00
$this->decrypt = $decrypt;
return $this;
2022-11-25 20:52:52 -03:00
}
2022-11-28 22:56:21 -03:00
public function setFolder(string $folder): Attachments
2022-11-25 20:52:52 -03:00
{
2022-11-28 22:56:21 -03:00
$this->folder = $folder;
return $this;
2022-11-25 20:52:52 -03:00
}
2022-11-28 22:56:21 -03:00
public function getLocalAttachment(Message $message, string $relative_filename): \ProVM\Emails\Model\Attachment
2022-11-25 20:52:52 -03:00
{
2022-11-28 22:56:21 -03:00
return $this->getRepository()->fetchByMessageAndFilename($message->getId(), $relative_filename);
2022-11-25 20:52:52 -03:00
}
2022-11-28 22:56:21 -03:00
public function getRemoteAttachment(Message $message, string $relative_filename): AttachmentInterface
2022-11-25 20:52:52 -03:00
{
2022-11-28 22:56:21 -03:00
$remote_message = $this->getMessages()->getRemoteMessage($message->getUID());
return $this->getRemoteService()->get($remote_message, $relative_filename);
2022-11-25 20:52:52 -03:00
}
2022-11-29 11:12:06 -03:00
public function getFile(int $attachment_id): string
{
$attachment = $this->getRepository()->fetchById($attachment_id);
$filename = implode(DIRECTORY_SEPARATOR, [
$this->getFolder(),
$attachment->getFullFilename()
]);
if ($attachment->isDecrypted()) {
$filename = implode(DIRECTORY_SEPARATOR, [
$this->getFolder(),
'decrypted',
$attachment->getFullFilename()
]);
}
2023-06-08 20:49:27 -04:00
return file_get_contents($filename);
2022-11-29 11:12:06 -03:00
}
2022-11-25 20:52:52 -03:00
2022-11-28 22:56:21 -03:00
public function getAll(): array
2022-11-25 20:52:52 -03:00
{
2022-11-28 22:56:21 -03:00
return $this->getRepository()->fetchAll();
2022-11-25 20:52:52 -03:00
}
2023-06-08 20:49:27 -04:00
public function getDownloadedFiles(): array
{
$downloaded = [];
$folder = $this->getFolder();
$files = new \FilesystemIterator($folder);
foreach ($files as $file) {
if ($file->isDir()) {
continue;
}
$name = $file->getBasename(".{$file->getExtension()}");
2023-06-12 21:14:07 -04:00
list($date, $subject, $filename) = explode(' - ', $name);
2023-06-08 20:49:27 -04:00
try {
$message = $this->getMessages()->find($subject, $date)[0];
$filename = "{$filename}.{$file->getExtension()}";
$downloaded []= compact('message', 'filename');
} catch (BlankResult $e) {
}
}
return $downloaded;
}
2022-11-28 22:56:21 -03:00
public function create(int $message_id): array
2022-11-25 20:52:52 -03:00
{
2022-11-28 22:56:21 -03:00
$message = $this->getMessages()->getRepository()->fetchById($message_id);
$remote_message = $this->getMessages()->getRemoteMessage($message->getUID());
if (!$remote_message->hasAttachments()) {
throw new NoAttachments($remote_message);
}
2022-11-25 20:52:52 -03:00
$attachments = [];
2022-11-28 22:56:21 -03:00
foreach ($remote_message->getAttachments() as $attachment) {
if (!$this->getMessages()->validateAttachment($attachment)) {
2022-11-25 20:52:52 -03:00
continue;
}
2022-11-28 22:56:21 -03:00
if ($this->save($message, $attachment, false)) {
$attachments []= $attachment->getFilename();
}
2022-11-25 20:52:52 -03:00
}
return $attachments;
}
2022-11-28 22:56:21 -03:00
public function grab(int $message_id): array
2022-11-25 20:52:52 -03:00
{
2022-11-28 22:56:21 -03:00
$message = $this->getMessages()->getRepository()->fetchById($message_id);
$remote_message = $this->getMessages()->getRemoteMessage($message->getUID());
if (!$remote_message->hasAttachments()) {
throw new NoAttachments($remote_message);
}
2022-11-25 20:52:52 -03:00
$attachments = [];
2022-11-28 22:56:21 -03:00
foreach ($remote_message->getAttachments() as $attachment) {
if (!$this->getMessages()->validateAttachment($attachment)) {
2022-11-25 20:52:52 -03:00
continue;
}
2022-11-28 22:56:21 -03:00
if ($this->save($message, $attachment)) {
$attachments []= $attachment->getFilename();
}
2022-11-25 20:52:52 -03:00
}
return $attachments;
}
2022-11-28 22:56:21 -03:00
public function save(Message $message, AttachmentInterface $remote_attachment, bool $upload = true): bool
{
$data = [
'message_id' => $message->getId(),
'filename' => $remote_attachment->getFilename()
];
try {
$attachment = $this->getRepository()->create($data);
$this->getRepository()->save($attachment);
if ($upload and $this->upload($attachment, $remote_attachment)) {
$attachment->itIsDownloaded();
$message->doesHaveDownloadedAttachments();
$this->getMessages()->getRepository()->save($message);
if ($this->isFileEncrypted($attachment->getMessage(), $attachment->getFilename())) {
$attachment->itIsEncrypted();
if ($this->isFileDecrypted($attachment->getMessage(), $attachment->getFilename())) {
$attachment->itIsDecrypted();
} else {
if ($this->decrypt($attachment->getMessage(), $attachment->getFilename())) {
$attachment->itIsDecrypted();
}
}
}
2022-11-25 20:52:52 -03:00
}
2022-11-28 22:56:21 -03:00
$this->getRepository()->save($attachment);
return true;
} catch (PDOException $e) {
$this->getLogger()->error($e);
return false;
2022-11-25 20:52:52 -03:00
}
}
2022-11-28 22:56:21 -03:00
public function upload(\ProVM\Emails\Model\Attachment $attachment, AttachmentInterface $remote_attachment): bool
2022-11-25 20:52:52 -03:00
{
2022-11-28 22:56:21 -03:00
$destination = implode(DIRECTORY_SEPARATOR, [
$this->getFolder(),
$attachment->getFullFilename()
]);
try {
2023-06-08 20:49:27 -04:00
file_put_contents($destination, $remote_attachment->getDecodedContent());
2022-11-28 22:56:21 -03:00
return true;
} catch (FilesystemException $e) {
$this->getLogger()->error($e);
return false;
2022-11-25 20:52:52 -03:00
}
}
2022-11-28 22:56:21 -03:00
public function isFileEncrypted(Message $message, string $relative_filename): bool
2022-11-25 20:52:52 -03:00
{
2022-11-28 22:56:21 -03:00
$attachment = $this->getLocalAttachment($message, $relative_filename);
$filename = implode(DIRECTORY_SEPARATOR, [
$this->getFolder(),
$attachment->getFullFilename()
]);
try {
return $this->getDecrypt()->isEncrypted($filename);
} catch (\InvalidArgumentException $e) {
2022-11-25 20:52:52 -03:00
return false;
}
}
2022-11-28 22:56:21 -03:00
public function isFileDecrypted(Message $message, string $relative_filename): bool
2022-11-25 20:52:52 -03:00
{
2022-11-28 22:56:21 -03:00
$attachment = $this->getLocalAttachment($message, $relative_filename);
$filename = implode(DIRECTORY_SEPARATOR, [
$this->getFolder(),
'decrypted',
$attachment->getFullFilename()
]);
try {
return !$this->getDecrypt()->isEncrypted($filename);
} catch (\InvalidArgumentException $e) {
return false;
}
}
public function decrypt(Message $message, string $relative_filename): bool
{
$attachment = $this->getLocalAttachment($message, $relative_filename);
$source = implode(DIRECTORY_SEPARATOR, [
$this->getFolder(),
$attachment->getFullFilename()
]);
$destination = implode(DIRECTORY_SEPARATOR, [
$this->getFolder(),
'decrypted',
$attachment->getFullFilename()
]);
return $this->getDecrypt()->runCommand($source, $destination);
}
public function isDownloaded(Message $message, MessageInterface $remote_message): bool
{
if (!$message->hasValidAttachments()) {
return false;
}
2023-06-08 20:49:27 -04:00
if ($message->hasDownloadedAttachments()) {
return true;
}
2022-11-28 22:56:21 -03:00
foreach ($remote_message->getAttachments() as $attachment) {
if (!str_contains($attachment->getFilename(), '.pdf')) {
continue;
}
$attachment = $this->getLocalAttachment($message, $attachment->getFilename());
if (!$attachment->isDownloaded()) {
return false;
}
2022-11-25 20:52:52 -03:00
}
2022-11-28 22:56:21 -03:00
return true;
2022-11-25 20:52:52 -03:00
}
2023-06-08 20:49:27 -04:00
public function find(Message $message, string $filename): \ProVM\Emails\Model\Attachment
{
return $this->getRepository()->fetchByMessageAndFilename($message->getId(), $filename);
}
public function exists(Message $message, string $filename): bool
{
try {
$this->find($message, $filename);
return true;
} catch (BlankResult $e) {
return false;
}
}
public function add(Message $message, string $filename): bool
{
$data = [
'message_id' => $message->getId(),
'filename' => $filename
];
try {
$attachment = $this->getRepository()->create($data);
$attachment->itIsDownloaded();
$this->getRepository()->save($attachment);
$message->doesHaveDownloadedAttachments();
$this->getMessages()->getRepository()->save($message);
return true;
} catch (PDOException $e) {
$this->getLogger()->error($e);
return false;
}
}
public function checkDownloaded(): void
{
$data = $this->getDownloadedFiles();
foreach ($data as $info) {
if (!$this->exists($info['message'], $info['filename'])) {
$this->logger->info("Updating attachment {$info['filename']} for message {$info['message']->getSubject()}");
$this->add($info['message'], $info['filename']);
}
}
}
public function getDownloaded(): array
{
return $this->getRepository()->fetchDownloaded();
}
public function checkEncryption(): void
{
$attachments = $this->getDownloaded();
foreach ($attachments as $attachment) {
if ($attachment->isEncrypted() and !$attachment->isDecrypted()) {
$this->logger->notice("Schedule decrypt for {$attachment->getFullFilename()}");
$this->decrypt($attachment->getMessage(), $attachment->getFilename());
}
}
}
}