feat: dummy replacement pdf upload for environments other than prod
This commit is contained in:
@@ -73,3 +73,5 @@ [email protected]
|
|||||||
|
|
||||||
FEATURE_SANITIZE_UPLOADS=false
|
FEATURE_SANITIZE_UPLOADS=false
|
||||||
FEATURE_STAMP_INVOICES=false
|
FEATURE_STAMP_INVOICES=false
|
||||||
|
|
||||||
|
UPLOAD_REPLACEMENT_FILE=assets/pdf/chicken.pdf
|
||||||
|
|||||||
Binary file not shown.
@@ -135,6 +135,8 @@ services:
|
|||||||
arguments:
|
arguments:
|
||||||
$orphanageManager: '@oneup_uploader.orphanage_manager'
|
$orphanageManager: '@oneup_uploader.orphanage_manager'
|
||||||
$projectDir: '%kernel.project_dir%'
|
$projectDir: '%kernel.project_dir%'
|
||||||
|
$environment: '%kernel.environment%'
|
||||||
|
$uploadReplacementFile: '%env(default::UPLOAD_REPLACEMENT_FILE)%'
|
||||||
|
|
||||||
App\Service\Pdf\Sanitizer:
|
App\Service\Pdf\Sanitizer:
|
||||||
arguments:
|
arguments:
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ class BatchDownloadController extends AbstractController
|
|||||||
/** @var Upload $upload */
|
/** @var Upload $upload */
|
||||||
$teamer = $upload->getOwner()->getTeamer();
|
$teamer = $upload->getOwner()->getTeamer();
|
||||||
$filename = $namer->nameForTeamer($upload, $teamer);
|
$filename = $namer->nameForTeamer($upload, $teamer);
|
||||||
$filepath = $this->uploadHandler->getUploadFilepath($upload);
|
$filepath = $this->uploadHandler->getResolvedUploadFilepath($upload);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$zip->addFileFromPath(fileName: $filename, path: $filepath);
|
$zip->addFileFromPath(fileName: $filename, path: $filepath);
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class DownloadController extends AbstractController
|
|||||||
#[IsGranted('DOWNLOAD', subject: 'upload')]
|
#[IsGranted('DOWNLOAD', subject: 'upload')]
|
||||||
public function index(Upload $upload, Request $request): Response
|
public function index(Upload $upload, Request $request): Response
|
||||||
{
|
{
|
||||||
$path = $this->uploadHandler->getUploadFilepath($upload);
|
$path = $this->uploadHandler->getResolvedUploadFilepath($upload);
|
||||||
|
|
||||||
if (true === in_array($upload->getType(), [Upload::TYPE_INVOICE, Upload::TYPE_CONTRACT])) {
|
if (true === in_array($upload->getType(), [Upload::TYPE_INVOICE, Upload::TYPE_CONTRACT])) {
|
||||||
$namer = new DownloadNamer();
|
$namer = new DownloadNamer();
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ class DatevEmailSubscriber implements EventSubscriberInterface
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$path = $this->uploadHandler->getUploadFilepath($document);
|
$path = $this->uploadHandler->getResolvedUploadFilepath($document);
|
||||||
|
|
||||||
if (false === file_exists($path)) {
|
if (false === file_exists($path)) {
|
||||||
$this->logger->error('DATEV email skipped: attachment file not found', [
|
$this->logger->error('DATEV email skipped: attachment file not found', [
|
||||||
|
|||||||
@@ -4,10 +4,20 @@ namespace App\Service\Pdf;
|
|||||||
|
|
||||||
use App\Entity\Disposition;
|
use App\Entity\Disposition;
|
||||||
use App\Entity\Upload;
|
use App\Entity\Upload;
|
||||||
|
use App\Service\Upload\UploadHandler;
|
||||||
use Symfony\Component\Filesystem\Filesystem;
|
use Symfony\Component\Filesystem\Filesystem;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
|
||||||
class InvoiceApprover extends AbstractPdfRenderer
|
class InvoiceApprover extends AbstractPdfRenderer
|
||||||
{
|
{
|
||||||
|
public function __construct(
|
||||||
|
TranslatorInterface $translator,
|
||||||
|
array $options,
|
||||||
|
private readonly UploadHandler $uploadHandler,
|
||||||
|
) {
|
||||||
|
parent::__construct($translator, $options);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws \InvalidArgumentException
|
* @throws \InvalidArgumentException
|
||||||
*/
|
*/
|
||||||
@@ -16,24 +26,23 @@ class InvoiceApprover extends AbstractPdfRenderer
|
|||||||
$teamer = $disposition->getTeamer();
|
$teamer = $disposition->getTeamer();
|
||||||
$assignment = $disposition->getAssignment();
|
$assignment = $disposition->getAssignment();
|
||||||
$invoice = $disposition->getDocumentByType(Upload::TYPE_INVOICE);
|
$invoice = $disposition->getDocumentByType(Upload::TYPE_INVOICE);
|
||||||
$originalFilename = $invoice->getFilename();
|
|
||||||
|
|
||||||
if ('application/pdf' !== $invoice->getMimeType()) {
|
if ('application/pdf' !== $invoice->getMimeType()) {
|
||||||
throw new \InvalidArgumentException('Expected PDF but got '.$invoice->getMimeType());
|
throw new \InvalidArgumentException('Expected PDF but got '.$invoice->getMimeType());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load template
|
$sourcePath = $this->uploadHandler->getResolvedUploadFilepath($invoice);
|
||||||
$folder = substr($originalFilename, 0, 1);
|
$targetPath = $this->uploadHandler->getUploadFilepath($invoice);
|
||||||
$filepath = sprintf('%s/uploads/invoice/%s/%s', $this->config['project_dir'], $folder, $originalFilename);
|
|
||||||
if (false === file_exists($filepath)) {
|
if (false === file_exists($sourcePath)) {
|
||||||
throw new \InvalidArgumentException('Uploaded document not found at '.$filepath);
|
throw new \InvalidArgumentException('Uploaded document not found at '.$sourcePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
$pdf = new Pdf();
|
$pdf = new Pdf();
|
||||||
|
|
||||||
$pdf->SetAuthor($teamer->getFullName(), true);
|
$pdf->SetAuthor($teamer->getFullName(), true);
|
||||||
$pdf->SetCreator($teamer->getFullName(), true);
|
$pdf->SetCreator($teamer->getFullName(), true);
|
||||||
$pdf->appendPdf($filepath);
|
$pdf->appendPdf($sourcePath);
|
||||||
$pdf->setPage(1);
|
$pdf->setPage(1);
|
||||||
|
|
||||||
// Cost unit job profile
|
// Cost unit job profile
|
||||||
@@ -53,9 +62,16 @@ class InvoiceApprover extends AbstractPdfRenderer
|
|||||||
$pdf->SetTextColor(0, 128, 0);
|
$pdf->SetTextColor(0, 128, 0);
|
||||||
$pdf->Text(20, 30, $pdf->encodeString('geprüft: '.$invoice->getApprovedBy()));
|
$pdf->Text(20, 30, $pdf->encodeString('geprüft: '.$invoice->getApprovedBy()));
|
||||||
|
|
||||||
$this->createBackup($filepath);
|
$filesystem = new Filesystem();
|
||||||
|
$targetDir = \dirname($targetPath);
|
||||||
|
|
||||||
$pdf->Output('F', $filepath);
|
if (false === $filesystem->exists($targetDir)) {
|
||||||
|
$filesystem->mkdir($targetDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->createBackup($targetPath);
|
||||||
|
|
||||||
|
$pdf->Output('F', $targetPath);
|
||||||
|
|
||||||
return $pdf;
|
return $pdf;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ class UploadHandler
|
|||||||
private readonly Sanitizer $sanitizer,
|
private readonly Sanitizer $sanitizer,
|
||||||
private readonly LoggerInterface $logger,
|
private readonly LoggerInterface $logger,
|
||||||
private readonly string $projectDir,
|
private readonly string $projectDir,
|
||||||
|
private readonly string $environment,
|
||||||
|
private readonly string $uploadReplacementFile,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,6 +145,27 @@ class UploadHandler
|
|||||||
return true === $absolute ? sprintf('%s/%s', $this->projectDir, $relativePath) : $relativePath;
|
return true === $absolute ? sprintf('%s/%s', $this->projectDir, $relativePath) : $relativePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the upload file path, substituting a replacement file in non-production environments
|
||||||
|
* when configured. Use this for read-only access (downloads, email attachments).
|
||||||
|
*/
|
||||||
|
public function getResolvedUploadFilepath(Upload $upload): string
|
||||||
|
{
|
||||||
|
$originalPath = $this->getUploadFilepath($upload);
|
||||||
|
|
||||||
|
if ('' === $this->uploadReplacementFile || 'prod' === $this->environment) {
|
||||||
|
return $originalPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
$replacementPath = sprintf('%s/%s', $this->projectDir, $this->uploadReplacementFile);
|
||||||
|
|
||||||
|
if (false === file_exists($replacementPath)) {
|
||||||
|
return $originalPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $replacementPath;
|
||||||
|
}
|
||||||
|
|
||||||
public function getTempUploadFilepath(UploadDto $uploadDto, string $uploadSessionId): string
|
public function getTempUploadFilepath(UploadDto $uploadDto, string $uploadSessionId): string
|
||||||
{
|
{
|
||||||
$tempUploadDir = $this->getTempUploadDir($uploadSessionId);
|
$tempUploadDir = $this->getTempUploadDir($uploadSessionId);
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ use App\Event\DocumentConfirmedEvent;
|
|||||||
use App\EventListener\DatevEmailSubscriber;
|
use App\EventListener\DatevEmailSubscriber;
|
||||||
use App\Model\EmailPathAttachmentDto;
|
use App\Model\EmailPathAttachmentDto;
|
||||||
use App\Service\Upload\UploadHandler;
|
use App\Service\Upload\UploadHandler;
|
||||||
|
use Flagception\Manager\FeatureManagerInterface;
|
||||||
use PHPUnit\Framework\MockObject\MockObject;
|
use PHPUnit\Framework\MockObject\MockObject;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
@@ -21,6 +22,7 @@ class DatevEmailSubscriberTest extends TestCase
|
|||||||
private Mailer&MockObject $mailer;
|
private Mailer&MockObject $mailer;
|
||||||
private UploadHandler&MockObject $uploadHandler;
|
private UploadHandler&MockObject $uploadHandler;
|
||||||
private LoggerInterface&MockObject $logger;
|
private LoggerInterface&MockObject $logger;
|
||||||
|
private FeatureManagerInterface&MockObject $featureManager;
|
||||||
private DatevEmailSubscriber $subscriber;
|
private DatevEmailSubscriber $subscriber;
|
||||||
|
|
||||||
protected function setUp(): void
|
protected function setUp(): void
|
||||||
@@ -28,6 +30,8 @@ class DatevEmailSubscriberTest extends TestCase
|
|||||||
$this->mailer = $this->createMock(Mailer::class);
|
$this->mailer = $this->createMock(Mailer::class);
|
||||||
$this->uploadHandler = $this->createMock(UploadHandler::class);
|
$this->uploadHandler = $this->createMock(UploadHandler::class);
|
||||||
$this->logger = $this->createMock(LoggerInterface::class);
|
$this->logger = $this->createMock(LoggerInterface::class);
|
||||||
|
$this->featureManager = $this->createMock(FeatureManagerInterface::class);
|
||||||
|
$this->featureManager->method('isActive')->with('datev_email')->willReturn(true);
|
||||||
|
|
||||||
$this->subscriber = new DatevEmailSubscriber(
|
$this->subscriber = new DatevEmailSubscriber(
|
||||||
$this->mailer,
|
$this->mailer,
|
||||||
@@ -35,6 +39,7 @@ class DatevEmailSubscriberTest extends TestCase
|
|||||||
$this->logger,
|
$this->logger,
|
||||||
'[email protected]',
|
'[email protected]',
|
||||||
'[email protected]',
|
'[email protected]',
|
||||||
|
$this->featureManager,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,7 +123,7 @@ class DatevEmailSubscriberTest extends TestCase
|
|||||||
$nonExistentPath = '/tmp/non_existent_file_'.uniqid().'.pdf';
|
$nonExistentPath = '/tmp/non_existent_file_'.uniqid().'.pdf';
|
||||||
|
|
||||||
$this->uploadHandler
|
$this->uploadHandler
|
||||||
->method('getUploadFilepath')
|
->method('getResolvedUploadFilepath')
|
||||||
->with($document)
|
->with($document)
|
||||||
->willReturn($nonExistentPath);
|
->willReturn($nonExistentPath);
|
||||||
|
|
||||||
@@ -160,7 +165,7 @@ class DatevEmailSubscriberTest extends TestCase
|
|||||||
try {
|
try {
|
||||||
$this->uploadHandler
|
$this->uploadHandler
|
||||||
->expects($this->once())
|
->expects($this->once())
|
||||||
->method('getUploadFilepath')
|
->method('getResolvedUploadFilepath')
|
||||||
->with($document)
|
->with($document)
|
||||||
->willReturn($tmpFile);
|
->willReturn($tmpFile);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
upload.orig.pdf
|
||||||
@@ -14,6 +14,8 @@ use App\Entity\Upload;
|
|||||||
use App\Service\Pdf\InvoiceApprover;
|
use App\Service\Pdf\InvoiceApprover;
|
||||||
use App\Service\Pdf\InvoiceRenderer;
|
use App\Service\Pdf\InvoiceRenderer;
|
||||||
use App\Service\Pdf\Pdf;
|
use App\Service\Pdf\Pdf;
|
||||||
|
use App\Service\Upload\UploadHandler;
|
||||||
|
use PHPUnit\Framework\MockObject\MockObject;
|
||||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||||
use Symfony\Component\Filesystem\Filesystem;
|
use Symfony\Component\Filesystem\Filesystem;
|
||||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
@@ -25,6 +27,7 @@ class InvoiceApproverTest extends WebTestCase
|
|||||||
private string $pdfPath;
|
private string $pdfPath;
|
||||||
private string $origPath;
|
private string $origPath;
|
||||||
private Filesystem $filesystem;
|
private Filesystem $filesystem;
|
||||||
|
private UploadHandler&MockObject $uploadHandler;
|
||||||
|
|
||||||
protected function setUp(): void
|
protected function setUp(): void
|
||||||
{
|
{
|
||||||
@@ -35,6 +38,7 @@ class InvoiceApproverTest extends WebTestCase
|
|||||||
$this->pdfPath = $this->invoiceDir.'/test_approver_backup.pdf';
|
$this->pdfPath = $this->invoiceDir.'/test_approver_backup.pdf';
|
||||||
$this->origPath = $this->invoiceDir.'/test_approver_backup.orig.pdf';
|
$this->origPath = $this->invoiceDir.'/test_approver_backup.orig.pdf';
|
||||||
$this->filesystem = new Filesystem();
|
$this->filesystem = new Filesystem();
|
||||||
|
$this->uploadHandler = $this->createMock(UploadHandler::class);
|
||||||
|
|
||||||
$this->filesystem->mkdir($this->invoiceDir);
|
$this->filesystem->mkdir($this->invoiceDir);
|
||||||
}
|
}
|
||||||
@@ -80,7 +84,7 @@ class InvoiceApproverTest extends WebTestCase
|
|||||||
$translator = $this->createMock(TranslatorInterface::class);
|
$translator = $this->createMock(TranslatorInterface::class);
|
||||||
|
|
||||||
/** @var TranslatorInterface $translator */
|
/** @var TranslatorInterface $translator */
|
||||||
return new InvoiceApprover($translator, ['project_dir' => $this->projectDir]);
|
return new InvoiceApprover($translator, ['project_dir' => $this->projectDir], $this->uploadHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createDispositionWithInvoicePdf(): Disposition
|
private function createDispositionWithInvoicePdf(): Disposition
|
||||||
@@ -130,6 +134,9 @@ class InvoiceApproverTest extends WebTestCase
|
|||||||
;
|
;
|
||||||
$disposition->addDocument($invoice);
|
$disposition->addDocument($invoice);
|
||||||
|
|
||||||
|
$this->uploadHandler->method('getResolvedUploadFilepath')->with($invoice)->willReturn($this->pdfPath);
|
||||||
|
$this->uploadHandler->method('getUploadFilepath')->with($invoice)->willReturn($this->pdfPath);
|
||||||
|
|
||||||
return $disposition;
|
return $disposition;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ use App\Entity\User;
|
|||||||
use App\Service\Pdf\InvoiceApprover;
|
use App\Service\Pdf\InvoiceApprover;
|
||||||
use App\Service\Pdf\InvoiceRenderer;
|
use App\Service\Pdf\InvoiceRenderer;
|
||||||
use App\Service\Pdf\Pdf;
|
use App\Service\Pdf\Pdf;
|
||||||
|
use App\Service\Upload\UploadHandler;
|
||||||
use Carbon\CarbonPeriod;
|
use Carbon\CarbonPeriod;
|
||||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
@@ -108,8 +109,13 @@ class InvoiceRendererTest extends WebTestCase
|
|||||||
;
|
;
|
||||||
$disposition->addDocument($invoice);
|
$disposition->addDocument($invoice);
|
||||||
|
|
||||||
|
$invoicePath = $projectDir.'/uploads/invoice/a/abcdef0123456789.pdf';
|
||||||
|
$uploadHandler = $this->createMock(UploadHandler::class);
|
||||||
|
$uploadHandler->method('getResolvedUploadFilepath')->with($invoice)->willReturn($invoicePath);
|
||||||
|
$uploadHandler->method('getUploadFilepath')->with($invoice)->willReturn($invoicePath);
|
||||||
|
|
||||||
/** @var TranslatorInterface $translator */
|
/** @var TranslatorInterface $translator */
|
||||||
$approver = new InvoiceApprover($translator, ['project_dir' => $projectDir]);
|
$approver = new InvoiceApprover($translator, ['project_dir' => $projectDir], $uploadHandler);
|
||||||
$pdf = $approver->render($disposition);
|
$pdf = $approver->render($disposition);
|
||||||
$this->assertInstanceOf(Pdf::class, $pdf);
|
$this->assertInstanceOf(Pdf::class, $pdf);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user