Download attachments

This commit is contained in:
2022-11-29 11:12:06 -03:00
parent c53eb4c7a6
commit f8500e061c
21 changed files with 242 additions and 27 deletions

View File

@ -7,6 +7,7 @@ use Psr\Http\Message\ServerRequestInterface;
use ProVM\Common\Implement\Controller\Json;
use ProVM\Common\Service\Attachments as Service;
use ProVM\Emails\Model\Attachment;
use Psr\Log\LoggerInterface;
class Attachments
{
@ -51,4 +52,13 @@ class Attachments
}
return $this->withJson($response, $output);
}
public function get(ServerRequestInterface $request, ResponseInterface $response, Service $service, LoggerInterface $logger, int $attachment_id): ResponseInterface
{
$attachment = $service->getRepository()->fetchById($attachment_id);
$response->withHeader('Content-Type', 'application/pdf');
$response->withHeader('Content-Disposition', "'attachment;filename='{$attachment->getFullFilename()}'");
$response->getBody()->write($service->getFile($attachment_id));
return $response;
}
}

View File

@ -3,9 +3,11 @@ namespace ProVM\Common\Service;
use Ddeboer\Imap\Message\AttachmentInterface;
use Ddeboer\Imap\MessageInterface;
use Nyholm\Psr7\Stream;
use ProVM\Common\Exception\Message\NoAttachments;
use ProVM\Emails\Model\Message;
use ProVM\Emails\Repository\Attachment;
use Psr\Http\Message\StreamInterface;
use Psr\Log\LoggerInterface;
use Safe\Exceptions\FilesystemException;
@ -84,6 +86,22 @@ class Attachments extends Base
$remote_message = $this->getMessages()->getRemoteMessage($message->getUID());
return $this->getRemoteService()->get($remote_message, $relative_filename);
}
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()
]);
}
return \Safe\file_get_contents($filename);
}
public function getAll(): array
{

View File

@ -8,6 +8,6 @@ Monolog\ErrorHandler::register($app->getContainer()->get(Psr\Log\LoggerInterface
try {
$app->run();
} catch (Error | Exception $e) {
$app->getContainer()->get(\Psr\Log\LoggerInterface::class)->error($e);
$app->getContainer()->get(Psr\Log\LoggerInterface::class)->error($e);
throw $e;
}

View File

@ -5,4 +5,7 @@ $app->group('/attachments', function($app) {
$app->put('/grab', [Attachments::class, 'grab']);
$app->post('/decrypt', [Attachments::class, 'decrypt']);
$app->get('[/]', Attachments::class);
});
$app->group('/attachment/{attachment_id}', function($app) {
$app->get('[/]', [Attachments::class, 'get']);
});

View File

@ -6,4 +6,7 @@ $app->group('/messages', function($app) {
$app->put('/grab', [Messages::class, 'grab']);
$app->put('/schedule', [Jobs::class, 'schedule']);
$app->get('/pending', [Jobs::class, 'pending']);
});
$app->group('/message/{message_id}', function($app) {
$app->get('[/]', [Messages::class, 'get']);
});

View File

@ -2,21 +2,21 @@
use Psr\Container\ContainerInterface;
return [
\Monolog\Handler\DeduplicationHandler::class => function(ContainerInterface $container) {
return new \Monolog\Handler\DeduplicationHandler($container->get(\Monolog\Handler\RotatingFileHandler::class));
Monolog\Handler\DeduplicationHandler::class => function(ContainerInterface $container) {
return new Monolog\Handler\DeduplicationHandler($container->get(Monolog\Handler\RotatingFileHandler::class));
},
\Monolog\Handler\RotatingFileHandler::class => function(ContainerInterface $container) {
$handler = new \Monolog\Handler\RotatingFileHandler($container->get('log_file'));
$handler->setFormatter($container->get(\Monolog\Formatter\SyslogFormatter::class));
Monolog\Handler\RotatingFileHandler::class => function(ContainerInterface $container) {
$handler = new Monolog\Handler\RotatingFileHandler($container->get('log_file'));
$handler->setFormatter($container->get(Monolog\Formatter\SyslogFormatter::class));
return $handler;
},
\Psr\Log\LoggerInterface::class => function(ContainerInterface $container) {
$logger = new \Monolog\Logger('file_logger');
$logger->pushHandler($container->get(\Monolog\Handler\DeduplicationHandler::class));
//$logger->pushHandler($container->get(\Monolog\Handler\RotatingFileHandler::class));
$logger->pushProcessor($container->get(\Monolog\Processor\PsrLogMessageProcessor::class));
$logger->pushProcessor($container->get(\Monolog\Processor\IntrospectionProcessor::class));
$logger->pushProcessor($container->get(\Monolog\Processor\MemoryUsageProcessor::class));
Psr\Log\LoggerInterface::class => function(ContainerInterface $container) {
$logger = new Monolog\Logger('file_logger');
$logger->pushHandler($container->get(Monolog\Handler\DeduplicationHandler::class));
//$logger->pushHandler($container->get(Monolog\Handler\RotatingFileHandler::class));
$logger->pushProcessor($container->get(Monolog\Processor\PsrLogMessageProcessor::class));
$logger->pushProcessor($container->get(Monolog\Processor\IntrospectionProcessor::class));
$logger->pushProcessor($container->get(Monolog\Processor\MemoryUsageProcessor::class));
return $logger;
}
];

View File

@ -163,6 +163,7 @@ class Attachment implements Model
'date_time' => $this->getMessage()->getDateTime()->format('Y-m-d H:i:s')
],
'filename' => $this->getFilename(),
'fullname' => $this->getFullFilename(),
'downloaded' => $this->isDownloaded(),
'encrypted' => $this->isEncrypted(),
'decrypted' => $this->isDecrypted()

View File

@ -0,0 +1,21 @@
<?php
namespace ProVM\Common\Controller;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Client\ClientInterface;
use Psr\Log\LoggerInterface;
class Attachments
{
public function get(ServerRequestInterface $request, ResponseInterface $response, ClientInterface $client, LoggerInterface $logger, int $attachment_id): ResponseInterface
{
$rs = $client->get("/attachment/{$attachment_id}", [
'stream' => true,
'sink' => \Safe\fopen('php://stdout', 'wb')
]);
$response->withHeader('Content-Type', 'application/pdf');
$response->getBody()->write($rs->getBody()->getContents());
return $response;
}
}

View File

@ -11,8 +11,12 @@ class Emails
{
return $view->render($response, 'emails.mailboxes');
}
public function messages(ServerRequestInterface $request, ResponseInterface $response, View $view, string $mailbox): ResponseInterface
public function messages(ServerRequestInterface $request, ResponseInterface $response, View $view, int $mailbox_id): ResponseInterface
{
return $view->render($response, 'emails.messages', ['mailbox_id' => $mailbox]);
return $view->render($response, 'emails.messages', compact('mailbox_id'));
}
public function show(ServerRequestInterface $request, ResponseInterface $response, View $view, int $message_id): ResponseInterface
{
return $view->render($response, 'emails.show', compact('message_id'));
}
}

View File

@ -3,6 +3,7 @@
"type": "project",
"require": {
"berrnd/slim-blade-view": "^1.0",
"guzzlehttp/guzzle": "^7.5",
"monolog/monolog": "^3.2",
"nyholm/psr7": "^1.5",
"nyholm/psr7-server": "^1.0",

View File

@ -4,4 +4,10 @@ $app = require_once implode(DIRECTORY_SEPARATOR, [
'setup',
'app.php'
]);
$app->run();
Monolog\ErrorHandler::register($app->getContainer()->get(Psr\Log\LoggerInterface::class));
try {
$app->run();
} catch (Error | Exception $e) {
$app->getContainer()->get(Psr\Log\LoggerInterface::class)->error($e);
throw $e;
}

View File

@ -2,9 +2,12 @@
use ProVM\Common\Controller\Emails;
$app->group('/emails', function($app) {
$app->group('/mailbox/{mailbox}', function ($app) {
$app->group('/mailbox/{mailbox_id}', function($app) {
$app->get('[/]', [Emails::class, 'messages']);
});
$app->group('/message/{message_id}', function($app) {
$app->get('[/]', [Emails::class, 'show']);
});
$app->get('/mailboxes', Emails::class);
$app->get('[/]', Emails::class);
});

View File

@ -0,0 +1,6 @@
<?php
use ProVM\Common\Controller\Attachments;
$app->group('/attachment/{attachment_id}', function($app) {
$app->get('[/]', [Attachments::class, 'get']);
});

View File

@ -141,7 +141,7 @@
$('<div></div>').addClass('ui popup').append(list)
)
}
return $('<tr></tr>').append(
const tr = $('<tr></tr>').append(
$('<td></td>').html(this.get().subject())
).append(
$('<td></td>').html(format.format(date))
@ -163,6 +163,19 @@
}) : ''
)
)
if (this.has().downloaded()) {
tr.find('td').each((i, td) => {
const content = $(td).html()
if (content.indexOf('icon') > -1) {
return
}
$(td).html('')
$(td).append(
$('<a></a>').attr('href', '{{$urls->base}}/emails/message/' + this.id).html(content)
)
})
}
return tr
}
download() {

View File

@ -0,0 +1,103 @@
@extends('emails.base')
@section('emails_content')
<h3>Message - <span id="subject"></span> - <span id="from"></span></h3>
<h4 id="date_time"></h4>
<div class="ui list" id="attachments"></div>
@endsection
@push('page_scripts')
<script type="text/javascript">
const message = {
ids: {
subject: '',
from: '',
date_time: '',
attachments: ''
},
data: {
subject: '',
from: '',
date_time: '',
attachments: []
},
get: function() {
return {
message: message_id => {
return Send.get('/message/' + message_id).then(response => {
this.set().subject(response.message.subject)
.set().from(response.message.from)
.set().date_time(response.message.date_time)
.set().attachments(response.message.attachments)
}).then(() => {
this.draw().data()
})
},
subject: () => {
return this.data.subject
},
from: () => {
return this.data.from
},
date_time: () => {
return this.data.date_time
},
attachments: () => {
return this.data.attachments
}
}
},
set: function() {
return {
subject: subject => {
this.data.subject = subject
return this
},
from: from => {
this.data.from = from
return this
},
date_time: date => {
this.data.date_time = date
return this
},
attachments: attachments => {
attachments.forEach(attachment => {
this.data.attachments.push(attachment)
})
return this
}
}
},
draw: function() {
return {
data: () => {
$(this.ids.subject).html(this.get().subject())
$(this.ids.from).html(this.get().from())
$(this.ids.date_time).html(this.get().date_time())
this.draw().attachments($(this.ids.attachments))
},
attachments: parent => {
this.get().attachments().forEach(attachment => {
parent.append(
$('<a></a>').attr('href', _urls.base + '/attachment/' + attachment.id).attr('download', attachment.fullname).html(attachment.fullname)
)
})
}
}
},
setup: function(message_id) {
this.get().message(message_id)
}
}
$(document).ready(() => {
message.ids.subject = '#subject'
message.ids.from = '#from'
message.ids.date_time = '#date_time'
message.ids.attachments = '#attachments'
message.setup('{{$message_id}}')
})
</script>
@endpush

View File

@ -35,4 +35,5 @@
return this.base({method: 'delete', uri, data, dataType, contentType})
}
}
const _urls = JSON.parse('{!! Safe\json_encode($urls) !!}')
</script>

View File

@ -1,2 +1,2 @@
<?php
$app->add($app->getContainer()->get(\Zeuxisoo\Whoops\Slim\WhoopsMiddleware::class));
$app->add($app->getContainer()->get(Zeuxisoo\Whoops\Slim\WhoopsMiddleware::class));

View File

@ -1,4 +1,4 @@
<?php
return [
'api_key' => $_ENV['API_KEY']
'api_key' => sha1($_ENV['API_KEY'])
];

View File

@ -0,0 +1,15 @@
<?php
use Psr\Container\ContainerInterface;
return [
Psr\Http\Client\ClientInterface::class => function(ContainerInterface $container) {
return new GuzzleHttp\Client([
'base_uri' => "http://proxy:8080",
'headers' => [
'Authorization' => [
"Bearer {$container->get('api_key')}"
]
]
]);
}
];

View File

@ -9,7 +9,7 @@ return [
null,
[
'urls' => $container->get('urls'),
'api_key' => sha1($container->get('api_key'))
'api_key' => $container->get('api_key')
]
);
}

