Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
91.18% covered (success)
91.18%
62 / 68
60.00% covered (warning)
60.00%
6 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
FooterPolicyValue
91.18% covered (success)
91.18%
62 / 68
60.00% covered (warning)
60.00%
6 / 10
28.54
0.00% covered (danger)
0.00%
0 / 1
 defaults
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
1
 normalize
96.15% covered (success)
96.15%
25 / 26
0.00% covered (danger)
0.00%
0 / 1
7
 encode
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isEnabled
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isQrCodeEnabled
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 getSnapshotEffectiveValue
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
4
 toBool
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
4.05
 toString
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 toTemplateString
40.00% covered (danger)
40.00%
2 / 5
0.00% covered (danger)
0.00%
0 / 1
4.94
 toInt
80.00% covered (warning)
80.00%
4 / 5
0.00% covered (danger)
0.00%
0 / 1
3.07
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\Service\Policy\Provider\Footer;
10
11use OCA\Libresign\Db\File as FileEntity;
12
13final class FooterPolicyValue {
14    /** @return array{enabled: bool, writeQrcodeOnFooter: bool, validationSite: string, customizeFooterTemplate: bool, footerTemplate: string, previewWidth: int, previewHeight: int, previewZoom: int} */
15    public static function defaults(string $defaultTemplate = ''): array {
16        return [
17            'enabled' => true,
18            'writeQrcodeOnFooter' => true,
19            'validationSite' => '',
20            'customizeFooterTemplate' => false,
21            'footerTemplate' => $defaultTemplate,
22            'previewWidth' => 595,
23            'previewHeight' => 100,
24            'previewZoom' => 100,
25        ];
26    }
27
28    /** @return array{enabled: bool, writeQrcodeOnFooter: bool, validationSite: string, customizeFooterTemplate: bool, footerTemplate: string, previewWidth: int, previewHeight: int, previewZoom: int} */
29    public static function normalize(mixed $rawValue, string $defaultTemplate = ''): array {
30        $defaults = self::defaults($defaultTemplate);
31
32        if (is_array($rawValue)) {
33            $normalized = [
34                'enabled' => self::toBool($rawValue['enabled'] ?? $rawValue['addFooter'] ?? $defaults['enabled']),
35                'writeQrcodeOnFooter' => self::toBool($rawValue['writeQrcodeOnFooter'] ?? $rawValue['write_qrcode_on_footer'] ?? $defaults['writeQrcodeOnFooter']),
36                'validationSite' => self::toString($rawValue['validationSite'] ?? $rawValue['validation_site'] ?? $defaults['validationSite']),
37                'customizeFooterTemplate' => self::toBool($rawValue['customizeFooterTemplate'] ?? $rawValue['customize_footer_template'] ?? $defaults['customizeFooterTemplate']),
38                'footerTemplate' => self::toTemplateString($rawValue['footerTemplate'] ?? $rawValue['footer_template'] ?? $defaults['footerTemplate']),
39                'previewWidth' => self::toInt($rawValue['previewWidth'] ?? $rawValue['preview_width'] ?? null, $defaults['previewWidth']),
40                'previewHeight' => self::toInt($rawValue['previewHeight'] ?? $rawValue['preview_height'] ?? null, $defaults['previewHeight']),
41                'previewZoom' => self::toInt($rawValue['previewZoom'] ?? $rawValue['preview_zoom'] ?? null, $defaults['previewZoom']),
42            ];
43
44            return $normalized;
45        }
46
47        if (is_bool($rawValue) || is_int($rawValue)) {
48            $defaults['enabled'] = self::toBool($rawValue);
49            return $defaults;
50        }
51
52        if (is_string($rawValue)) {
53            $trimmedValue = trim($rawValue);
54            if ($trimmedValue === '') {
55                return $defaults;
56            }
57
58            $decoded = json_decode($trimmedValue, true);
59            if (is_array($decoded)) {
60                return self::normalize($decoded, $defaultTemplate);
61            }
62
63            $defaults['enabled'] = self::toBool($trimmedValue);
64            return $defaults;
65        }
66
67        return $defaults;
68    }
69
70    public static function encode(array $value, string $defaultTemplate = ''): string {
71        return (string)json_encode(self::normalize($value, $defaultTemplate), JSON_UNESCAPED_SLASHES);
72    }
73
74    public static function isEnabled(mixed $rawValue): bool {
75        return self::normalize($rawValue)['enabled'];
76    }
77
78    public static function isQrCodeEnabled(mixed $rawValue): bool {
79        $normalized = self::normalize($rawValue);
80        return $normalized['enabled'] && $normalized['writeQrcodeOnFooter'];
81    }
82
83    public static function getSnapshotEffectiveValue(FileEntity $file): ?string {
84        $metadata = $file->getMetadata() ?? [];
85        $policySnapshot = $metadata['policy_snapshot'] ?? null;
86        if (!is_array($policySnapshot)) {
87            return null;
88        }
89
90        $effectiveValue = $policySnapshot[FooterPolicy::KEY]['effectiveValue'] ?? null;
91        if (!is_string($effectiveValue) || trim($effectiveValue) === '') {
92            return null;
93        }
94
95        return $effectiveValue;
96    }
97
98    private static function toBool(mixed $rawValue): bool {
99        if (is_bool($rawValue)) {
100            return $rawValue;
101        }
102
103        if (is_int($rawValue)) {
104            return $rawValue === 1;
105        }
106
107        if (is_string($rawValue)) {
108            return in_array(strtolower(trim($rawValue)), ['1', 'true', 'yes', 'on'], true);
109        }
110
111        return (bool)$rawValue;
112    }
113
114    private static function toString(mixed $rawValue): string {
115        if (!is_scalar($rawValue)) {
116            return '';
117        }
118
119        return trim((string)$rawValue);
120    }
121
122    private static function toTemplateString(mixed $rawValue): string {
123        if (is_string($rawValue)) {
124            return $rawValue;
125        }
126
127        if (is_scalar($rawValue)) {
128            return (string)$rawValue;
129        }
130
131        return '';
132    }
133
134    private static function toInt(mixed $rawValue, int $fallback): int {
135        if (is_int($rawValue)) {
136            return $rawValue;
137        }
138
139        if (is_numeric($rawValue)) {
140            return (int)$rawValue;
141        }
142
143        return $fallback;
144    }
145}