Browse Source

Merge pull request #2707 from nextcloud/clear_appstore_cache_on_upgrade

Clear appstore cache on version upgrade
tags/v12.0.0beta1
Lukas Reschke 7 years ago
parent
commit
b0c1460a1d

+ 4
- 11
lib/private/App/AppStore/Fetcher/AppFetcher.php View File

use OCP\IConfig; use OCP\IConfig;


class AppFetcher extends Fetcher { class AppFetcher extends Fetcher {
/** @var IConfig */
private $config;

/** /**
* @param IAppData $appData * @param IAppData $appData
* @param IClientService $clientService * @param IClientService $clientService
parent::__construct( parent::__construct(
$appData, $appData,
$clientService, $clientService,
$timeFactory
$timeFactory,
$config
); );


$this->fileName = 'apps.json'; $this->fileName = 'apps.json';
$this->config = $config;


$versionArray = explode('.', $this->config->getSystemValue('version')); $versionArray = explode('.', $this->config->getSystemValue('version'));
$this->endpointUrl = sprintf( $this->endpointUrl = sprintf(
* @return array * @return array
*/ */
protected function fetch() { protected function fetch() {
$client = $this->clientService->newClient();
$response = $client->get($this->endpointUrl);
$responseJson = [];
$responseJson['data'] = json_decode($response->getBody(), true);
$responseJson['timestamp'] = $this->timeFactory->getTime();
$response = $responseJson;
/** @var mixed[] $response */
$response = parent::fetch();


$ncVersion = $this->config->getSystemValue('version'); $ncVersion = $this->config->getSystemValue('version');
$ncMajorVersion = explode('.', $ncVersion)[0]; $ncMajorVersion = explode('.', $ncVersion)[0];

+ 6
- 2
lib/private/App/AppStore/Fetcher/CategoryFetcher.php View File

use OCP\AppFramework\Utility\ITimeFactory; use OCP\AppFramework\Utility\ITimeFactory;
use OCP\Files\IAppData; use OCP\Files\IAppData;
use OCP\Http\Client\IClientService; use OCP\Http\Client\IClientService;
use OCP\IConfig;


class CategoryFetcher extends Fetcher { class CategoryFetcher extends Fetcher {
/** /**
* @param IAppData $appData * @param IAppData $appData
* @param IClientService $clientService * @param IClientService $clientService
* @param ITimeFactory $timeFactory * @param ITimeFactory $timeFactory
* @param IConfig $config
*/ */
public function __construct(IAppData $appData, public function __construct(IAppData $appData,
IClientService $clientService, IClientService $clientService,
ITimeFactory $timeFactory) {
ITimeFactory $timeFactory,
IConfig $config) {
parent::__construct( parent::__construct(
$appData, $appData,
$clientService, $clientService,
$timeFactory
$timeFactory,
$config
); );
$this->fileName = 'categories.json'; $this->fileName = 'categories.json';
$this->endpointUrl = 'https://apps.nextcloud.com/api/v1/categories.json'; $this->endpointUrl = 'https://apps.nextcloud.com/api/v1/categories.json';

+ 14
- 3
lib/private/App/AppStore/Fetcher/Fetcher.php View File

use OCP\Files\IAppData; use OCP\Files\IAppData;
use OCP\Files\NotFoundException; use OCP\Files\NotFoundException;
use OCP\Http\Client\IClientService; use OCP\Http\Client\IClientService;
use OCP\IConfig;


abstract class Fetcher { abstract class Fetcher {
const INVALIDATE_AFTER_SECONDS = 300; const INVALIDATE_AFTER_SECONDS = 300;
protected $clientService; protected $clientService;
/** @var ITimeFactory */ /** @var ITimeFactory */
protected $timeFactory; protected $timeFactory;
/** @var IConfig */
protected $config;
/** @var string */ /** @var string */
protected $fileName; protected $fileName;
/** @var string */ /** @var string */
* @param IAppData $appData * @param IAppData $appData
* @param IClientService $clientService * @param IClientService $clientService
* @param ITimeFactory $timeFactory * @param ITimeFactory $timeFactory
* @param IConfig $config
*/ */
public function __construct(IAppData $appData, public function __construct(IAppData $appData,
IClientService $clientService, IClientService $clientService,
ITimeFactory $timeFactory) {
ITimeFactory $timeFactory,
IConfig $config) {
$this->appData = $appData; $this->appData = $appData;
$this->clientService = $clientService; $this->clientService = $clientService;
$this->timeFactory = $timeFactory; $this->timeFactory = $timeFactory;
$this->config = $config;
} }


/** /**
$responseJson = []; $responseJson = [];
$responseJson['data'] = json_decode($response->getBody(), true); $responseJson['data'] = json_decode($response->getBody(), true);
$responseJson['timestamp'] = $this->timeFactory->getTime(); $responseJson['timestamp'] = $this->timeFactory->getTime();
$responseJson['ncversion'] = $this->config->getSystemValue('version');
return $responseJson; return $responseJson;
} }


$file = $rootFolder->getFile($this->fileName); $file = $rootFolder->getFile($this->fileName);
$jsonBlob = json_decode($file->getContent(), true); $jsonBlob = json_decode($file->getContent(), true);
if(is_array($jsonBlob)) { if(is_array($jsonBlob)) {
// If the timestamp is older than 300 seconds request the files new
if((int)$jsonBlob['timestamp'] > ($this->timeFactory->getTime() - self::INVALIDATE_AFTER_SECONDS)) {
/*
* If the timestamp is older than 300 seconds request the files new
* If the version changed (update!) also refresh
*/
if((int)$jsonBlob['timestamp'] > ($this->timeFactory->getTime() - self::INVALIDATE_AFTER_SECONDS) &&
isset($jsonBlob['ncversion']) && $jsonBlob['ncversion'] === $this->config->getSystemValue('version', '0.0.0')) {
return $jsonBlob['data']; return $jsonBlob['data'];
} }
} }

+ 2
- 1
lib/private/Server.php View File

return new CategoryFetcher( return new CategoryFetcher(
$this->getAppDataDir('appstore'), $this->getAppDataDir('appstore'),
$this->getHTTPClientService(), $this->getHTTPClientService(),
$this->query(TimeFactory::class)
$this->query(TimeFactory::class),
$this->getConfig()
); );
}); });
$this->registerService('UserCache', function ($c) { $this->registerService('UserCache', function ($c) {

+ 2
- 1
settings/Application.php View File

return new CategoryFetcher( return new CategoryFetcher(
$server->getAppDataDir('appstore'), $server->getAppDataDir('appstore'),
$server->getHTTPClientService(), $server->getHTTPClientService(),
$server->query(TimeFactory::class)
$server->query(TimeFactory::class),
$server->getConfig()
); );
}); });
} }

+ 1
- 0
tests/lib/App/AppStore/Fetcher/AppFetcherTest.php View File

), ),
), ),
'timestamp' => 1234, 'timestamp' => 1234,
'ncversion' => '11.0.0.2',
); );


