Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
85.94% covered (warning)
85.94%
55 / 64
72.73% covered (warning)
72.73%
8 / 11
CRAP
0.00% covered (danger)
0.00%
0 / 1
FooterService
85.94% covered (warning)
85.94%
55 / 64
72.73% covered (warning)
72.73%
8 / 11
21.11
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
 isDefaultTemplate
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getTemplate
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getDefaultTemplate
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getPreviewSettings
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 saveTemplate
89.47% covered (warning)
89.47%
17 / 19
0.00% covered (danger)
0.00%
0 / 1
5.03
 saveSystemFooterPolicy
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 getEffectiveFooterPolicy
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 renderPreviewPdf
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
3
 getTemplateVariablesMetadata
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isPreviewAllowed
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
4
1<?php
2
3declare(strict_types=1);
4/**
5 * SPDX-FileCopyrightText: 2025 LibreCode coop and contributors
6 * SPDX-License-Identifier: AGPL-3.0-or-later
7 */
8
9namespace OCA\Libresign\Service;
10
11use OCA\Libresign\Handler\FooterHandler;
12use OCA\Libresign\Service\Policy\PolicyService;
13use OCA\Libresign\Service\Policy\Provider\Footer\FooterPolicy;
14use OCA\Libresign\Service\Policy\Provider\Footer\FooterPolicyValue;
15
16class FooterService {
17    public function __construct(
18        private PolicyService $policyService,
19        private FooterHandler $footerHandler,
20    ) {
21    }
22
23    public function isDefaultTemplate(): bool {
24        $footerPolicy = $this->getEffectiveFooterPolicy();
25        return !$footerPolicy['customizeFooterTemplate'];
26    }
27
28    public function getTemplate(): string {
29        return $this->footerHandler->getTemplate();
30    }
31
32    public function getDefaultTemplate(): string {
33        return $this->footerHandler->getDefaultTemplate();
34    }
35
36    /** @return array{preview_width: int, preview_height: int, preview_zoom: int} */
37    public function getPreviewSettings(): array {
38        $footerPolicy = $this->getEffectiveFooterPolicy();
39
40        return [
41            'preview_width' => (int)$footerPolicy['previewWidth'],
42            'preview_height' => (int)$footerPolicy['previewHeight'],
43            'preview_zoom' => (int)$footerPolicy['previewZoom'],
44        ];
45    }
46
47    public function saveTemplate(string $template = '', ?int $previewWidth = null, ?int $previewHeight = null): void {
48        $defaultTemplate = $this->footerHandler->getDefaultTemplate();
49        $currentPolicy = $this->getEffectiveFooterPolicy();
50        $normalizedPolicy = FooterPolicyValue::normalize($currentPolicy);
51
52        if ($previewWidth !== null) {
53            $normalizedPolicy['previewWidth'] = $previewWidth;
54        }
55
56        if ($previewHeight !== null) {
57            $normalizedPolicy['previewHeight'] = $previewHeight;
58        }
59
60        if (empty($template)) {
61            $normalizedPolicy['customizeFooterTemplate'] = false;
62            $normalizedPolicy['footerTemplate'] = '';
63            $this->saveSystemFooterPolicy($normalizedPolicy);
64            return;
65        }
66
67        $isProvidedTemplateEqualsDefault = $template === $defaultTemplate;
68
69        if ($isProvidedTemplateEqualsDefault) {
70            $normalizedPolicy['customizeFooterTemplate'] = false;
71            $normalizedPolicy['footerTemplate'] = '';
72        } else {
73            $normalizedPolicy['customizeFooterTemplate'] = true;
74            $normalizedPolicy['footerTemplate'] = $template;
75        }
76
77        $this->saveSystemFooterPolicy($normalizedPolicy);
78    }
79
80    /** @param array{enabled: bool, writeQrcodeOnFooter: bool, validationSite: string, customizeFooterTemplate: bool, footerTemplate: string, previewWidth: int, previewHeight: int, previewZoom: int} $normalizedPolicy */
81    private function saveSystemFooterPolicy(array $normalizedPolicy): void {
82        $allowChildOverride = $this->policyService->getSystemPolicy(FooterPolicy::KEY)?->isAllowChildOverride() ?? false;
83        $this->policyService->saveSystem(
84            FooterPolicy::KEY,
85            FooterPolicyValue::encode($normalizedPolicy),
86            $allowChildOverride,
87        );
88    }
89
90    private function getEffectiveFooterPolicy(): array {
91        $policyJson = $this->footerHandler->getEffectiveFooterPolicyAsJson();
92        return FooterPolicyValue::normalize($policyJson, '');
93    }
94
95    public function renderPreviewPdf(string $template = '', int $width = 595, int $height = 50, ?bool $writeQrcodeOnFooter = null): string {
96        $previewUuid = sprintf(
97            'preview-%04x-%04x-%04x-%012x',
98            random_int(0, 0xffff),
99            random_int(0, 0xffff),
100            random_int(0, 0xffff),
101            random_int(0, 0xffffffffffff)
102        );
103
104        $handler = $this->footerHandler
105            ->setTemplateOverride($template !== '' ? $template : null)
106            ->setTemplateVar('uuid', $previewUuid)
107            ->setTemplateVar('signers', [
108                [
109                    'displayName' => 'Preview Signer',
110                    'signed' => date('c'),
111                ],
112            ]);
113
114        if ($writeQrcodeOnFooter !== null) {
115            $handler->setWriteQrcodeOnFooterOverride($writeQrcodeOnFooter);
116        }
117
118        return $handler->getFooter([['w' => $width, 'h' => $height]], true);
119    }
120
121    public function getTemplateVariablesMetadata(): array {
122        return $this->footerHandler->getTemplateVariablesMetadata();
123    }
124
125    public function isPreviewAllowed(): bool {
126        $footerPolicy = $this->getEffectiveFooterPolicy();
127        if (!$footerPolicy['enabled']) {
128            return false;
129        }
130
131        $policy = $this->policyService->resolve(FooterPolicy::KEY);
132        return $policy->isVisible()
133            && ($policy->isEditableByCurrentActor() || $policy->canUseAsRequestOverride());
134    }
135}