Skip to content

Commit

Permalink
Merge pull request #4624 from LibreSign/fix/use-entities-instead-of-c…
Browse files Browse the repository at this point in the history
…har-converting

fix: use entities instead of char convertoing
Signed-off-by: Vitor Mattos <vitor@php.rio>
  • Loading branch information
samuelsonbrito authored and vitormattos committed Feb 12, 2025
2 parents 8c1a06c + 1f7870f commit bc0444a
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 27 deletions.
15 changes: 10 additions & 5 deletions lib/Handler/FooterHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
use OCP\IL10N;
use OCP\ITempManager;
use OCP\IURLGenerator;
use OCP\L10N\IFactory;

class FooterHandler {
private QrCode $qrCode;
Expand All @@ -40,6 +41,7 @@ public function __construct(
private PdfParserService $pdfParserService,
private IURLGenerator $urlGenerator,
private IL10N $l10n,
private IFactory $l10nFactory,
private ITempManager $tempManager,
) {
}
Expand Down Expand Up @@ -70,6 +72,7 @@ public function getFooter(File $file, FileEntity $fileEntity): string {
$dimension['h'] * self::POINT_TO_MILIMETER,
],
]);
$pdf->SetDirectionality($this->templateVars['direction']);
}
$pdf->AddPage(
orientation: 'P',
Expand Down Expand Up @@ -108,11 +111,9 @@ public function setTemplateVar(string $name, mixed $value): self {
}

private function getTemplateVars(): array {
$this->templateVars['signedBy'] = iconv(
'UTF-8',
'windows-1252',
$this->appConfig->getValueString(Application::APP_ID, 'footer_signed_by', $this->l10n->t('Digital signed by LibreSign.'))
);
$this->templateVars['signedBy'] = $this->appConfig->getValueString(Application::APP_ID, 'footer_signed_by', $this->l10n->t('Digital signed by LibreSign.'));

$this->templateVars['direction'] = $this->l10nFactory->getLanguageDirection($this->l10n->getLanguageCode());

$this->templateVars['linkToSite'] = $this->appConfig->getValueString(Application::APP_ID, 'footer_link_to_site', 'https://libresign.coop');

Expand All @@ -130,6 +131,10 @@ private function getTemplateVars(): array {
$this->templateVars['validateIn'] = $this->l10n->t('Validate in %s.', ['%s']);
}

foreach ($this->templateVars as $key => $value) {
$this->templateVars[$key] = mb_convert_encoding($value, 'HTML-ENTITIES', 'UTF-8');
}

if ($this->appConfig->getValueBool(Application::APP_ID, 'write_qrcode_on_footer', true)) {
$this->templateVars['qrcode'] = $this->getQrCodeImageBase64($this->templateVars['validationSite']);
}
Expand Down
2 changes: 1 addition & 1 deletion lib/Handler/Templates/footer.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/

?>
<table style="width:100%;border:0;<?php if (empty($qrcode)) { ?>padding-left:15px;<?php } ?>font-size:8px;">
<table style="width:100%;border:0;<?php if (empty($qrcode)) { ?>padding-left:15px;<?php } ?>font-size:8px;" dir="<?= $direction; ?>">
<tr>
<?php if (!empty($qrcode)) { ?>
<td width="<?= $qrcodeSize; ?>px">
Expand Down
118 changes: 97 additions & 21 deletions tests/Unit/Handler/FooterHandlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@
use OCP\IL10N;
use OCP\ITempManager;
use OCP\IURLGenerator;
use OCP\L10N\IFactory;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\MockObject\MockObject;

final class FooterHandlerTest extends \OCA\Libresign\Tests\Unit\TestCase {
private IAppConfig $appConfig;
private PdfParserService&MockObject $pdfParserService;
private IURLGenerator&MockObject $urlGenerator;
private IL10N&MockObject $l10n;
private IL10N $l10n;
private IFactory $l10nFactory;
private ITempManager $tempManager;
private FooterHandler $footerHandler;
public function setUp(): void {
Expand All @@ -29,10 +31,7 @@ public function setUp(): void {
$this->urlGenerator = $this->createMock(IURLGenerator::class);
$this->tempManager = \OCP\Server::get(ITempManager::class);

$this->l10n = $this->createMock(IL10N::class);
$this->l10n
->method('t')
->will($this->returnArgument(0));
$this->l10nFactory = \OCP\Server::get(IFactory::class);
}

private function getClass(): FooterHandler {
Expand All @@ -41,6 +40,7 @@ private function getClass(): FooterHandler {
$this->pdfParserService,
$this->urlGenerator,
$this->l10n,
$this->l10nFactory,
$this->tempManager,
);
return $this->footerHandler;
Expand All @@ -55,7 +55,7 @@ public function testGetFooterWithoutValidationSite(): void {
}

#[DataProvider('dataGetFooterWithSuccess')]
public function testGetFooterWithSuccess(array $settings, array $expected): void {
public function testGetFooterWithSuccess(string $language, array $settings, array $expected): void {
foreach ($settings as $key => $value) {
switch (gettype($value)) {
case 'boolean':
Expand Down Expand Up @@ -85,11 +85,17 @@ public function testGetFooterWithSuccess(array $settings, array $expected): void
default => '',
};
});

$this->l10n = $this->l10nFactory->get(Application::APP_ID, $language);

$pdf = $this->getClass()
->setTemplateVar('test', 'fake value')
->getFooter($file, $libresignFile);
if ($settings['add_footer']) {
$actual = $this->extractPdfContent($pdf, array_keys($expected));
$actual = $this->extractPdfContent(
$pdf,
array_keys($expected),
$this->l10nFactory->getLanguageDirection($language)
);
if ($settings['write_qrcode_on_footer']) {
$this->assertNotEmpty($actual['qrcode'], 'Invalid qrcode content');
unset($actual['qrcode'], $expected['qrcode']);
Expand All @@ -101,11 +107,13 @@ public function testGetFooterWithSuccess(array $settings, array $expected): void
}

public static function dataGetFooterWithSuccess(): array {
return [
[
$data = [
'without_footer' => [
'en',
['add_footer' => false,], []
],
[
'en',
[
'add_footer' => true,
'validation_site' => 'http://test.coop',
Expand All @@ -114,11 +122,10 @@ public static function dataGetFooterWithSuccess(): array {
'footer_signed_by' => 'Digital signed by LibreSign.',
'footer_validate_in' => 'Validate in %s.',
'footer_template' => <<<'HTML'
<div style="font-size:8px;">
<div style="font-size:8px;" dir="<?= $direction ?>">
qrcodeSize:<?= $qrcodeSize ?><br />
signedBy:<?= $signedBy ?><br />
validateIn:<?= $validateIn ?><br />
test:<?= $test ?><br />
qrcode:<?= $qrcode ?>
</div>
HTML,
Expand All @@ -128,10 +135,10 @@ public static function dataGetFooterWithSuccess(): array {
'qrcodeSize' => '108',
'signedBy' => 'Digital signed by LibreSign.',
'validateIn' => 'Validate in %s.',
'test' => 'fake value',
]
],
[
'en' => [
'en',
[
'add_footer' => true,
'validation_site' => 'http://test.coop',
Expand All @@ -140,23 +147,87 @@ public static function dataGetFooterWithSuccess(): array {
'footer_signed_by' => 'Digital signed by LibreSign.',
'footer_validate_in' => 'Validate in %s.',
'footer_template' => <<<'HTML'
<div style="font-size:8px;">
<div style="font-size:8px;" dir="<?= $direction ?>">
signedBy:<?= $signedBy ?><br />
validateIn:<?= $validateIn ?><br />
test:<?= $test ?>
</div>
HTML,
],
[
'signedBy' => 'Digital signed by LibreSign.',
'validateIn' => 'Validate in %s.',
'test' => 'fake value',
]
]
],
'fr' => [
'fr',
[
'add_footer' => true,
'validation_site' => 'http://test.coop',
'write_qrcode_on_footer' => false,
'footer_link_to_site' => 'https://libresign.coop',
'footer_signed_by' => 'Signé numériquement avec LibreSign.',
'footer_validate_in' => 'Validate in %s',
'footer_template' => <<<'HTML'
<div style="font-size:8px;" dir="<?= $direction ?>">
signedBy:<?= $signedBy ?><br />
validateIn:<?= $validateIn ?><br />
</div>
HTML,
],
[
'signedBy' => 'Signé numériquement avec LibreSign.',
'validateIn' => 'Validate in %s',
]
],
'el' => [
'el',
[
'add_footer' => true,
'validation_site' => 'http://test.coop',
'write_qrcode_on_footer' => false,
'footer_link_to_site' => 'https://libresign.coop',
'footer_signed_by' => 'Το αρχείο υπάρχει',
'footer_validate_in' => 'Validate in %s.',
'footer_template' => <<<'HTML'
<div style="font-size:8px;" dir="<?= $direction ?>">
signedBy:<?= $signedBy ?><br />
validateIn:<?= $validateIn ?><br />
</div>
HTML,
],
[
'signedBy' => 'Το αρχείο υπάρχει',
'validateIn' => 'Validate in %s.',
]
],
'he' => [
'he',
[
'add_footer' => true,
'validation_site' => 'http://test.coop',
'write_qrcode_on_footer' => false,
'footer_link_to_site' => 'https://libresign.coop',
'footer_signed_by' => 'אין המלצות. נא להתחיל להקליד.',
'footer_validate_in' => 'אמת ב- %s.',
'footer_template' => <<<'HTML'
<div style="font-size:8px;" dir="<?= $direction ?>">
signedBy:<?= $signedBy ?><br />
validateIn:<?= $validateIn ?><br />
</div>
HTML,
],
[
'signedBy' => 'אין המלצות. נא להתחיל להקליד.',
'validateIn' => 'אמת ב- %s.',
]
],
];

// LTR langages was ignored at CI because the returned text is flipped by MPDF
return array_filter($data, fn ($key) => !in_array($key, ['he']), ARRAY_FILTER_USE_KEY);
}

private function extractPdfContent(string $content, array $keys): array {
private function extractPdfContent(string $content, array $keys, string $direction): array {
$this->assertNotEmpty($content, 'Empty PDF file');
$this->assertNotEmpty($keys, 'Is necessary to send a not empty array of fields to search at PDF file');
$parser = new \Smalot\PdfParser\Parser();
Expand All @@ -166,8 +237,13 @@ private function extractPdfContent(string $content, array $keys): array {
$content = explode("\n", $text);
$this->assertNotEmpty($content, 'PDF without any row');
$content = array_map(fn ($row) => str_getcsv($row, ':'), $content);
$content = array_filter($content, fn ($row) => in_array($row[0], $keys));

// Necessary flip key/value when the language is LTR
$columnKey = $direction === 'rtl' ? 1 : 0;
$columnValue = $direction === 'rtl' ? 0 : 1;

$content = array_filter($content, fn ($row) => in_array($row[$columnKey], $keys));
$this->assertNotEmpty($content, 'Fields not found at PDF file');
return array_column($content, 1, 0);
return array_column($content, $columnValue, $columnKey);
}
}

0 comments on commit bc0444a

Please sign in to comment.