CLI
This commit is contained in:
@ -3,11 +3,12 @@ FROM php:8-cli
|
||||
ENV PATH ${PATH}:/app/bin
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y libc-client-dev libkrb5-dev git libzip-dev unzip \
|
||||
&& apt-get install -y cron git libzip-dev unzip \
|
||||
&& rm -r /var/lib/apt/lists/* \
|
||||
&& docker-php-ext-configure imap --with-kerberos --with-imap-ssl \
|
||||
&& docker-php-ext-install imap zip
|
||||
&& docker-php-ext-install zip
|
||||
|
||||
COPY --from=composer /usr/bin/composer /usr/bin/composer
|
||||
COPY ./crontab /var/spool/cron/crontabs/root
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
CMD [ "cron", "-f", "-L", "15" ]
|
||||
|
67
cli/common/Command/DecryptPdf.php
Normal file
67
cli/common/Command/DecryptPdf.php
Normal file
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
namespace ProVM\Common\Command;
|
||||
|
||||
use ProVM\Common\Service\Communicator;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
#[AsCommand(
|
||||
name: 'attachments:decrypt',
|
||||
description: 'Decrypt attachments pending',
|
||||
hidden: false
|
||||
)]
|
||||
class DecryptPdf extends Command
|
||||
{
|
||||
public function __construct(Communicator $communicator, string $name = null)
|
||||
{
|
||||
$this->setCommunicator($communicator);
|
||||
parent::__construct($name);
|
||||
}
|
||||
|
||||
protected Communicator $communicator;
|
||||
public function getCommunicator(): Communicator
|
||||
{
|
||||
return $this->communicator;
|
||||
}
|
||||
public function setCommunicator(Communicator $communicator): DecryptPdf
|
||||
{
|
||||
$this->communicator = $communicator;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function getAttachments(): array
|
||||
{
|
||||
$response = $this->getCommunicator()->get('/attachments/pending');
|
||||
return \Safe\json_decode($response->getBody()->getContents())->attachments;
|
||||
}
|
||||
protected function decrypt(string $attachment): bool
|
||||
{
|
||||
$response = $this->getCommunicator()->put('/attachments/decrypt', ['attachments' => [$attachment]]);
|
||||
return \Safe\json_decode($response->getBody()->getContents())->status;
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$io->title('Decrypt Attachments');
|
||||
|
||||
$io->section('Grabbing Attachments');
|
||||
$attachments = $this->getAttachments();
|
||||
$io->text('Found ' . count($attachments) . ' attachments.');
|
||||
$io->section('Decrypting Attachments');
|
||||
foreach ($attachments as $attachment) {
|
||||
$status = $this->decrypt($attachment);
|
||||
if ($status) {
|
||||
$io->success("{$attachment} decrypted correctly.");
|
||||
} else {
|
||||
$io->error("Problem decrypting {$attachment}.");
|
||||
}
|
||||
}
|
||||
$io->success('Done.');
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
64
cli/common/Command/GrabAttachments.php
Normal file
64
cli/common/Command/GrabAttachments.php
Normal file
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
namespace ProVM\Common\Command;
|
||||
|
||||
use ProVM\Common\Service\Communicator;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
#[AsCommand(
|
||||
name: 'attachments:grab',
|
||||
description: 'Grab attachments from pending messages',
|
||||
aliases: ['attachments:get'],
|
||||
hidden: false
|
||||
)]
|
||||
class GrabAttachments extends Command
|
||||
{
|
||||
public function __construct(Communicator $communicator, string $name = null)
|
||||
{
|
||||
$this->setCommunicator($communicator);
|
||||
parent::__construct($name);
|
||||
}
|
||||
|
||||
protected Communicator $service;
|
||||
public function getCommunicator(): Communicator
|
||||
{
|
||||
return $this->service;
|
||||
}
|
||||
public function setCommunicator(Communicator $service): GrabAttachments
|
||||
{
|
||||
$this->service = $service;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function getMessages(): array
|
||||
{
|
||||
$response = $this->getCommunicator()->get('/messages/pending');
|
||||
return \Safe\json_decode($response->getBody()->getContents())->messages;
|
||||
}
|
||||
protected function grabAttachments(int $message_uid): int
|
||||
{
|
||||
$response = $this->getCommunicator()->put('/attachments/grab', ['messages' => [$message_uid]]);
|
||||
return \Safe\json_decode($response->getBody()->getContents())->attachment_count;
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$io->title('Grab Attachments');
|
||||
|
||||
$io->section('Grabbing Messages');
|
||||
$messages = $this->getMessages();
|
||||
$io->text('Found ' . count($messages) . ' messages.');
|
||||
$io->section('Grabbing Attachments');
|
||||
foreach ($messages as $message) {
|
||||
$attachments = $this->grabAttachments($message);
|
||||
$io->text("Found {$attachments} attachments for message UID:{$message}.");
|
||||
}
|
||||
$io->success('Done.');
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
66
cli/common/Command/Messages.php
Normal file
66
cli/common/Command/Messages.php
Normal file
@ -0,0 +1,66 @@
|
||||
<?php
|
||||
namespace ProVM\Common\Command;
|
||||
|
||||
use ProVM\Common\Service\Communicator;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
#[AsCommand(
|
||||
name: 'messages:grab',
|
||||
description: 'Run grab messages job for registered mailboxes',
|
||||
aliases: ['messages'],
|
||||
hidden: false
|
||||
)]
|
||||
class Messages extends Command
|
||||
{
|
||||
public function __construct(Communicator $communicator, string $name = null)
|
||||
{
|
||||
$this->setCommunicator($communicator);
|
||||
parent::__construct($name);
|
||||
}
|
||||
|
||||
protected Communicator $communicator;
|
||||
public function getCommunicator(): Communicator
|
||||
{
|
||||
return $this->communicator;
|
||||
}
|
||||
public function setCommunicator(Communicator $communicator): Messages
|
||||
{
|
||||
$this->communicator = $communicator;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function getMailboxes(): array
|
||||
{
|
||||
$response = $this->getCommunicator()->get('/mailboxes/registered');
|
||||
return \Safe\json_decode($response->getBody()->getContents())->mailboxes;
|
||||
}
|
||||
protected function grabMessages(string $mailbox): int
|
||||
{
|
||||
$response = $this->getCommunicator()->put('/messages/grab', ['mailboxes' => [$mailbox]]);
|
||||
$body = \Safe\json_decode($response->getBody()->getContents());
|
||||
return $body->message_count;
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$io->title('Messages');
|
||||
$io->section('Grabbing Registered Mailboxes');
|
||||
|
||||
$mailboxes = $this->getMailboxes();
|
||||
$io->text('Found ' . count($mailboxes) . ' registered mailboxes.');
|
||||
$io->section('Grabbing Messages');
|
||||
foreach ($mailboxes as $mailbox) {
|
||||
$message_count = $this->grabMessages($mailbox->name);
|
||||
$io->text("Found {$message_count} messages in {$mailbox->name}.");
|
||||
}
|
||||
$io->success('Done.');
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
64
cli/common/Service/Communicator.php
Normal file
64
cli/common/Service/Communicator.php
Normal file
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
namespace ProVM\Common\Service;
|
||||
|
||||
use HttpResponseException;
|
||||
use Psr\Http\Client\ClientInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use function Safe\json_encode;
|
||||
|
||||
class Communicator
|
||||
{
|
||||
public function __construct(ClientInterface $client)
|
||||
{
|
||||
$this->setClient($client);
|
||||
}
|
||||
|
||||
protected ClientInterface $client;
|
||||
|
||||
public function getClient(): ClientInterface
|
||||
{
|
||||
return $this->client;
|
||||
}
|
||||
|
||||
public function setClient(ClientInterface $client): Communicator
|
||||
{
|
||||
$this->client = $client;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function handleResponse(ResponseInterface $response): ResponseInterface
|
||||
{
|
||||
if ($response->getStatusCode() < 200 or $response->getStatusCode() >= 300) {
|
||||
throw new HttpResponseException($response->getStatusCode(), $response->getReasonPhrase());
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
protected function request(string $method, string $uri, ?array $body = null): ResponseInterface
|
||||
{
|
||||
$options = [];
|
||||
if ($body !== null) {
|
||||
$options['headers'] = [
|
||||
'Content-Type' => 'application/json'
|
||||
];
|
||||
$options['body'] = json_encode($body);
|
||||
}
|
||||
return $this->handleResponse($this->getClient()->request($method, $uri, $options));
|
||||
}
|
||||
|
||||
public function get(string $uri): ResponseInterface
|
||||
{
|
||||
return $this->request('get', $uri);
|
||||
}
|
||||
public function post(string $uri, array $data): ResponseInterface
|
||||
{
|
||||
return $this->request('post', $uri, $data);
|
||||
}
|
||||
public function put(string $uri, array $data): ResponseInterface
|
||||
{
|
||||
return $this->request('put', $uri, $data);
|
||||
}
|
||||
public function delete(string $uri, array $data): ResponseInterface
|
||||
{
|
||||
return $this->request('delete', $uri, $data);
|
||||
}
|
||||
}
|
25
cli/common/Wrapper/Application.php
Normal file
25
cli/common/Wrapper/Application.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
namespace ProVM\Common\Wrapper;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Symfony\Component\Console\Application as Base;
|
||||
|
||||
class Application extends Base
|
||||
{
|
||||
public function __construct(ContainerInterface $container, string $name = 'UNKNOWN', string $version = 'UNKNOWN')
|
||||
{
|
||||
$this->setContainer($container);
|
||||
parent::__construct($name, $version);
|
||||
}
|
||||
|
||||
protected ContainerInterface $container;
|
||||
public function getContainer(): ContainerInterface
|
||||
{
|
||||
return $this->container;
|
||||
}
|
||||
public function setContainer(ContainerInterface $container): Application
|
||||
{
|
||||
$this->container = $container;
|
||||
return $this;
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
"name": "provm/emails",
|
||||
"type": "project",
|
||||
"require": {
|
||||
"ddeboer/imap": "^1.14",
|
||||
"guzzlehttp/guzzle": "^7.5",
|
||||
"monolog/monolog": "^3.2",
|
||||
"php-di/php-di": "^6.4",
|
||||
"symfony/console": "^6.1",
|
||||
@ -15,8 +15,7 @@
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"ProVM\\Common\\": "common/",
|
||||
"Provm\\Emails\\": "src/"
|
||||
"ProVM\\Common\\": "common/"
|
||||
}
|
||||
},
|
||||
"authors": [
|
||||
|
3
cli/crontab
Normal file
3
cli/crontab
Normal file
@ -0,0 +1,3 @@
|
||||
# minutes hour day_of_month month day_of_week command
|
||||
0 2 * * 2-6 /app/bin/emails messages:grab >> /logs/messages.log
|
||||
0 3 * * 2-6 /app/bin/emails attachments:grab >> /logs/attachments.log
|
@ -3,14 +3,13 @@ services:
|
||||
cli:
|
||||
profiles:
|
||||
- cli
|
||||
container_name: cli
|
||||
container_name: emails-cli
|
||||
build:
|
||||
context: ${CLI_PATH:-.}
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- ${CLI_PATH:-.}/.env
|
||||
- .mail.env
|
||||
- .key.env
|
||||
volumes:
|
||||
- ${CLI_PATH:-.}/:/app
|
||||
- ./logs:/logs
|
||||
- ${ATT_PATH}:/attachments
|
||||
- ./logs/cli:/logs
|
||||
|
@ -4,4 +4,9 @@ $app = require_once implode(DIRECTORY_SEPARATOR, [
|
||||
'setup',
|
||||
'app.php'
|
||||
]);
|
||||
$app->run();
|
||||
try {
|
||||
$app->run();
|
||||
} catch (Error | Exception $e) {
|
||||
$app->getContainer()->get(\Psr\Log\LoggerInterface::class)->error($e);
|
||||
throw $e;
|
||||
}
|
||||
|
2
cli/resources/commands/01_messages.php
Normal file
2
cli/resources/commands/01_messages.php
Normal file
@ -0,0 +1,2 @@
|
||||
<?php
|
||||
$app->add($app->getContainer()->get(\ProVM\Common\Command\Messages::class));
|
3
cli/resources/commands/02_attachments.php
Normal file
3
cli/resources/commands/02_attachments.php
Normal file
@ -0,0 +1,3 @@
|
||||
<?php
|
||||
$app->add($app->getContainer()->get(\ProVM\Common\Command\GrabAttachments::class));
|
||||
$app->add($app->getContainer()->get(\ProVM\Common\Command\DecryptPdf::class));
|
@ -1,16 +1,5 @@
|
||||
<?php
|
||||
return [
|
||||
'email' => function() {
|
||||
$data = [
|
||||
'host' => $_ENV['EMAIL_HOST'],
|
||||
'username' => $_ENV['EMAIL_USERNAME'],
|
||||
'password' => $_ENV['EMAIL_PASSWORD'],
|
||||
'folder' => $_ENV['EMAIL_FOLDER'],
|
||||
'attachments' => $_ENV['ATTACHMENTS_FOLDER'],
|
||||
];
|
||||
if (isset($_ENV['EMAIL_PORT'])) {
|
||||
$data['port'] = $_ENV['EMAIL_PORT'];
|
||||
}
|
||||
return json_decode(json_encode($data));
|
||||
}
|
||||
'api_uri' => $_ENV['API_URI'],
|
||||
'api_key' => sha1($_ENV['API_KEY'])
|
||||
];
|
||||
|
13
cli/setup/setups/02_api.php
Normal file
13
cli/setup/setups/02_api.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
return [
|
||||
\Psr\Http\Client\ClientInterface::class => function(ContainerInterface $container) {
|
||||
return new \GuzzleHttp\Client([
|
||||
'base_uri' => $container->get('api_uri'),
|
||||
'headers' => [
|
||||
'Authorization' => "Bearer {$container->get('api_key')}"
|
||||
]
|
||||
]);
|
||||
}
|
||||
];
|
@ -1,25 +0,0 @@
|
||||
<?php
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
return [
|
||||
\Ddeboer\Imap\ServerInterface::class => function(ContainerInterface $container) {
|
||||
$emails = $container->get('email');
|
||||
if (isset($emails->port)) {
|
||||
return new \Ddeboer\Imap\Server($emails->host, $emails->port);
|
||||
}
|
||||
return new \Ddeboer\Imap\Server($emails->host);
|
||||
},
|
||||
\Ddeboer\Imap\ConnectionInterface::class => function(ContainerInterface $container) {
|
||||
$emails = $container->get('email');
|
||||
$server = $container->get(\Ddeboer\Imap\ServerInterface::class);
|
||||
return $server->authenticate($emails->username, $emails->password);
|
||||
},
|
||||
\ProVM\Common\Service\Emails::class => function(ContainerInterface $container) {
|
||||
return new \ProVM\Common\Service\Emails(
|
||||
$container->get(\Ddeboer\Imap\ConnectionInterface::class),
|
||||
$container->get(\Psr\Log\LoggerInterface::class),
|
||||
$container->get('email')->folder,
|
||||
$container->get('email')->attachments
|
||||
);
|
||||
}
|
||||
];
|
Reference in New Issue
Block a user