1 | <?php |
||
2 | declare(strict_types=1); |
||
3 | /** |
||
4 | * Analytics |
||
5 | * |
||
6 | * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors |
||
7 | * SPDX-License-Identifier: AGPL-3.0-or-later |
||
8 | */ |
||
9 | |||
10 | namespace OCA\Analytics\WhatsNew; |
||
11 | |||
12 | use OCP\AppFramework\Db\DoesNotExistException; |
||
0 ignored issues
–
show
|
|||
13 | use OCP\Http\Client\IClientService; |
||
0 ignored issues
–
show
The type
OCP\Http\Client\IClientService was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||
14 | use OCP\Http\Client\IResponse; |
||
0 ignored issues
–
show
The type
OCP\Http\Client\IResponse was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||
15 | use Psr\Log\LoggerInterface; |
||
0 ignored issues
–
show
The type
Psr\Log\LoggerInterface was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||
16 | |||
17 | class WhatsNewCheck |
||
18 | { |
||
19 | public const RESPONSE_NO_CONTENT = 0; |
||
20 | public const RESPONSE_USE_CACHE = 1; |
||
21 | public const RESPONSE_HAS_CONTENT = 2; |
||
22 | /** @var IClientService */ |
||
23 | protected $clientService; |
||
24 | /** @var WhatsNewMapper */ |
||
25 | private $mapper; |
||
26 | /** @var ILogger */ |
||
0 ignored issues
–
show
The type
OCA\Analytics\WhatsNew\ILogger was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||
27 | private $logger; |
||
28 | |||
29 | public function __construct(IClientService $clientService, WhatsNewMapper $mapper, LoggerInterface $logger) |
||
30 | { |
||
31 | $this->clientService = $clientService; |
||
32 | $this->mapper = $mapper; |
||
33 | $this->logger = $logger; |
||
34 | } |
||
35 | |||
36 | /** |
||
37 | * @param string $version |
||
38 | * @return array |
||
39 | * @throws DoesNotExistException |
||
40 | */ |
||
41 | public function getChangesForVersion(string $version): array |
||
42 | { |
||
43 | $version = $this->normalizeVersion($version); |
||
44 | $changesInfo = $this->mapper->getChanges($version); |
||
45 | $changesData = json_decode($changesInfo->getData(), true); |
||
46 | if (empty($changesData)) { |
||
47 | throw new DoesNotExistException('Unable to decode changes info'); |
||
48 | } |
||
49 | return $changesData; |
||
50 | } |
||
51 | |||
52 | /** |
||
53 | * returns a x.y.z form of the provided version. Extra numbers will be |
||
54 | * omitted, missing ones added as zeros. |
||
55 | */ |
||
56 | public function normalizeVersion(string $version): string |
||
57 | { |
||
58 | $versionNumbers = array_slice(explode('.', $version), 0, 3); |
||
59 | $versionNumbers[0] = $versionNumbers[0] ?: '0'; // deal with empty input |
||
60 | while (count($versionNumbers) < 3) { |
||
61 | // changelog server expects x.y.z, pad 0 if it is too short |
||
62 | $versionNumbers[] = 0; |
||
63 | } |
||
64 | return implode('.', $versionNumbers); |
||
65 | } |
||
66 | |||
67 | /** |
||
68 | * @param string $uri |
||
69 | * @param string $version |
||
70 | * @return array |
||
71 | * @throws \Exception |
||
72 | */ |
||
73 | public function check(string $uri, string $version): array |
||
74 | { |
||
75 | try { |
||
76 | $version = $this->normalizeVersion($version); |
||
77 | $changesInfo = $this->mapper->getChanges($version); |
||
78 | if ($changesInfo->getLastCheck() + 1800 > time()) { |
||
79 | return json_decode($changesInfo->getData(), true); |
||
80 | } |
||
81 | } catch (DoesNotExistException $e) { |
||
82 | $changesInfo = new WhatsNewResult(); |
||
83 | } |
||
84 | |||
85 | $response = $this->queryChangesServer($uri, $changesInfo); |
||
86 | |||
87 | switch ($this->evaluateResponse($response)) { |
||
88 | case self::RESPONSE_NO_CONTENT: |
||
89 | return []; |
||
90 | case self::RESPONSE_USE_CACHE: |
||
91 | return json_decode($changesInfo->getData(), true); |
||
92 | case self::RESPONSE_HAS_CONTENT: |
||
93 | default: |
||
94 | $data = $this->extractData($response->getBody()); |
||
95 | $changesInfo->setData(json_encode($data)); |
||
96 | $changesInfo->setEtag($response->getHeader('Etag')); |
||
97 | $this->cacheResult($changesInfo, $version); |
||
98 | |||
99 | return $data; |
||
100 | } |
||
101 | } |
||
102 | |||
103 | /** |
||
104 | * @throws \Exception |
||
105 | */ |
||
106 | protected function queryChangesServer(string $uri, WhatsNewResult $entry): IResponse |
||
107 | { |
||
108 | $headers = []; |
||
109 | if ($entry->getEtag() !== '') { |
||
110 | $headers['If-None-Match'] = [$entry->getEtag()]; |
||
111 | } |
||
112 | |||
113 | $entry->setLastCheck(time()); |
||
114 | $client = $this->clientService->newClient(); |
||
115 | return $client->get($uri, [ |
||
116 | 'headers' => $headers, |
||
117 | ]); |
||
118 | } |
||
119 | |||
120 | protected function evaluateResponse(IResponse $response): int |
||
121 | { |
||
122 | if ($response->getStatusCode() === 304) { |
||
123 | return self::RESPONSE_USE_CACHE; |
||
124 | } elseif ($response->getStatusCode() === 404) { |
||
125 | return self::RESPONSE_NO_CONTENT; |
||
126 | } elseif ($response->getStatusCode() === 200) { |
||
127 | return self::RESPONSE_HAS_CONTENT; |
||
128 | } |
||
129 | return self::RESPONSE_NO_CONTENT; |
||
130 | } |
||
131 | |||
132 | protected function extractData($body): array |
||
133 | { |
||
134 | $data = []; |
||
135 | if ($body) { |
||
136 | $loadEntities = libxml_disable_entity_loader(true); |
||
137 | $xml = @simplexml_load_string($body); |
||
138 | libxml_disable_entity_loader($loadEntities); |
||
139 | if ($xml !== false) { |
||
140 | $data['changelogURL'] = (string)$xml->changelog['href']; |
||
141 | $data['whatsNew'] = []; |
||
142 | foreach ($xml->whatsNew as $infoSet) { |
||
143 | $data['whatsNew'][(string)$infoSet['lang']] = [ |
||
144 | 'regular' => (array)$infoSet->regular->item, |
||
145 | 'admin' => (array)$infoSet->admin->item, |
||
146 | ]; |
||
147 | } |
||
148 | } else { |
||
149 | libxml_clear_errors(); |
||
150 | } |
||
151 | } |
||
152 | return $data; |
||
153 | } |
||
154 | |||
155 | protected function cacheResult(WhatsNewResult $entry, string $version) |
||
156 | { |
||
157 | if ($entry->getVersion() === $version) { |
||
158 | $this->mapper->update($entry); |
||
159 | } else { |
||
160 | $entry->setVersion($version); |
||
161 | $this->mapper->insert($entry); |
||
162 | } |
||
163 | } |
||
164 | } |
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"]
, you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths