Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
92.68% covered (success)
92.68%
38 / 41
57.14% covered (warning)
57.14%
4 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
SignerGeolocationFilePolicyApplier
92.68% covered (success)
92.68%
38 / 41
57.14% covered (warning)
57.14%
4 / 7
15.09
0.00% covered (danger)
0.00%
0 / 1
 apply
87.50% covered (warning)
87.50%
7 / 8
0.00% covered (danger)
0.00%
0 / 1
3.02
 sync
93.33% covered (success)
93.33%
14 / 15
0.00% covered (danger)
0.00%
0 / 1
5.01
 supportsCoreFlowSync
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getOverrides
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 assertOverrideAllowed
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 storeSignerGeolocationPolicySnapshot
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 hasSnapshot
83.33% covered (warning)
83.33%
5 / 6
0.00% covered (danger)
0.00%
0 / 1
3.04
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\SignerGeolocation\FilePolicy;
10
11use OCA\Libresign\Db\File as FileEntity;
12use OCA\Libresign\Service\Policy\AbstractFilePolicyApplier;
13use OCA\Libresign\Service\Policy\Model\ResolvedPolicy;
14use OCA\Libresign\Service\Policy\Provider\SignerGeolocation\SignerGeolocationPolicy;
15use OCA\Libresign\Service\Policy\Provider\SignerGeolocation\SignerGeolocationPolicyValue;
16use OCP\IUser;
17
18class SignerGeolocationFilePolicyApplier extends AbstractFilePolicyApplier {
19
20    #[\Override]
21    public function apply(FileEntity $file, array $data): void {
22        $user = ($data['userManager'] ?? null) instanceof IUser ? $data['userManager'] : null;
23        $requestOverrides = $this->getOverrides($data);
24        $activeContext = $this->extractActiveContext($data);
25        $resolvedPolicy = $activeContext === null
26            ? $this->policyService->resolveForUser(SignerGeolocationPolicy::KEY, $user, $requestOverrides)
27            : $this->policyService->resolveForUser(SignerGeolocationPolicy::KEY, $user, $requestOverrides, $activeContext);
28        $this->assertOverrideAllowed($requestOverrides, $resolvedPolicy);
29        $this->storeSignerGeolocationPolicySnapshot($file, $resolvedPolicy);
30    }
31
32    #[\Override]
33    public function sync(FileEntity $file, array $data): void {
34        if ($this->hasSnapshot($file)) {
35            return;
36        }
37
38        if ($file->isEnvelope()) {
39            return;
40        }
41
42        $requestOverrides = $this->getOverrides($data);
43        $activeContext = $this->extractActiveContext($data);
44        $resolvedPolicy = $activeContext === null
45            ? $this->policyService->resolveForUserId(SignerGeolocationPolicy::KEY, $file->getUserId(), $requestOverrides)
46            : $this->policyService->resolveForUserId(SignerGeolocationPolicy::KEY, $file->getUserId(), $requestOverrides, $activeContext);
47        $this->assertOverrideAllowed($requestOverrides, $resolvedPolicy);
48        $metadataBeforeUpdate = $file->getMetadata() ?? [];
49        $this->storeSignerGeolocationPolicySnapshot($file, $resolvedPolicy);
50        $metadataChanged = ($file->getMetadata() ?? []) !== $metadataBeforeUpdate;
51
52        if ($metadataChanged) {
53            $this->fileService->update($file);
54        }
55    }
56
57    #[\Override]
58    public function supportsCoreFlowSync(): bool {
59        return true;
60    }
61
62    /** @return array<string, array{mode: string}> */
63    private function getOverrides(array $data): array {
64        return $this->extractSinglePolicyOverride(
65            $data,
66            SignerGeolocationPolicy::KEY,
67            static fn (mixed $value): array => SignerGeolocationPolicyValue::normalize($value),
68        );
69    }
70
71    /** @param array<string, mixed> $requestOverrides */
72    private function assertOverrideAllowed(array $requestOverrides, ResolvedPolicy $resolvedPolicy): void {
73        $this->assertRequestOverrideAllowed($requestOverrides, $resolvedPolicy, 'Signer geolocation flow override is blocked by %s.');
74    }
75
76    private function storeSignerGeolocationPolicySnapshot(FileEntity $file, ResolvedPolicy $resolvedPolicy): void {
77        parent::storePolicySnapshot(
78            $file,
79            $resolvedPolicy,
80            SignerGeolocationPolicyValue::normalize($resolvedPolicy->getEffectiveValue()),
81        );
82    }
83
84    private function hasSnapshot(FileEntity $file): bool {
85        $metadata = $file->getMetadata() ?? [];
86        $policySnapshot = $metadata['policy_snapshot'] ?? null;
87        if (!is_array($policySnapshot)) {
88            return false;
89        }
90
91        $entry = $policySnapshot[SignerGeolocationPolicy::KEY] ?? null;
92        return is_array($entry) && array_key_exists('effectiveValue', $entry);
93    }
94}