View File

@ -2,14 +2,21 @@
use Psr\Container\ContainerInterface;
return [
\Monolog\Handler\RotatingFileHandler::class => function(ContainerInterface $container) {
$handler = new \Monolog\Handler\RotatingFileHandler($container->get('log_file'));
$handler->setFormatter($container->get(\Monolog\Formatter\LineFormatter::class));
Monolog\Handler\DeduplicationHandler::class => function(ContainerInterface $container) {
return new Monolog\Handler\DeduplicationHandler($container->get(Monolog\Handler\RotatingFileHandler::class));
},
Monolog\Handler\RotatingFileHandler::class => function(ContainerInterface $container) {
$handler = new Monolog\Handler\RotatingFileHandler($container->get('log_file'));
$handler->setFormatter($container->get(Monolog\Formatter\SyslogFormatter::class));
return $handler;
},
\Psr\Log\LoggerInterface::class => function(ContainerInterface $container) {
$logger = new \Monolog\Logger('file_logger');
$logger->pushHandler($container->get(\Monolog\Handler\RotatingFileHandler::class));
Psr\Log\LoggerInterface::class => function(ContainerInterface $container) {
$logger = new Monolog\Logger('file_logger');
$logger->pushHandler($container->get(Monolog\Handler\DeduplicationHandler::class));
//$logger->pushHandler($container->get(Monolog\Handler\RotatingFileHandler::class));
$logger->pushProcessor($container->get(Monolog\Processor\PsrLogMessageProcessor::class));
$logger->pushProcessor($container->get(Monolog\Processor\IntrospectionProcessor::class));
$logger->pushProcessor($container->get(Monolog\Processor\MemoryUsageProcessor::class));
return $logger;
}
];