$dataToPut = $expected; $dataToPut = $expected;

+ 2
- 1
tests/lib/App/AppStore/Fetcher/CategoryFetcherTest.php View File

$this->fetcher = new CategoryFetcher( $this->fetcher = new CategoryFetcher(
$this->appData, $this->appData,
$this->clientService, $this->clientService,
$this->timeFactory
$this->timeFactory,
$this->config
); );
} }
} }

+ 128
- 6
tests/lib/App/AppStore/Fetcher/FetcherBase.php View File

$this->clientService = $this->createMock(IClientService::class); $this->clientService = $this->createMock(IClientService::class);
$this->timeFactory = $this->createMock(ITimeFactory::class); $this->timeFactory = $this->createMock(ITimeFactory::class);
$this->config = $this->createMock(IConfig::class); $this->config = $this->createMock(IConfig::class);

$this->config
->method('getSystemValue')
->with(
$this->equalTo('version'),
$this->anything()
)->willReturn('11.0.0.2');
} }


public function testGetWithAlreadyExistingFileAndUpToDateTimestamp() {
public function testGetWithAlreadyExistingFileAndUpToDateTimestampAndVersion() {
$folder = $this->createMock(ISimpleFolder::class); $folder = $this->createMock(ISimpleFolder::class);
$file = $this->createMock(ISimpleFile::class); $file = $this->createMock(ISimpleFile::class);
$this->appData $this->appData
$file $file
->expects($this->once()) ->expects($this->once())
->method('getContent') ->method('getContent')
->willReturn('{"timestamp":1200,"data":[{"id":"MyApp"}]}');
->willReturn('{"timestamp":1200,"data":[{"id":"MyApp"}],"ncversion":"11.0.0.2"}');
$this->timeFactory $this->timeFactory
->expects($this->once()) ->expects($this->once())
->method('getTime') ->method('getTime')
$this->assertSame($expected, $this->fetcher->get()); $this->assertSame($expected, $this->fetcher->get());
} }


