mirror of
https://github.com/LibreSign/libresign.git
synced 2025-12-18 05:20:45 +01:00
feat: Admin frontend of custom signature template
Signed-off-by: Vitor Mattos <vitor@php.rio>
This commit is contained in:
parent
e2c6debad2
commit
dab0ea499f
15 changed files with 1011 additions and 120 deletions
|
|
@ -2,13 +2,13 @@
|
|||
"require": {
|
||||
"endroid/qr-code": "^5.0",
|
||||
"jsignpdf/jsignpdf-php": "^1.2",
|
||||
"league/plates": "^3.5",
|
||||
"libresign/whatosami": "^0.0.2",
|
||||
"mikehaertl/php-pdftk": "^0.13.0",
|
||||
"mpdf/mpdf": "^8.2",
|
||||
"pagerfanta/pagerfanta": "^4.5",
|
||||
"phpseclib/phpseclib": "^3.0",
|
||||
"smalot/pdfparser": "^2.4",
|
||||
"twig/twig": "^3.20",
|
||||
"wobeto/email-blur": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
|
|
|
|||
224
composer.lock
generated
224
composer.lock
generated
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "fa70120a807fdc1e2baca77ca52aebf5",
|
||||
"content-hash": "a7c0ec19a821254f3138366739329b9f",
|
||||
"packages": [
|
||||
{
|
||||
"name": "bacon/bacon-qr-code",
|
||||
|
|
@ -235,70 +235,6 @@
|
|||
},
|
||||
"time": "2024-12-12T16:47:19+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/plates",
|
||||
"version": "v3.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/plates.git",
|
||||
"reference": "12ee65166adbc6fb5916fb80b0c0758e49a2d996"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/plates/zipball/12ee65166adbc6fb5916fb80b0c0758e49a2d996",
|
||||
"reference": "12ee65166adbc6fb5916fb80b0c0758e49a2d996",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mikey179/vfsstream": "^1.6",
|
||||
"phpunit/phpunit": "^11.4",
|
||||
"squizlabs/php_codesniffer": "^3.5"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"League\\Plates\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jonathan Reinink",
|
||||
"email": "jonathan@reinink.ca",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "RJ Garcia",
|
||||
"email": "ragboyjr@icloud.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Plates, the native PHP template system that's fast, easy to use and easy to extend.",
|
||||
"homepage": "https://platesphp.com",
|
||||
"keywords": [
|
||||
"league",
|
||||
"package",
|
||||
"templates",
|
||||
"templating",
|
||||
"views"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/thephpleague/plates/issues",
|
||||
"source": "https://github.com/thephpleague/plates/tree/v3.6.0"
|
||||
},
|
||||
"time": "2024-11-02T15:03:35+00:00"
|
||||
},
|
||||
{
|
||||
"name": "libresign/whatosami",
|
||||
"version": "0.0.2",
|
||||
|
|
@ -1345,6 +1281,85 @@
|
|||
],
|
||||
"time": "2024-09-25T14:20:29+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
"version": "v1.31.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
|
||||
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"provide": {
|
||||
"ext-ctype": "*"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-ctype": "For best performance"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"thanks": {
|
||||
"url": "https://github.com/symfony/polyfill",
|
||||
"name": "symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Ctype\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Gert de Pagter",
|
||||
"email": "BackEndTea@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill for ctype functions",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"ctype",
|
||||
"polyfill",
|
||||
"portable"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-09-09T11:45:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.31.0",
|
||||
|
|
@ -1425,6 +1440,85 @@
|
|||
],
|
||||
"time": "2024-09-09T11:45:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "twig/twig",
|
||||
"version": "v3.20.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/twigphp/Twig.git",
|
||||
"reference": "3468920399451a384bef53cf7996965f7cd40183"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/3468920399451a384bef53cf7996965f7cd40183",
|
||||
"reference": "3468920399451a384bef53cf7996965f7cd40183",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.1.0",
|
||||
"symfony/deprecation-contracts": "^2.5|^3",
|
||||
"symfony/polyfill-ctype": "^1.8",
|
||||
"symfony/polyfill-mbstring": "^1.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^2.0",
|
||||
"psr/container": "^1.0|^2.0",
|
||||
"symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/Resources/core.php",
|
||||
"src/Resources/debug.php",
|
||||
"src/Resources/escaper.php",
|
||||
"src/Resources/string_loader.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Twig\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com",
|
||||
"homepage": "http://fabien.potencier.org",
|
||||
"role": "Lead Developer"
|
||||
},
|
||||
{
|
||||
"name": "Twig Team",
|
||||
"role": "Contributors"
|
||||
},
|
||||
{
|
||||
"name": "Armin Ronacher",
|
||||
"email": "armin.ronacher@active-4.com",
|
||||
"role": "Project Founder"
|
||||
}
|
||||
],
|
||||
"description": "Twig, the flexible, fast, and secure template language for PHP",
|
||||
"homepage": "https://twig.symfony.com",
|
||||
"keywords": [
|
||||
"templating"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/twigphp/Twig/issues",
|
||||
"source": "https://github.com/twigphp/Twig/tree/v3.20.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/twig/twig",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-02-13T08:34:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "wobeto/email-blur",
|
||||
"version": "1.0.0",
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ use OCA\Libresign\ResponseDefinitions;
|
|||
use OCA\Libresign\Service\Install\ConfigureCheckService;
|
||||
use OCA\Libresign\Service\Install\InstallService;
|
||||
use OCA\Libresign\Service\SignatureBackgroundService;
|
||||
use OCA\Libresign\Service\SignatureTextService;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\AppFramework\Http\Attribute\ApiRoute;
|
||||
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
|
||||
|
|
@ -45,6 +46,7 @@ class AdminController extends AEnvironmentAwareController {
|
|||
private InstallService $installService,
|
||||
private CertificateEngineHandler $certificateEngineHandler,
|
||||
private IEventSourceFactory $eventSourceFactory,
|
||||
private SignatureTextService $signatureTextService,
|
||||
private IL10N $l10n,
|
||||
protected ISession $session,
|
||||
private SignatureBackgroundService $signatureBackgroundService,
|
||||
|
|
@ -380,4 +382,44 @@ class AdminController extends AEnvironmentAwareController {
|
|||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save signature text service
|
||||
*
|
||||
* @param string $template Template to signature text
|
||||
* @return DataResponse<Http::STATUS_OK, array{parsed: string}, array{}>
|
||||
*
|
||||
* 200: OK
|
||||
*/
|
||||
#[ApiRoute(verb: 'POST', url: '/api/{apiVersion}/admin/signature-text', requirements: ['apiVersion' => '(v1)'])]
|
||||
public function signatureTextSave(string $template): DataResponse {
|
||||
$parsed = $this->signatureTextService->save($template);
|
||||
return new DataResponse(
|
||||
[
|
||||
'parsed' => $parsed,
|
||||
],
|
||||
Http::STATUS_OK
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get parsed signature text service
|
||||
*
|
||||
* @param string $template Template to signature text
|
||||
* @param string $context Context for parsing the template
|
||||
* @return DataResponse<Http::STATUS_OK, array{parsed: string}, array{}>
|
||||
*
|
||||
* 200: OK
|
||||
*/
|
||||
#[ApiRoute(verb: 'GET', url: '/api/{apiVersion}/admin/signature-text', requirements: ['apiVersion' => '(v1)'])]
|
||||
public function signatureTextGet(string $template = '', string $context = ''): DataResponse {
|
||||
$context = json_decode($context, true) ?? [];
|
||||
$parsed = $this->signatureTextService->parse($template, $context);
|
||||
return new DataResponse(
|
||||
[
|
||||
'parsed' => $parsed
|
||||
],
|
||||
Http::STATUS_OK
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ use Endroid\QrCode\ErrorCorrectionLevel;
|
|||
use Endroid\QrCode\QrCode;
|
||||
use Endroid\QrCode\RoundBlockSizeMode;
|
||||
use Endroid\QrCode\Writer\PngWriter;
|
||||
use League\Plates\Engine;
|
||||
use Mpdf\Mpdf;
|
||||
use OCA\Libresign\AppInfo\Application;
|
||||
use OCA\Libresign\Db\File as FileEntity;
|
||||
|
|
@ -28,6 +27,9 @@ use OCP\IL10N;
|
|||
use OCP\ITempManager;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\L10N\IFactory;
|
||||
use Twig\Environment;
|
||||
use Twig\Error\SyntaxError;
|
||||
use Twig\Loader\FilesystemLoader;
|
||||
|
||||
class FooterHandler {
|
||||
private QrCode $qrCode;
|
||||
|
|
@ -100,10 +102,16 @@ class FooterHandler {
|
|||
}
|
||||
|
||||
private function getRenderedHtmlFooter(): string {
|
||||
$templateFile = $this->getTemplateFile();
|
||||
$pathInfo = pathinfo($templateFile);
|
||||
$templates = new Engine($pathInfo['dirname']);
|
||||
return $templates->render($pathInfo['filename'], $this->getTemplateVars());
|
||||
try {
|
||||
$twigEnvironment = new Environment(
|
||||
new FilesystemLoader(),
|
||||
);
|
||||
return $twigEnvironment
|
||||
->createTemplate($this->getTemplate())
|
||||
->render($this->getTemplateVars());
|
||||
} catch (SyntaxError $e) {
|
||||
throw new LibresignException($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function setTemplateVar(string $name, mixed $value): self {
|
||||
|
|
@ -145,17 +153,12 @@ class FooterHandler {
|
|||
return $this->templateVars;
|
||||
}
|
||||
|
||||
private function getTemplateFile(): string {
|
||||
private function getTemplate(): string {
|
||||
$footerTemplate = $this->appConfig->getValueString(Application::APP_ID, 'footer_template', '');
|
||||
if ($footerTemplate) {
|
||||
$tempFile = $this->tempManager->getTemporaryFile('footerTemplate.php');
|
||||
if (!$tempFile) {
|
||||
throw new LibresignException('Failure to create temporary file footerTemplate.php');
|
||||
}
|
||||
file_put_contents($tempFile, $footerTemplate);
|
||||
return $tempFile;
|
||||
return $footerTemplate;
|
||||
}
|
||||
return __DIR__ . '/Templates/footer.php';
|
||||
return (string) file_get_contents(__DIR__ . '/Templates/footer.teig');
|
||||
}
|
||||
|
||||
private function getQrCodeImageBase64(string $text): string {
|
||||
|
|
|
|||
|
|
@ -1,23 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2024 LibreCode coop and contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
?>
|
||||
<table style="width:100%;border:0;<?php if (empty($qrcode)) { ?>padding-left:15px;<?php } ?>font-size:8px;">
|
||||
<tr>
|
||||
<?php if (!empty($qrcode)) { ?>
|
||||
<td width="<?= $qrcodeSize; ?>px">
|
||||
<img src="data:image/png;base64,<?= $qrcode; ?>" style="width:<?= $qrcodeSize; ?>px"/>
|
||||
</td>
|
||||
<?php } ?>
|
||||
<td style="vertical-align: bottom;padding: 0px 0px 15px 0px;line-height:1.5em;">
|
||||
<a href="<?= $linkToSite; ?>" style="text-decoration: none;color:unset;"><?= $signedBy; ?></a>
|
||||
<?php if ($validateIn) { ?>
|
||||
<br>
|
||||
<a href="<?=$validationSite; ?>" style="text-decoration: none;color:unset;"><?= str_replace('%s', $validationSite, $validateIn); ?></a>
|
||||
<?php } ?>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
23
lib/Handler/Templates/footer.twig
Normal file
23
lib/Handler/Templates/footer.twig
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
{#
|
||||
SPDX-FileCopyrightText: 2024 LibreCode coop and contributors
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
#}
|
||||
<table style="width:100%; border:0; {% if not qrcode %}padding-left:15px;{% endif %} font-size:8px;">
|
||||
<tr>
|
||||
{% if qrcode %}
|
||||
<td width="{{ qrcodeSize }}px">
|
||||
<img src="data:image/png;base64,{{ qrcode }}" style="width:{{ qrcodeSize }}px" />
|
||||
</td>
|
||||
{% endif %}
|
||||
<td style="vertical-align: bottom; padding: 0px 0px 15px 0px; line-height:1.5em;">
|
||||
<a href="{{ linkToSite }}" style="text-decoration: none; color: unset;">{{ signedBy }}</a>
|
||||
{% if validateIn %}
|
||||
<br>
|
||||
<a href="{{ validationSite }}"
|
||||
style="text-decoration: none; color: unset;">
|
||||
{{ validateIn|replace({'%s': validationSite}) }}
|
||||
</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
51
lib/Service/SignatureTextService.php
Normal file
51
lib/Service/SignatureTextService.php
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2025 LibreCode coop and contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace OCA\Libresign\Service;
|
||||
|
||||
use DateTimeInterface;
|
||||
use OCP\AppFramework\Services\IAppConfig;
|
||||
use Sabre\DAV\UUIDUtil;
|
||||
use Twig\Environment;
|
||||
use Twig\Error\SyntaxError;
|
||||
use Twig\Loader\FilesystemLoader;
|
||||
|
||||
class SignatureTextService {
|
||||
public function __construct(
|
||||
private IAppConfig $appConfig,
|
||||
) {
|
||||
}
|
||||
public function save(string $template): string {
|
||||
$this->appConfig->setAppValueString('signature_text_template', $template);
|
||||
return $this->parse($template);
|
||||
}
|
||||
|
||||
public function parse(string $template, array $context = []): string {
|
||||
if (empty($template)) {
|
||||
$template = $this->appConfig->getAppValueString('signature_text_template');
|
||||
}
|
||||
if (empty($context)) {
|
||||
$context = [
|
||||
'SignerName' => 'John Doe',
|
||||
'DocumentUUID' => UUIDUtil::getUUID(),
|
||||
'CommonName' => 'Acme Cooperative',
|
||||
'SignatureDate' => (new \DateTime())->format(DateTimeInterface::ATOM)
|
||||
];
|
||||
}
|
||||
try {
|
||||
$twigEnvironment = new Environment(
|
||||
new FilesystemLoader(),
|
||||
);
|
||||
return $twigEnvironment
|
||||
->createTemplate($template)
|
||||
->render($context);
|
||||
} catch (SyntaxError $e) {
|
||||
return (string) preg_replace('/in "[^"]+" at line \d+/', '', $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1058,6 +1058,205 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/ocs/v2.php/apps/libresign/api/{apiVersion}/admin/signature-text": {
|
||||
"post": {
|
||||
"operationId": "admin-signature-text-save",
|
||||
"summary": "Save signature text service",
|
||||
"description": "This endpoint requires admin access",
|
||||
"tags": [
|
||||
"admin"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"bearer_auth": []
|
||||
},
|
||||
{
|
||||
"basic_auth": []
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"template"
|
||||
],
|
||||
"properties": {
|
||||
"template": {
|
||||
"type": "string",
|
||||
"description": "Template to signature text"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "apiVersion",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"v1"
|
||||
],
|
||||
"default": "v1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "OCS-APIRequest",
|
||||
"in": "header",
|
||||
"description": "Required to be true for the API request to pass",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"parsed"
|
||||
],
|
||||
"properties": {
|
||||
"parsed": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"get": {
|
||||
"operationId": "admin-signature-text-get",
|
||||
"summary": "Get parsed signature text service",
|
||||
"description": "This endpoint requires admin access",
|
||||
"tags": [
|
||||
"admin"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"bearer_auth": []
|
||||
},
|
||||
{
|
||||
"basic_auth": []
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "apiVersion",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"v1"
|
||||
],
|
||||
"default": "v1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "template",
|
||||
"in": "query",
|
||||
"description": "Template to signature text",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"default": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "context",
|
||||
"in": "query",
|
||||
"description": "Context for parsing the template",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"default": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "OCS-APIRequest",
|
||||
"in": "header",
|
||||
"description": "Required to be true for the API request to pass",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"parsed"
|
||||
],
|
||||
"properties": {
|
||||
"parsed": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ocs/v2.php/apps/libresign/api/{apiVersion}/setting/has-root-cert": {
|
||||
"get": {
|
||||
"operationId": "setting-has-root-cert",
|
||||
|
|
|
|||
|
|
@ -8795,6 +8795,205 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/ocs/v2.php/apps/libresign/api/{apiVersion}/admin/signature-text": {
|
||||
"post": {
|
||||
"operationId": "admin-signature-text-save",
|
||||
"summary": "Save signature text service",
|
||||
"description": "This endpoint requires admin access",
|
||||
"tags": [
|
||||
"admin"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"bearer_auth": []
|
||||
},
|
||||
{
|
||||
"basic_auth": []
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"template"
|
||||
],
|
||||
"properties": {
|
||||
"template": {
|
||||
"type": "string",
|
||||
"description": "Template to signature text"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "apiVersion",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"v1"
|
||||
],
|
||||
"default": "v1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "OCS-APIRequest",
|
||||
"in": "header",
|
||||
"description": "Required to be true for the API request to pass",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"parsed"
|
||||
],
|
||||
"properties": {
|
||||
"parsed": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"get": {
|
||||
"operationId": "admin-signature-text-get",
|
||||
"summary": "Get parsed signature text service",
|
||||
"description": "This endpoint requires admin access",
|
||||
"tags": [
|
||||
"admin"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"bearer_auth": []
|
||||
},
|
||||
{
|
||||
"basic_auth": []
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "apiVersion",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"v1"
|
||||
],
|
||||
"default": "v1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "template",
|
||||
"in": "query",
|
||||
"description": "Template to signature text",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"default": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "context",
|
||||
"in": "query",
|
||||
"description": "Context for parsing the template",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"default": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "OCS-APIRequest",
|
||||
"in": "header",
|
||||
"description": "Required to be true for the API request to pass",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"parsed"
|
||||
],
|
||||
"properties": {
|
||||
"parsed": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ocs/v2.php/apps/libresign/api/{apiVersion}/setting/has-root-cert": {
|
||||
"get": {
|
||||
"operationId": "setting-has-root-cert",
|
||||
|
|
|
|||
|
|
@ -139,6 +139,30 @@ export type paths = {
|
|||
patch: operations["admin-signature-background-reset"];
|
||||
trace?: never;
|
||||
};
|
||||
"/ocs/v2.php/apps/libresign/api/{apiVersion}/admin/signature-text": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/**
|
||||
* Get parsed signature text service
|
||||
* @description This endpoint requires admin access
|
||||
*/
|
||||
get: operations["admin-signature-text-get"];
|
||||
put?: never;
|
||||
/**
|
||||
* Save signature text service
|
||||
* @description This endpoint requires admin access
|
||||
*/
|
||||
post: operations["admin-signature-text-save"];
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/ocs/v2.php/apps/libresign/api/{apiVersion}/setting/has-root-cert": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
|
|
@ -574,6 +598,82 @@ export interface operations {
|
|||
};
|
||||
};
|
||||
};
|
||||
"admin-signature-text-get": {
|
||||
parameters: {
|
||||
query?: {
|
||||
/** @description Template to signature text */
|
||||
template?: string;
|
||||
/** @description Context for parsing the template */
|
||||
context?: string;
|
||||
};
|
||||
header: {
|
||||
/** @description Required to be true for the API request to pass */
|
||||
"OCS-APIRequest": boolean;
|
||||
};
|
||||
path: {
|
||||
apiVersion: "v1";
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description OK */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": {
|
||||
ocs: {
|
||||
meta: components["schemas"]["OCSMeta"];
|
||||
data: {
|
||||
parsed: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
"admin-signature-text-save": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header: {
|
||||
/** @description Required to be true for the API request to pass */
|
||||
"OCS-APIRequest": boolean;
|
||||
};
|
||||
path: {
|
||||
apiVersion: "v1";
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": {
|
||||
/** @description Template to signature text */
|
||||
template: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description OK */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": {
|
||||
ocs: {
|
||||
meta: components["schemas"]["OCSMeta"];
|
||||
data: {
|
||||
parsed: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
"setting-has-root-cert": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
|
|
|
|||
|
|
@ -1049,6 +1049,30 @@ export type paths = {
|
|||
patch: operations["admin-signature-background-reset"];
|
||||
trace?: never;
|
||||
};
|
||||
"/ocs/v2.php/apps/libresign/api/{apiVersion}/admin/signature-text": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/**
|
||||
* Get parsed signature text service
|
||||
* @description This endpoint requires admin access
|
||||
*/
|
||||
get: operations["admin-signature-text-get"];
|
||||
put?: never;
|
||||
/**
|
||||
* Save signature text service
|
||||
* @description This endpoint requires admin access
|
||||
*/
|
||||
post: operations["admin-signature-text-save"];
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/ocs/v2.php/apps/libresign/api/{apiVersion}/setting/has-root-cert": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
|
|
@ -4573,6 +4597,82 @@ export interface operations {
|
|||
};
|
||||
};
|
||||
};
|
||||
"admin-signature-text-get": {
|
||||
parameters: {
|
||||
query?: {
|
||||
/** @description Template to signature text */
|
||||
template?: string;
|
||||
/** @description Context for parsing the template */
|
||||
context?: string;
|
||||
};
|
||||
header: {
|
||||
/** @description Required to be true for the API request to pass */
|
||||
"OCS-APIRequest": boolean;
|
||||
};
|
||||
path: {
|
||||
apiVersion: "v1";
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description OK */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": {
|
||||
ocs: {
|
||||
meta: components["schemas"]["OCSMeta"];
|
||||
data: {
|
||||
parsed: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
"admin-signature-text-save": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header: {
|
||||
/** @description Required to be true for the API request to pass */
|
||||
"OCS-APIRequest": boolean;
|
||||
};
|
||||
path: {
|
||||
apiVersion: "v1";
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": {
|
||||
/** @description Template to signature text */
|
||||
template: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description OK */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": {
|
||||
ocs: {
|
||||
meta: components["schemas"]["OCSMeta"];
|
||||
data: {
|
||||
parsed: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
"setting-has-root-cert": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
<DefaultUserFolder />
|
||||
<SignatureHashAlgorithm />
|
||||
<SignatureBackground />
|
||||
<SignatureTextTemplate />
|
||||
</NcSettingsSection>
|
||||
</template>
|
||||
|
||||
|
|
@ -40,6 +41,7 @@ import RootCertificateCfssl from './RootCertificateCfssl.vue'
|
|||
import RootCertificateOpenSsl from './RootCertificateOpenSsl.vue'
|
||||
import SignatureBackground from './SignatureBackground.vue'
|
||||
import SignatureHashAlgorithm from './SignatureHashAlgorithm.vue'
|
||||
import SignatureTextTemplate from './SignatureTextTemplate.vue'
|
||||
import Validation from './Validation.vue'
|
||||
|
||||
export default {
|
||||
|
|
@ -61,6 +63,7 @@ export default {
|
|||
DefaultUserFolder,
|
||||
SignatureHashAlgorithm,
|
||||
SignatureBackground,
|
||||
SignatureTextTemplate,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
|
|||
95
src/views/Settings/SignatureTextTemplate.vue
Normal file
95
src/views/Settings/SignatureTextTemplate.vue
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
<!--
|
||||
- SPDX-FileCopyrightText: 2024 LibreCode coop and LibreCode contributors
|
||||
- SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-->
|
||||
<template>
|
||||
<NcSettingsSection :name="name" :description="description">
|
||||
<div class="content">
|
||||
<NcTextArea :value.sync="inputValue"
|
||||
:placeholder="t('libresign', 'Signature text template')"
|
||||
:success="showSuccess"
|
||||
resize="vertical"
|
||||
@keydown.enter="save"
|
||||
@blur="save" />
|
||||
<div class="text-pre-line">
|
||||
{{ parsed }}
|
||||
</div>
|
||||
</div>
|
||||
</NcSettingsSection>
|
||||
</template>
|
||||
<script>
|
||||
import debounce from 'debounce'
|
||||
|
||||
import axios from '@nextcloud/axios'
|
||||
import { translate as t } from '@nextcloud/l10n'
|
||||
import { generateOcsUrl } from '@nextcloud/router'
|
||||
|
||||
import NcSettingsSection from '@nextcloud/vue/components/NcSettingsSection'
|
||||
import NcTextArea from '@nextcloud/vue/components/NcTextArea'
|
||||
|
||||
export default {
|
||||
name: 'SignatureTextTemplate',
|
||||
components: {
|
||||
NcSettingsSection,
|
||||
NcTextArea,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
name: t('libresign', 'Signature text template'),
|
||||
description: t('libresign', 'This template will be mixed to signature.'),
|
||||
signatureTextTemplate: '',
|
||||
showSuccess: false,
|
||||
parsed: '',
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
inputValue: {
|
||||
get() {
|
||||
return this.signatureTextTemplate
|
||||
},
|
||||
set(value) {
|
||||
this.signatureTextTemplate = value.trim()
|
||||
this.debouncePropertyChange()
|
||||
},
|
||||
},
|
||||
debouncePropertyChange() {
|
||||
return debounce(async function() {
|
||||
await this.save()
|
||||
}, 1000)
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.getData()
|
||||
},
|
||||
methods: {
|
||||
async getData() {
|
||||
await axios.get(generateOcsUrl('/apps/provisioning_api/api/v1/config/apps/libresign/signature_text_template'))
|
||||
.then(({ data }) => {
|
||||
this.signatureTextTemplate = data.ocs.data.data
|
||||
return axios.get(generateOcsUrl('/apps/libresign/api/v1/admin/signature-text'))
|
||||
})
|
||||
.then(({ data }) => {
|
||||
this.parsed = data.ocs.data.parsed
|
||||
})
|
||||
},
|
||||
async save() {
|
||||
this.showSuccess = false
|
||||
await axios.post(generateOcsUrl('/apps/libresign/api/v1/admin/signature-text'), { template: this.signatureTextTemplate })
|
||||
.then(({ data }) => {
|
||||
this.parsed = data.ocs.data.parsed
|
||||
this.showSuccess = true
|
||||
setTimeout(() => { this.showSuccess = false }, 2000)
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.content{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.text-pre-line {
|
||||
white-space: pre-line;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -123,11 +123,11 @@ final class FooterHandlerTest extends \OCA\Libresign\Tests\Unit\TestCase {
|
|||
'footer_signed_by' => 'Digital signed by LibreSign.',
|
||||
'footer_validate_in' => 'Validate in %s.',
|
||||
'footer_template' => <<<'HTML'
|
||||
<div style="font-size:8px;" dir="<?= $direction ?>">
|
||||
qrcodeSize:<?= $qrcodeSize ?><br />
|
||||
signedBy:<?= $signedBy ?><br />
|
||||
validateIn:<?= $validateIn ?><br />
|
||||
qrcode:<?= $qrcode ?>
|
||||
<div style="font-size:8px;" dir="{{ direction }}">
|
||||
qrcodeSize:{{ qrcodeSize }}<br />
|
||||
signedBy:{{ signedBy|raw }}<br />
|
||||
validateIn:{{ validateIn }}<br />
|
||||
qrcode:{{ qrcode }}
|
||||
</div>
|
||||
HTML,
|
||||
],
|
||||
|
|
@ -148,9 +148,9 @@ final class FooterHandlerTest extends \OCA\Libresign\Tests\Unit\TestCase {
|
|||
'footer_signed_by' => 'Digital signed by LibreSign.',
|
||||
'footer_validate_in' => 'Validate in %s.',
|
||||
'footer_template' => <<<'HTML'
|
||||
<div style="font-size:8px;" dir="<?= $direction ?>">
|
||||
signedBy:<?= $signedBy ?><br />
|
||||
validateIn:<?= $validateIn ?><br />
|
||||
<div style="font-size:8px;" dir="{{ direction }}">
|
||||
signedBy:{{ signedBy|raw }}<br />
|
||||
validateIn:{{ validateIn }}<br />
|
||||
</div>
|
||||
HTML,
|
||||
],
|
||||
|
|
@ -169,9 +169,9 @@ final class FooterHandlerTest extends \OCA\Libresign\Tests\Unit\TestCase {
|
|||
'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 style="font-size:8px;" dir="{{ direction }}">
|
||||
signedBy:{{ signedBy|raw }}<br />
|
||||
validateIn:{{ validateIn }}<br />
|
||||
</div>
|
||||
HTML,
|
||||
],
|
||||
|
|
@ -190,9 +190,9 @@ final class FooterHandlerTest extends \OCA\Libresign\Tests\Unit\TestCase {
|
|||
'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 style="font-size:8px;" dir="{{ direction }}">
|
||||
signedBy:{{ signedBy|raw }}<br />
|
||||
validateIn:{{ validateIn }}<br />
|
||||
</div>
|
||||
HTML,
|
||||
],
|
||||
|
|
@ -211,9 +211,9 @@ final class FooterHandlerTest extends \OCA\Libresign\Tests\Unit\TestCase {
|
|||
'footer_signed_by' => 'אין המלצות. נא להתחיל להקליד.',
|
||||
'footer_validate_in' => 'אמת ב- %s.',
|
||||
'footer_template' => <<<'HTML'
|
||||
<div style="font-size:8px;" dir="<?= $direction ?>">
|
||||
signedBy:<?= $signedBy ?><br />
|
||||
validateIn:<?= $validateIn ?><br />
|
||||
<div style="font-size:8px;" dir="{{ direction }}">
|
||||
signedBy:{{ signedBy|raw }}<br />
|
||||
validateIn:{{ validateIn }}<br />
|
||||
</div>
|
||||
HTML,
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<files psalm-version="5.26.1@d747f6500b38ac4f7dfc5edbcae6e4b637d7add0">
|
||||
<files psalm-version="6.5.0@38fc8444edf0cebc9205296ee6e30e906ade783b">
|
||||
<file src="lib/AppInfo/Application.php">
|
||||
<InvalidArgument>
|
||||
<code><![CDATA[LoadAdditionalListener::class]]></code>
|
||||
|
|
@ -177,6 +177,11 @@
|
|||
<code><![CDATA[UUIDUtil]]></code>
|
||||
</UndefinedClass>
|
||||
</file>
|
||||
<file src="lib/Service/SignatureTextService.php">
|
||||
<UndefinedClass>
|
||||
<code><![CDATA[UUIDUtil]]></code>
|
||||
</UndefinedClass>
|
||||
</file>
|
||||
<file src="lib/Service/TFile.php">
|
||||
<UndefinedDocblockClass>
|
||||
<code><![CDATA[PdfTypeException]]></code>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue