Rello /
analytics
| 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 Loading history...
|
|||
| 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 Loading history...
|
|||
| 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 Loading history...
|
|||
| 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 Loading history...
|
|||
| 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