Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
92.00% covered (success)
92.00%
23 / 25
66.67% covered (warning)
66.67%
2 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
SignatureStampPreviewController
92.00% covered (success)
92.00%
23 / 25
66.67% covered (warning)
66.67%
2 / 3
6.02
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 previewPdf
90.91% covered (success)
90.91%
20 / 22
0.00% covered (danger)
0.00%
0 / 1
3.01
 canEditSignatureStampPolicy
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3declare(strict_types=1);
4/**
5 * SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
6 * SPDX-License-Identifier: AGPL-3.0-or-later
7 */
8
9namespace OCA\Libresign\Controller;
10
11use OCA\Libresign\AppInfo\Application;
12use OCA\Libresign\Service\Policy\PolicyService;
13use OCA\Libresign\Service\Policy\Provider\SignatureText\SignatureTextPolicy;
14use OCA\Libresign\Service\Policy\Provider\SignatureText\SignatureTextPolicyValue;
15use OCA\Libresign\Service\SignatureStampPreview\SignatureStampPreviewNativeService;
16use OCA\Libresign\Service\SignerElementsService;
17use OCP\AppFramework\Http;
18use OCP\AppFramework\Http\Attribute\ApiRoute;
19use OCP\AppFramework\Http\Attribute\NoAdminRequired;
20use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
21use OCP\AppFramework\Http\DataDownloadResponse;
22use OCP\AppFramework\Http\DataResponse;
23use OCP\IRequest;
24
25/**
26 * @psalm-import-type LibresignErrorResponse from \OCA\Libresign\ResponseDefinitions
27 */
28final class SignatureStampPreviewController extends AEnvironmentAwareController {
29    public function __construct(
30        IRequest $request,
31        private SignatureStampPreviewNativeService $signatureStampPreviewNativeService,
32        private PolicyService $policyService,
33    ) {
34        parent::__construct(Application::APP_ID, $request);
35    }
36
37    /**
38     * Render a preview PDF of the signature stamp with the provided configuration
39     *
40     * @param string $template Signature text template (Twig syntax)
41     * @param float $templateFontSize Font size for template text in pt
42     * @param float $signatureFontSize Font size for signer name in pt
43     * @param float $signatureWidth Stamp width in mm
44     * @param float $signatureHeight Stamp height in mm
45     * @param string $renderMode Render mode: default, text, graphic, description_only
46     * @param string $backgroundType Background: default, custom, deleted
47     *
48     * @return DataDownloadResponse<Http::STATUS_OK, 'application/pdf', array{}>|DataResponse<Http::STATUS_FORBIDDEN|Http::STATUS_UNPROCESSABLE_ENTITY, LibresignErrorResponse, array{}>
49     *
50     * 200: Preview PDF
51     * 403: Forbidden
52     * 422: Rendering error
53     */
54    #[NoAdminRequired]
55    #[NoCSRFRequired]
56    #[ApiRoute(verb: 'POST', url: '/api/{apiVersion}/signature-stamp/preview-pdf', requirements: ['apiVersion' => '(v1)'])]
57    public function previewPdf(
58        string $template = '',
59        ?float $templateFontSize = null,
60        ?float $signatureFontSize = null,
61        ?float $signatureWidth = null,
62        ?float $signatureHeight = null,
63        ?string $renderMode = null,
64        ?string $backgroundType = null,
65    ): DataDownloadResponse|DataResponse {
66        $templateFontSize ??= SignatureTextPolicyValue::DEFAULT_TEMPLATE_FONT_SIZE;
67        $signatureFontSize ??= SignatureTextPolicyValue::DEFAULT_SIGNATURE_FONT_SIZE;
68        $signatureWidth ??= SignatureTextPolicyValue::DEFAULT_SIGNATURE_WIDTH;
69        $signatureHeight ??= SignatureTextPolicyValue::DEFAULT_SIGNATURE_HEIGHT;
70        $renderMode ??= SignerElementsService::RENDER_MODE_GRAPHIC_AND_DESCRIPTION;
71        $backgroundType ??= 'default';
72
73        if (!$this->canEditSignatureStampPolicy()) {
74            return new DataResponse([
75                'error' => 'Signature stamp preview is only available for users who can edit policies.',
76            ], Http::STATUS_FORBIDDEN);
77        }
78
79        try {
80            $pdf = $this->signatureStampPreviewNativeService->renderPreviewPdf(
81                template: $template,
82                templateFontSize: $templateFontSize,
83                signatureFontSize: $signatureFontSize,
84                signatureWidth: $signatureWidth,
85                signatureHeight: $signatureHeight,
86                renderMode: $renderMode,
87                backgroundType: $backgroundType,
88            );
89        } catch (\Exception $e) {
90            return new DataResponse(['error' => $e->getMessage()], Http::STATUS_UNPROCESSABLE_ENTITY);
91        }
92
93        return new DataDownloadResponse($pdf, 'stamp-preview.pdf', 'application/pdf');
94    }
95
96    private function canEditSignatureStampPolicy(): bool {
97        $policy = $this->policyService->resolve(SignatureTextPolicy::KEY);
98
99        return $policy->isVisible() && $policy->isEditableByCurrentActor();
100    }
101}