public function testGetWithNotExistingFileAndUpToDateTimestamp() {
public function testGetWithNotExistingFileAndUpToDateTimestampAndVersion() {
$folder = $this->createMock(ISimpleFolder::class); $folder = $this->createMock(ISimpleFolder::class);
$file = $this->createMock(ISimpleFile::class); $file = $this->createMock(ISimpleFile::class);
$this->appData $this->appData
->expects($this->once()) ->expects($this->once())
->method('getBody') ->method('getBody')
->willReturn('[{"id":"MyNewApp", "foo": "foo"}, {"id":"bar"}]'); ->willReturn('[{"id":"MyNewApp", "foo": "foo"}, {"id":"bar"}]');
$fileData = '{"data":[{"id":"MyNewApp","foo":"foo"},{"id":"bar"}],"timestamp":1502}';
$fileData = '{"data":[{"id":"MyNewApp","foo":"foo"},{"id":"bar"}],"timestamp":1502,"ncversion":"11.0.0.2"}';
$file $file
->expects($this->at(0)) ->expects($this->at(0))
->method('putContent') ->method('putContent')
$file $file
->expects($this->at(0)) ->expects($this->at(0))
->method('getContent') ->method('getContent')
->willReturn('{"timestamp":1200,"data":{"MyApp":{"id":"MyApp"}}}');
->willReturn('{"timestamp":1200,"data":{"MyApp":{"id":"MyApp"}},"ncversion":"11.0.0.2"}');
$this->timeFactory $this->timeFactory
->expects($this->at(0)) ->expects($this->at(0))
->method('getTime') ->method('getTime')
->expects($this->once()) ->expects($this->once())
->method('getBody') ->method('getBody')
->willReturn('[{"id":"MyNewApp", "foo": "foo"}, {"id":"bar"}]'); ->willReturn('[{"id":"MyNewApp", "foo": "foo"}, {"id":"bar"}]');
$fileData = '{"data":[{"id":"MyNewApp","foo":"foo"},{"id":"bar"}],"timestamp":1502}';
$fileData = '{"data":[{"id":"MyNewApp","foo":"foo"},{"id":"bar"}],"timestamp":1502,"ncversion":"11.0.0.2"}';
$file $file
->expects($this->at(1)) ->expects($this->at(1))
->method('putContent') ->method('putContent')
$this->assertSame($expected, $this->fetcher->get()); $this->assertSame($expected, $this->fetcher->get());
} }


public function testGetWithAlreadyExistingFileAndNoVersion() {
$folder = $this->createMock(ISimpleFolder::class);
$file = $this->createMock(ISimpleFile::class);
$this->appData
->expects($this->once())
->method('getFolder')
->with('/')
->willReturn($folder);
$folder
->expects($this->once())
->method('getFile')
->with($this->fileName)
->willReturn($file);
$file
->expects($this->at(0))
->method('getContent')
->willReturn('{"timestamp":1200,"data":{"MyApp":{"id":"MyApp"}}');
$this->timeFactory
->expects($this->at(0))
->method('getTime')
->willReturn(1201);
$client = $this->createMock(IClient::class);
$this->clientService
->expects($this->once())
->method('newClient')
->willReturn($client);
$response = $this->createMock(IResponse::class);
$client
->expects($this->once())
->method('get')
->with($this->endpoint)
->willReturn($response);
$response
->expects($this->once())
->method('getBody')
->willReturn('[{"id":"MyNewApp", "foo": "foo"}, {"id":"bar"}]');
$fileData = '{"data":[{"id":"MyNewApp","foo":"foo"},{"id":"bar"}],"timestamp":1201,"ncversion":"11.0.0.2"}';
$file
->expects($this->at(1))
->method('putContent')
->with($fileData);
$file
->expects($this->at(2))
->method('getContent')
->willReturn($fileData);

$expected = [
[
'id' => 'MyNewApp',
'foo' => 'foo',
],
[
'id' => 'bar',
],
];
$this->assertSame($expected, $this->fetcher->get());
}

public function testGetWithAlreadyExistingFileAndOutdatedVersion() {
$folder = $this->createMock(ISimpleFolder::class);
$file = $this->createMock(ISimpleFile::class);
$this->appData
->expects($this->once())
->method('getFolder')
->with('/')
->willReturn($folder);
$folder
->expects($this->once())
->method('getFile')
->with($this->fileName)
->willReturn($file);
$file
->expects($this->at(0))
->method('getContent')
->willReturn('{"timestamp":1200,"data":{"MyApp":{"id":"MyApp"}},"ncversion":"11.0.0.1"}');
$this->timeFactory
->method('getTime')
->willReturn(1201);
$client = $this->createMock(IClient::class);
$this->clientService
->expects($this->once())
->method('newClient')
->willReturn($client);
$response = $this->createMock(IResponse::class);
$client
->expects($this->once())
->method('get')
->with($this->endpoint)
->willReturn($response);
$response
->expects($this->once())
->method('getBody')
->willReturn('[{"id":"MyNewApp", "foo": "foo"}, {"id":"bar"}]');
$fileData = '{"data":[{"id":"MyNewApp","foo":"foo"},{"id":"bar"}],"timestamp":1201,"ncversion":"11.0.0.2"}';
$file
->expects($this->at(1))
->method('putContent')
->with($fileData);
$file
->expects($this->at(2))
->method('getContent')
->willReturn($fileData);

$expected = [
[
'id' => 'MyNewApp',
'foo' => 'foo',
],
[
'id' => 'bar',
],
];
$this->assertSame($expected, $this->fetcher->get());
}

public function testGetWithExceptionInClient() { public function testGetWithExceptionInClient() {
$folder = $this->createMock(ISimpleFolder::class); $folder = $this->createMock(ISimpleFolder::class);
$file = $this->createMock(ISimpleFile::class); $file = $this->createMock(ISimpleFile::class);

Loading…
Cancel
Save