From 5d8b941fea23f09586b825324d0dccd39284bc26 Mon Sep 17 00:00:00 2001 From: Roeland Jago Douma Date: Wed, 24 Aug 2016 12:03:22 +0200 Subject: [PATCH 01/14] Initial AppData * Introduce simpleFS * Introduce IAppData * Introduce AppData Factory to get your AppData folder * Update FileDisplayResponse * AppData implements a ISimpleRoot but lazy. So only if an apps starts to access data will stuff get initialized Signed-off-by: Roeland Jago Douma --- lib/private/Avatar.php | 7 +- lib/private/Files/AppData/AppData.php | 128 ++++++++++++++++++ lib/private/Files/AppData/Factory.php | 50 +++++++ lib/private/Files/SimpleFS/SimpleFile.php | 115 ++++++++++++++++ lib/private/Files/SimpleFS/SimpleFolder.php | 72 ++++++++++ lib/private/Server.php | 15 ++ .../AppFramework/Http/FileDisplayResponse.php | 7 +- lib/public/Files/IAppData.php | 36 +++++ lib/public/Files/SimpleFS/ISimpleFile.php | 100 ++++++++++++++ lib/public/Files/SimpleFS/ISimpleFolder.php | 87 ++++++++++++ lib/public/Files/SimpleFS/ISimpleRoot.php | 61 +++++++++ 11 files changed, 671 insertions(+), 7 deletions(-) create mode 100644 lib/private/Files/AppData/AppData.php create mode 100644 lib/private/Files/AppData/Factory.php create mode 100644 lib/private/Files/SimpleFS/SimpleFile.php create mode 100644 lib/private/Files/SimpleFS/SimpleFolder.php create mode 100644 lib/public/Files/IAppData.php create mode 100644 lib/public/Files/SimpleFS/ISimpleFile.php create mode 100644 lib/public/Files/SimpleFS/ISimpleFolder.php create mode 100644 lib/public/Files/SimpleFS/ISimpleRoot.php diff --git a/lib/private/Avatar.php b/lib/private/Avatar.php index 9e8bd0136c200..e7fd4da4615ff 100644 --- a/lib/private/Avatar.php +++ b/lib/private/Avatar.php @@ -33,6 +33,7 @@ use OCP\Files\File; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; +use OCP\Files\SimpleFS\ISimpleFolder; use OCP\IAvatar; use OCP\IConfig; use OCP\IImage; @@ -45,7 +46,7 @@ */ class Avatar implements IAvatar { - /** @var Folder */ + /** @var ISimpleFolder */ private $folder; /** @var IL10N */ private $l; @@ -59,13 +60,13 @@ class Avatar implements IAvatar { /** * constructor * - * @param Folder $folder The folder where the avatars are + * @param ISimpleFolder $folder The folder where the avatars are * @param IL10N $l * @param User $user * @param ILogger $logger * @param IConfig $config */ - public function __construct(Folder $folder, + public function __construct(ISimpleFolder $folder, IL10N $l, $user, ILogger $logger, diff --git a/lib/private/Files/AppData/AppData.php b/lib/private/Files/AppData/AppData.php new file mode 100644 index 0000000000000..f2180a48e617e --- /dev/null +++ b/lib/private/Files/AppData/AppData.php @@ -0,0 +1,128 @@ + + * + * @author Roeland Jago Douma + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OC\Files\AppData; + +use OC\Files\SimpleFS\SimpleFolder; +use OCP\Files\IAppData; +use OCP\Files\IRootFolder; +use OCP\Files\Folder; +use OC\SystemConfig; +use OCP\Files\NotFoundException; +use OCP\Files\NotPermittedException; + +class AppData extends SimpleRoot implements IAppData { + + /** @var IRootFolder */ + private $rootFolder; + + /** @var SystemConfig */ + private $config; + + /** @var string */ + private $appId; + + /** + * AppData constructor. + * + * @param IRootFolder $rootFolder + * @param SystemConfig $systemConfig + * @param string $appId + */ + public function __construct(IRootFolder $rootFolder, + SystemConfig $systemConfig, + $appId) { + + $this->rootFolder = $rootFolder; + $this->config = $systemConfig; + $this->appId = $appId; + } + + /** + * @return Folder + * @throws \RuntimeException + */ + private function getAppDataFolder() { + if ($this->folder === null) { + $instanceId = $this->config->getValue('instanceid', null); + if ($instanceId === null) { + throw new \RuntimeException('no instance id!'); + } + + $name = 'appdata_' . $instanceId; + + try { + $appDataFolder = $this->rootFolder->get($name); + } catch (NotFoundException $e) { + try { + $appDataFolder = $this->rootFolder->newFolder($name); + } catch (NotPermittedException $e) { + throw new \RuntimeException('Could not get appdata folder'); + } + } + + try { + $appDataFolder = $appDataFolder->get($this->appId); + } catch (NotFoundException $e) { + try { + $appDataFolder = $appDataFolder->newFolder($this->appId); + } catch (NotPermittedException $e) { + throw new \RuntimeException('Could not get appdata folder for ' . $this->appId); + } + } + + $this->folder = $appDataFolder; + } + + return $this->folder; + } + + /** + * @inheritdoc + */ + public function getFolder($name) { + $node = $this->getAppDataFolder()->get($name); + + /** @var Folder $node */ + return new SimpleFolder($node); + } + + /** + * @inheritdoc + */ + public function newFolder($name) { + $folder = $this->getAppDataFolder()->newFolder($name); + + return new SimpleFolder($folder); + } + + public function getDirectoryListing() { + $listing = $this->getAppDataFolder()->getDirectoryListing(); + + $fileListing = array_map(function(Node $file) { + return new SimpleFolder($file); + }, $listing); + + return $fileListing; + } +} diff --git a/lib/private/Files/AppData/Factory.php b/lib/private/Files/AppData/Factory.php new file mode 100644 index 0000000000000..85c757337964c --- /dev/null +++ b/lib/private/Files/AppData/Factory.php @@ -0,0 +1,50 @@ + + * + * @author Roeland Jago Douma + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +namespace OC\Files\AppData; + +use OC\SystemConfig; +use OCP\Files\IRootFolder; + +class Factory { + + /** @var IRootFolder */ + private $rootFolder; + + /** @var SystemConfig */ + private $config; + + public function __construct(IRootFolder $rootFolder, + SystemConfig $systemConfig) { + + $this->rootFolder = $rootFolder; + $this->config = $systemConfig; + } + + /** + * @param string $appId + * @return AppData + */ + public function get($appId) { + return new AppData($this->rootFolder, $this->config, $appId); + } +} diff --git a/lib/private/Files/SimpleFS/SimpleFile.php b/lib/private/Files/SimpleFS/SimpleFile.php new file mode 100644 index 0000000000000..5eadfd98b6044 --- /dev/null +++ b/lib/private/Files/SimpleFS/SimpleFile.php @@ -0,0 +1,115 @@ + + * + * @author Roeland Jago Douma + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +namespace OC\Files\SimpleFS; + +use OCP\Files\File; +use OCP\Files\NotPermittedException; +use OCP\Files\SimpleFS\ISimpleFile; + +class SimpleFile implements ISimpleFile { + + /** @var File $file */ + private $file; + + /** + * File constructor. + * + * @param File $file + */ + public function __construct(File $file) { + $this->file = $file; + } + + /** + * Get the name + * + * @return string + */ + public function getName() { + return $this->file->getName(); + } + + /** + * Get the size in bytes + * + * @return int + */ + public function getSize() { + return $this->file->getSize(); + } + + /** + * Get the ETag + * + * @return string + */ + public function getETag() { + return $this->file->getEtag(); + } + + /** + * Get the last modification time + * + * @return int + */ + public function getMTime() { + return $this->file->getMTime(); + } + + /** + * Get the content + * + * @return string + */ + public function getContent() { + return $this->file->getContent(); + } + + /** + * Overwrite the file + * + * @param string $data + * @throws NotPermittedException + */ + public function putContent($data) { + $this->file->putContent($data); + } + + /** + * Delete the file + * + * @throws NotPermittedException + */ + public function delete() { + $this->file->delete(); + } + + /** + * Get the MimeType + * + * @return string + */ + public function getMimeType() { + return $this->file->getMimeType(); + } +} diff --git a/lib/private/Files/SimpleFS/SimpleFolder.php b/lib/private/Files/SimpleFS/SimpleFolder.php new file mode 100644 index 0000000000000..4ee61f0eec955 --- /dev/null +++ b/lib/private/Files/SimpleFS/SimpleFolder.php @@ -0,0 +1,72 @@ + + * + * @author Roeland Jago Douma + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +namespace OC\Files\SimpleFS; + +use OCP\Files\Folder; +use OCP\Files\Node; +use OCP\Files\SimpleFS\ISimpleFolder; + +class SimpleFolder implements ISimpleFolder { + + /** @var Folder */ + private $folder; + + /** + * Folder constructor. + * + * @param Folder $folder + */ + public function __construct(Folder $folder) { + $this->folder = $folder; + } + + public function getName() { + return $this->folder->getName(); + } + + public function getDirectoryListing() { + $listing = $this->folder->getDirectoryListing(); + + $fileListing = array_map(function(Node $file) { + return new SimpleFile($file); + }, $listing); + + return $fileListing; + } + + public function delete() { + $this->folder->delete(); + } + + public function getFile($name) { + $file = $this->folder->get($name); + + return new SimpleFile($file); + } + + public function newFile($name) { + $file = $this->folder->newFile($name); + + return new SimpleFile($file); + } +} diff --git a/lib/private/Server.php b/lib/private/Server.php index 494387ab6ca65..838393b8507d2 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -742,6 +742,12 @@ public function __construct($webRoot, \OC\Config $config) { ); return $manager; }); + $this->registerService(\OC\Files\AppData\Factory::class, function (Server $c) { + return new \OC\Files\AppData\Factory( + $c->getRootFolder(), + $c->getSystemConfig() + ); + }); } /** @@ -1456,4 +1462,13 @@ public function getLDAPProvider() { public function getSettingsManager() { return $this->query('SettingsManager'); } + + /** + * @return \OCP\Files\IAppData + */ + public function getAppDataDir($app) { + /** @var \OC\Files\AppData\Factory $factory */ + $factory = $this->query(\OC\Files\AppData\Factory::class); + return $factory->get($app); + } } diff --git a/lib/public/AppFramework/Http/FileDisplayResponse.php b/lib/public/AppFramework/Http/FileDisplayResponse.php index 22171e2b3797c..03a6fbec2dd27 100644 --- a/lib/public/AppFramework/Http/FileDisplayResponse.php +++ b/lib/public/AppFramework/Http/FileDisplayResponse.php @@ -23,7 +23,6 @@ namespace OCP\AppFramework\Http; use OCP\AppFramework\Http; -use OCP\Files\File; /** * Class FileDisplayResponse @@ -33,18 +32,18 @@ */ class FileDisplayResponse extends Response implements ICallbackResponse { - /** @var File */ + /** @var \OCP\Files\File|\OCP\Files\SimpleFS\ISimpleFile */ private $file; /** * FileDisplayResponse constructor. * - * @param File $file + * @param \OCP\Files\File|\OCP\Files\SimpleFS\ISimpleFile $file * @param int $statusCode * @param array $headers * @since 9.2.0 */ - public function __construct(File $file, $statusCode=Http::STATUS_OK, + public function __construct($file, $statusCode=Http::STATUS_OK, $headers=[]) { $this->file = $file; $this->setStatus($statusCode); diff --git a/lib/public/Files/IAppData.php b/lib/public/Files/IAppData.php new file mode 100644 index 0000000000000..92e54fee3663b --- /dev/null +++ b/lib/public/Files/IAppData.php @@ -0,0 +1,36 @@ + + * + * @author Roeland Jago Douma + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +namespace OCP\Files; + +use OCP\Files\SimpleFS\ISimpleRoot; + +/** + * Interface IAppData + * + * @package OCP\Files + * @since 9.2.0 + * @internal This interface is experimental and might change for NC12 + */ +interface IAppData extends ISimpleRoot { + +} diff --git a/lib/public/Files/SimpleFS/ISimpleFile.php b/lib/public/Files/SimpleFS/ISimpleFile.php new file mode 100644 index 0000000000000..efd682e7855f3 --- /dev/null +++ b/lib/public/Files/SimpleFS/ISimpleFile.php @@ -0,0 +1,100 @@ + + * + * @author Roeland Jago Douma + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +namespace OCP\Files\SimpleFS; + +use OCP\Files\NotPermittedException; + +/** + * Interface ISimpleFile + * + * @package OCP\Files\SimpleFS + * @since 9.2.0 + * @internal This interface is experimental and might change for NC12 + */ +interface ISimpleFile { + + /** + * Get the name + * + * @return string + * @since 9.2.0 + */ + public function getName(); + + /** + * Get the size in bytes + * + * @return int + * @since 9.2.0 + */ + public function getSize(); + + /** + * Get the ETag + * + * @return string + * @since 9.2.0 + */ + public function getETag(); + + /** + * Get the last modification time + * + * @return int + * @since 9.2.0 + */ + public function getMTime(); + + /** + * Get the content + * + * @return string + * @since 9.2.0 + */ + public function getContent(); + + /** + * Overwrite the file + * + * @param string $data + * @throws NotPermittedException + * @since 9.2.0 + */ + public function putContent($data); + + /** + * Delete the file + * + * @throws NotPermittedException + * @since 9.2.0 + */ + public function delete(); + + /** + * Get the MimeType + * + * @return string + * @since 9.2.0 + */ + public function getMimeType(); +} diff --git a/lib/public/Files/SimpleFS/ISimpleFolder.php b/lib/public/Files/SimpleFS/ISimpleFolder.php new file mode 100644 index 0000000000000..c8d7f060fbeeb --- /dev/null +++ b/lib/public/Files/SimpleFS/ISimpleFolder.php @@ -0,0 +1,87 @@ + + * + * @author Roeland Jago Douma + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +namespace OCP\Files\SimpleFS; + +use OCP\Files\NotFoundException; +use OCP\Files\NotPermittedException; + +/** + * Interface ISimpleFolder + * + * @package OCP\Files\SimpleFS + * @since 9.2.0 + * @internal This interface is experimental and might change for NC12 + */ +interface ISimpleFolder { + /** + * Get all the files in a folder + * + * @return ISimpleFile[] + * @since 9.2.0 + */ + public function getDirectoryListing(); + + /** + * Check if a file with $name exists + * + * @param string $name + * @return bool + * @since 9.2.0 + */ + public function fileExists($name); + + /** + * + * @param string $name + * @return ISimpleFile + * @throws NotFoundException + * @since 9.2.0 + */ + public function getFile($name); + + /** + * Creates a new file with $name in the folder + * + * @param string $name + * @return ISimpleFile + * @throws NotPermittedException + * @since 9.2.0 + */ + public function newFile($name); + + /** + * Remove the folder and all the files in it + * + * @throws NotPermittedException + * @since 9.2.0 + */ + public function delete(); + + /** + * Get the folder name + * + * @return string + * @since 9.2.0 + */ + public function getName(); +} diff --git a/lib/public/Files/SimpleFS/ISimpleRoot.php b/lib/public/Files/SimpleFS/ISimpleRoot.php new file mode 100644 index 0000000000000..a9b00540eb234 --- /dev/null +++ b/lib/public/Files/SimpleFS/ISimpleRoot.php @@ -0,0 +1,61 @@ + + * + * @author Roeland Jago Douma + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +namespace OCP\Files\SimpleFS; + +use OCP\Files\NotFoundException; + +/** + * Interface ISimpleRoot + * + * @package OCP\Files\SimpleFS + * @since 9.2.0 + * @internal This interface is experimental and might change for NC12 + */ +interface ISimpleRoot { + /** + * Get the folder with name $name + * + * @param string $name + * @return ISimpleFolder + * @throws NotFoundException + * @since 9.2.0 + */ + public function getFolder($name); + + /** + * Get all the Folders + * + * @return ISimpleFolder[] + * @since 9.2.0 + */ + public function getDirectoryListing(); + + /** + * Create a new folder named $name + * + * @param string $name + * @return ISimpleFolder + * @since 9.2.0 + */ + public function newFolder($name); +} From ac38a3a654df909d2c0c9d7c4d84e8e5ea2c587a Mon Sep 17 00:00:00 2001 From: Roeland Jago Douma Date: Mon, 12 Sep 2016 14:57:15 +0200 Subject: [PATCH 02/14] Add Tests Signed-off-by: Roeland Jago Douma --- lib/private/Files/AppData/AppData.php | 23 +-- lib/private/Files/SimpleFS/SimpleFolder.php | 15 +- tests/lib/Files/AppData/AppDataTest.php | 121 +++++++++++++++ tests/lib/Files/AppData/FactoryTest.php | 55 +++++++ tests/lib/Files/SimpleFS/SimpleFileTest.php | 104 +++++++++++++ tests/lib/Files/SimpleFS/SimpleFolderTest.php | 138 ++++++++++++++++++ 6 files changed, 444 insertions(+), 12 deletions(-) create mode 100644 tests/lib/Files/AppData/AppDataTest.php create mode 100644 tests/lib/Files/AppData/FactoryTest.php create mode 100644 tests/lib/Files/SimpleFS/SimpleFileTest.php create mode 100644 tests/lib/Files/SimpleFS/SimpleFolderTest.php diff --git a/lib/private/Files/AppData/AppData.php b/lib/private/Files/AppData/AppData.php index f2180a48e617e..270e834b8e5db 100644 --- a/lib/private/Files/AppData/AppData.php +++ b/lib/private/Files/AppData/AppData.php @@ -28,10 +28,11 @@ use OCP\Files\IRootFolder; use OCP\Files\Folder; use OC\SystemConfig; +use OCP\Files\Node; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; -class AppData extends SimpleRoot implements IAppData { +class AppData implements IAppData { /** @var IRootFolder */ private $rootFolder; @@ -42,6 +43,9 @@ class AppData extends SimpleRoot implements IAppData { /** @var string */ private $appId; + /** @var Folder */ + private $folder; + /** * AppData constructor. * @@ -97,9 +101,6 @@ private function getAppDataFolder() { return $this->folder; } - /** - * @inheritdoc - */ public function getFolder($name) { $node = $this->getAppDataFolder()->get($name); @@ -107,9 +108,6 @@ public function getFolder($name) { return new SimpleFolder($node); } - /** - * @inheritdoc - */ public function newFolder($name) { $folder = $this->getAppDataFolder()->newFolder($name); @@ -119,10 +117,15 @@ public function newFolder($name) { public function getDirectoryListing() { $listing = $this->getAppDataFolder()->getDirectoryListing(); - $fileListing = array_map(function(Node $file) { - return new SimpleFolder($file); + $fileListing = array_map(function(Node $folder) { + if ($folder instanceof Folder) { + return new SimpleFolder($folder); + } + return null; }, $listing); - return $fileListing; + $fileListing = array_filter($fileListing); + + return array_values($fileListing); } } diff --git a/lib/private/Files/SimpleFS/SimpleFolder.php b/lib/private/Files/SimpleFS/SimpleFolder.php index 4ee61f0eec955..8ce6c013c1fa4 100644 --- a/lib/private/Files/SimpleFS/SimpleFolder.php +++ b/lib/private/Files/SimpleFS/SimpleFolder.php @@ -22,8 +22,10 @@ */ namespace OC\Files\SimpleFS; +use OCP\Files\File; use OCP\Files\Folder; use OCP\Files\Node; +use OCP\Files\NotFoundException; use OCP\Files\SimpleFS\ISimpleFolder; class SimpleFolder implements ISimpleFolder { @@ -48,10 +50,15 @@ public function getDirectoryListing() { $listing = $this->folder->getDirectoryListing(); $fileListing = array_map(function(Node $file) { - return new SimpleFile($file); + if ($file instanceof File) { + return new SimpleFile($file); + } + return null; }, $listing); - return $fileListing; + $fileListing = array_filter($fileListing); + + return array_values($fileListing); } public function delete() { @@ -61,6 +68,10 @@ public function delete() { public function getFile($name) { $file = $this->folder->get($name); + if (!($file instanceof File)) { + throw new NotFoundException(); + } + return new SimpleFile($file); } diff --git a/tests/lib/Files/AppData/AppDataTest.php b/tests/lib/Files/AppData/AppDataTest.php new file mode 100644 index 0000000000000..3247ce7ba9989 --- /dev/null +++ b/tests/lib/Files/AppData/AppDataTest.php @@ -0,0 +1,121 @@ + + * + * @author Roeland Jago Douma + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +namespace Test\Files\AppData; + +use OC\Files\AppData\AppData; +use OC\SystemConfig; +use OCP\Files\File; +use OCP\Files\Folder; +use OCP\Files\IAppData; +use OCP\Files\IRootFolder; +use OCP\Files\Node; +use OCP\Files\SimpleFS\ISimpleFolder; + +class AppDataTest extends \Test\TestCase { + /** @var IRootFolder|\PHPUnit_Framework_MockObject_MockObject */ + private $rootFolder; + + /** @var SystemConfig|\PHPUnit_Framework_MockObject_MockObject */ + private $systemConfig; + + /** @var IAppData */ + private $appData; + + public function setUp() { + parent::setUp(); + + $this->rootFolder = $this->createMock(IRootFolder::class); + $this->systemConfig = $this->createMock(SystemConfig::class); + $this->appData = new AppData($this->rootFolder, $this->systemConfig, 'myApp'); + + $this->systemConfig->expects($this->any()) + ->method('getValue') + ->with('instanceid', null) + ->willReturn('iid'); + } + + private function setupAppFolder() { + $dataFolder = $this->createMock(Folder::class); + $appFolder = $this->createMock(Folder::class); + + $this->rootFolder->expects($this->once()) + ->method('get') + ->with($this->equalTo('appdata_iid')) + ->willReturn($dataFolder); + $dataFolder->expects($this->once()) + ->method('get') + ->with($this->equalTo('myApp')) + ->willReturn($appFolder); + + return [$dataFolder, $appFolder]; + } + + public function testGetFolder() { + $folders = $this->setupAppFolder(); + $appFolder = $folders[1]; + + $folder = $this->createMock(Folder::class); + + $appFolder->expects($this->once()) + ->method('get') + ->with($this->equalTo('folder')) + ->willReturn($folder); + + $result = $this->appData->getFolder('folder'); + $this->assertInstanceOf(ISimpleFolder::class, $result); + } + + public function testNewFolder() { + $folders = $this->setupAppFolder(); + $appFolder = $folders[1]; + + $folder = $this->createMock(Folder::class); + + $appFolder->expects($this->once()) + ->method('newFolder') + ->with($this->equalTo('folder')) + ->willReturn($folder); + + $result = $this->appData->newFolder('folder'); + $this->assertInstanceOf(ISimpleFolder::class, $result); + } + + public function testGetDirectoryListing() { + $folders = $this->setupAppFolder(); + $appFolder = $folders[1]; + + $file = $this->createMock(File::class); + $folder = $this->createMock(Folder::class); + $node = $this->createMock(Node::class); + + $appFolder->expects($this->once()) + ->method('getDirectoryListing') + ->willReturn([$file, $folder, $node]); + + $result = $this->appData->getDirectoryListing(); + + $this->assertCount(1, $result); + $this->assertInstanceOf(ISimpleFolder::class, $result[0]); + } + +} diff --git a/tests/lib/Files/AppData/FactoryTest.php b/tests/lib/Files/AppData/FactoryTest.php new file mode 100644 index 0000000000000..75999c8c7da92 --- /dev/null +++ b/tests/lib/Files/AppData/FactoryTest.php @@ -0,0 +1,55 @@ + + * + * @author Roeland Jago Douma + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +namespace Test\Files\AppData; + +use OC\Files\AppData\Factory; +use OC\SystemConfig; +use OCP\Files\IRootFolder; + +class FactoryTest extends \Test\TestCase { + /** @var IRootFolder|\PHPUnit_Framework_MockObject_MockObject */ + private $rootFolder; + + /** @var SystemConfig|\PHPUnit_Framework_MockObject_MockObject */ + private $systemConfig; + + /** @var Factory */ + private $factory; + + public function setUp() { + parent::setUp(); + + $this->rootFolder = $this->createMock(IRootFolder::class); + $this->systemConfig = $this->createMock(SystemConfig::class); + $this->factory = new Factory($this->rootFolder, $this->systemConfig); + } + + public function testGet() { + $this->rootFolder->expects($this->never()) + ->method($this->anything()); + $this->systemConfig->expects($this->never()) + ->method($this->anything()); + + $this->factory->get('foo'); + } +} diff --git a/tests/lib/Files/SimpleFS/SimpleFileTest.php b/tests/lib/Files/SimpleFS/SimpleFileTest.php new file mode 100644 index 0000000000000..4e623eafa22ba --- /dev/null +++ b/tests/lib/Files/SimpleFS/SimpleFileTest.php @@ -0,0 +1,104 @@ + + * + * @author Roeland Jago Douma + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +namespace Test\File\SimpleFS; + +use OC\Files\SimpleFS\SimpleFile; +use OCP\Files\File; + +class SimpleFileTest extends \Test\TestCase { + /** @var File|\PHPUnit_Framework_MockObject_MockObject */ + private $file; + + /** @var SimpleFile */ + private $simpleFile; + + public function setUp() { + parent::setUp(); + + $this->file = $this->createMock(File::class); + $this->simpleFile = new SimpleFile($this->file); + } + + public function testGetName() { + $this->file->expects($this->once()) + ->method('getName') + ->willReturn('myname'); + + $this->assertEquals('myname', $this->simpleFile->getName()); + } + + public function testGetSize() { + $this->file->expects($this->once()) + ->method('getSize') + ->willReturn(42); + + $this->assertEquals(42, $this->simpleFile->getSize()); + } + + public function testGetETag() { + $this->file->expects($this->once()) + ->method('getETag') + ->willReturn('etag'); + + $this->assertEquals('etag', $this->simpleFile->getETag()); + } + + public function testGetMTime() { + $this->file->expects($this->once()) + ->method('getMTime') + ->willReturn(101); + + $this->assertEquals(101, $this->simpleFile->getMTime()); + } + + public function testGetContent() { + $this->file->expects($this->once()) + ->method('getContent') + ->willReturn('foo'); + + $this->assertEquals('foo', $this->simpleFile->getContent()); + } + + public function testPutContent() { + $this->file->expects($this->once()) + ->method('putContent') + ->with($this->equalTo('bar')); + + $this->simpleFile->putContent('bar'); + } + + public function testDelete() { + $this->file->expects($this->once()) + ->method('delete'); + + $this->simpleFile->delete(); + } + + public function testGetMimeType() { + $this->file->expects($this->once()) + ->method('getMimeType') + ->willReturn('app/awesome'); + + $this->assertEquals('app/awesome', $this->simpleFile->getMimeType()); + } +} diff --git a/tests/lib/Files/SimpleFS/SimpleFolderTest.php b/tests/lib/Files/SimpleFS/SimpleFolderTest.php new file mode 100644 index 0000000000000..d86c705d88083 --- /dev/null +++ b/tests/lib/Files/SimpleFS/SimpleFolderTest.php @@ -0,0 +1,138 @@ + + * + * @author Roeland Jago Douma + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +namespace Test\File\SimpleFS; + +use OC\Files\SimpleFS\SimpleFolder; +use OCP\Files\File; +use OCP\Files\Folder; +use OCP\Files\Node; +use OCP\Files\NotFoundException; +use OCP\Files\SimpleFS\ISimpleFile; + +class SimpleFolderTest extends \Test\TestCase { + /** @var Folder|\PHPUnit_Framework_MockObject_MockObject */ + private $folder; + + /** @var SimpleFolder */ + private $simpleFolder; + + public function setUp() { + parent::setUp(); + + $this->folder = $this->createMock(Folder::class); + $this->simpleFolder = new SimpleFolder($this->folder); + } + + public function testGetName() { + $this->folder->expects($this->once()) + ->method('getName') + ->willReturn('myname'); + + $this->assertEquals('myname', $this->simpleFolder->getName()); + } + + public function testDelete() { + $this->folder->expects($this->once()) + ->method('delete'); + + $this->simpleFolder->delete(); + } + + public function dataFileExists() { + return [ + [true], + [false], + ]; + } + + /** + * @dataProvider dataFileExists + * @param bool $exists + */ + public function testFileExists($exists) { + $this->folder->expects($this->once()) + ->method('nodeExists') + ->with($this->equalTo('file')) + ->willReturn($exists); + + $this->assertEquals($exists, $this->simpleFolder->fileExists('file')); + } + + public function dataGetFile() { + return [ + [File::class, false], + [Folder::class, true], + [Node::class, true], + ]; + } + + /** + * @dataProvider dataGetFile + * @param string $class + * @param bool $exception + */ + public function testGetFile($class, $exception) { + $node = $this->createMock($class); + + $this->folder->expects($this->once()) + ->method('get') + ->with($this->equalTo('file')) + ->willReturn($node); + + try { + $result = $this->simpleFolder->getFile('file'); + $this->assertFalse($exception); + $this->assertInstanceOf(ISimpleFile::class, $result); + } catch (NotFoundException $e) { + $this->assertTrue($exception); + } + } + + public function testNewFile() { + $file = $this->createMock(File::class); + + $this->folder->expects($this->once()) + ->method('newFile') + ->with($this->equalTo('file')) + ->willReturn($file); + + $result = $this->simpleFolder->newFile('file'); + $this->assertInstanceOf(ISimpleFile::class, $result); + } + + public function testGetDirectoryListing() { + $file = $this->createMock(File::class); + $folder = $this->createMock(Folder::class); + $node = $this->createMock(Node::class); + + $this->folder->expects($this->once()) + ->method('getDirectoryListing') + ->willReturn([$file, $folder, $node]); + + $result = $this->simpleFolder->getDirectoryListing(); + + $this->assertCount(1, $result); + $this->assertInstanceOf(ISimpleFile::class, $result[0]); + } + +} From 6807cb684f64587f1747b5168eb42e5172c889eb Mon Sep 17 00:00:00 2001 From: Roeland Jago Douma Date: Wed, 7 Sep 2016 16:09:22 +0200 Subject: [PATCH 03/14] avatar to appdata * Fix AvatarTest Signed-off-by: Roeland Jago Douma --- lib/private/Avatar.php | 16 ++++++------ lib/private/AvatarManager.php | 29 +++++++-------------- lib/private/Files/SimpleFS/SimpleFolder.php | 4 +++ lib/private/Server.php | 2 +- lib/public/Files/SimpleFS/ISimpleFolder.php | 1 + tests/lib/AvatarTest.php | 22 +++++++++------- 6 files changed, 36 insertions(+), 38 deletions(-) diff --git a/lib/private/Avatar.php b/lib/private/Avatar.php index e7fd4da4615ff..c3a068701df1e 100644 --- a/lib/private/Avatar.php +++ b/lib/private/Avatar.php @@ -29,10 +29,9 @@ namespace OC; use OC\User\User; -use OCP\Files\Folder; -use OCP\Files\File; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; +use OCP\Files\SimpleFS\ISimpleFile; use OCP\Files\SimpleFS\ISimpleFolder; use OCP\IAvatar; use OCP\IConfig; @@ -99,7 +98,8 @@ public function get ($size = 64) { * @return bool */ public function exists() { - return $this->folder->nodeExists('avatar.jpg') || $this->folder->nodeExists('avatar.png'); + + return $this->folder->fileExists('avatar.jpg') || $this->folder->fileExists('avatar.png'); } /** @@ -171,15 +171,15 @@ public function getFile($size) { } try { - $file = $this->folder->get($path); + $file = $this->folder->getFile($path); } catch (NotFoundException $e) { if ($size <= 0) { throw new NotFoundException; } $avatar = new OC_Image(); - /** @var File $file */ - $file = $this->folder->get('avatar.' . $ext); + /** @var ISimpleFile $file */ + $file = $this->folder->getFile('avatar.' . $ext); $avatar->loadFromData($file->getContent()); if ($size !== -1) { $avatar->resize($size); @@ -202,9 +202,9 @@ public function getFile($size) { * @throws NotFoundException */ private function getExtension() { - if ($this->folder->nodeExists('avatar.jpg')) { + if ($this->folder->fileExists('avatar.jpg')) { return 'jpg'; - } elseif ($this->folder->nodeExists('avatar.png')) { + } elseif ($this->folder->fileExists('avatar.png')) { return 'png'; } throw new NotFoundException; diff --git a/lib/private/AvatarManager.php b/lib/private/AvatarManager.php index df3247b8f0017..b8c6c2a1eb69d 100644 --- a/lib/private/AvatarManager.php +++ b/lib/private/AvatarManager.php @@ -27,13 +27,12 @@ namespace OC; -use OCP\Files\Folder; +use OCP\Files\IAppData; use OCP\Files\NotFoundException; use OCP\IAvatarManager; use OCP\IConfig; use OCP\ILogger; use OCP\IUserManager; -use OCP\Files\IRootFolder; use OCP\IL10N; /** @@ -44,8 +43,8 @@ class AvatarManager implements IAvatarManager { /** @var IUserManager */ private $userManager; - /** @var IRootFolder */ - private $rootFolder; + /** @var IAppData */ + private $appData; /** @var IL10N */ private $l; @@ -60,19 +59,19 @@ class AvatarManager implements IAvatarManager { * AvatarManager constructor. * * @param IUserManager $userManager - * @param IRootFolder $rootFolder + * @param IAppData $appData * @param IL10N $l * @param ILogger $logger * @param IConfig $config */ public function __construct( IUserManager $userManager, - IRootFolder $rootFolder, + IAppData $appData, IL10N $l, ILogger $logger, IConfig $config) { $this->userManager = $userManager; - $this->rootFolder = $rootFolder; + $this->appData = $appData; $this->l = $l; $this->logger = $logger; $this->config = $config; @@ -95,20 +94,12 @@ public function getAvatar($userId) { // sanitize userID - fixes casing issue (needed for the filesystem stuff that is done below) $userId = $user->getUID(); - /* - * Fix for #22119 - * Basically we do not want to copy the skeleton folder. - * - * For unit test purposes this is ignored when run in PHPUnit. - */ - if(!defined('PHPUNIT_RUN')) { - \OC\Files\Filesystem::initMountPoints($userId); + try { + $folder = $this->appData->getFolder($userId); + } catch (NotFoundException $e) { + $folder = $this->appData->newFolder($userId); } - $dir = '/' . $userId; - /** @var Folder $folder */ - $folder = $this->rootFolder->get($dir); - return new Avatar($folder, $this->l, $user, $this->logger, $this->config); } } diff --git a/lib/private/Files/SimpleFS/SimpleFolder.php b/lib/private/Files/SimpleFS/SimpleFolder.php index 8ce6c013c1fa4..5b55fe0f15765 100644 --- a/lib/private/Files/SimpleFS/SimpleFolder.php +++ b/lib/private/Files/SimpleFS/SimpleFolder.php @@ -65,6 +65,10 @@ public function delete() { $this->folder->delete(); } + public function fileExists($name) { + return $this->folder->nodeExists($name); + } + public function getFile($name) { $file = $this->folder->get($name); diff --git a/lib/private/Server.php b/lib/private/Server.php index 838393b8507d2..cd2cce5cb0bcb 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -359,7 +359,7 @@ public function __construct($webRoot, \OC\Config $config) { $this->registerService('AvatarManager', function (Server $c) { return new AvatarManager( $c->getUserManager(), - $c->getRootFolder(), + $c->getAppDataDir('avatar'), $c->getL10N('lib'), $c->getLogger(), $c->getConfig() diff --git a/lib/public/Files/SimpleFS/ISimpleFolder.php b/lib/public/Files/SimpleFS/ISimpleFolder.php index c8d7f060fbeeb..406bb6311593f 100644 --- a/lib/public/Files/SimpleFS/ISimpleFolder.php +++ b/lib/public/Files/SimpleFS/ISimpleFolder.php @@ -51,6 +51,7 @@ public function getDirectoryListing(); public function fileExists($name); /** + * Get the file named $name from the folder * * @param string $name * @return ISimpleFile diff --git a/tests/lib/AvatarTest.php b/tests/lib/AvatarTest.php index 7f012c895fd17..cea3f9bed1a09 100644 --- a/tests/lib/AvatarTest.php +++ b/tests/lib/AvatarTest.php @@ -8,6 +8,8 @@ namespace Test; +use OC\Files\SimpleFS\SimpleFolder; +use OC\User\User; use OCP\Files\File; use OCP\Files\Folder; use OCP\IConfig; @@ -30,11 +32,11 @@ class AvatarTest extends \Test\TestCase { public function setUp() { parent::setUp(); - $this->folder = $this->createMock(Folder::class); + $this->folder = $this->createMock(SimpleFolder::class); /** @var \OCP\IL10N | \PHPUnit_Framework_MockObject_MockObject $l */ $l = $this->createMock(IL10N::class); $l->method('t')->will($this->returnArgument(0)); - $this->user = $this->getMockBuilder('OC\User\User')->disableOriginalConstructor()->getMock(); + $this->user = $this->createMock(User::class); $this->config = $this->createMock(IConfig::class); $this->avatar = new \OC\Avatar( @@ -51,7 +53,7 @@ public function testGetNoAvatar() { } public function testGetAvatarSizeMatch() { - $this->folder->method('nodeExists') + $this->folder->method('fileExists') ->will($this->returnValueMap([ ['avatar.jpg', true], ['avatar.128.jpg', true], @@ -61,13 +63,13 @@ public function testGetAvatarSizeMatch() { $file = $this->createMock(File::class); $file->method('getContent')->willReturn($expected->data()); - $this->folder->method('get')->with('avatar.128.jpg')->willReturn($file); + $this->folder->method('getFile')->with('avatar.128.jpg')->willReturn($file); $this->assertEquals($expected->data(), $this->avatar->get(128)->data()); } public function testGetAvatarSizeMinusOne() { - $this->folder->method('nodeExists') + $this->folder->method('fileExists') ->will($this->returnValueMap([ ['avatar.jpg', true], ])); @@ -76,13 +78,13 @@ public function testGetAvatarSizeMinusOne() { $file = $this->createMock(File::class); $file->method('getContent')->willReturn($expected->data()); - $this->folder->method('get')->with('avatar.jpg')->willReturn($file); + $this->folder->method('getFile')->with('avatar.jpg')->willReturn($file); $this->assertEquals($expected->data(), $this->avatar->get(-1)->data()); } public function testGetAvatarNoSizeMatch() { - $this->folder->method('nodeExists') + $this->folder->method('fileExists') ->will($this->returnValueMap([ ['avatar.png', true], ['avatar.32.png', false], @@ -95,7 +97,7 @@ public function testGetAvatarNoSizeMatch() { $file = $this->createMock(File::class); $file->method('getContent')->willReturn($expected->data()); - $this->folder->method('get') + $this->folder->method('getFile') ->will($this->returnCallback( function($path) use ($file) { if ($path === 'avatar.png') { @@ -126,7 +128,7 @@ public function testExistsNo() { } public function testExiststJPG() { - $this->folder->method('nodeExists') + $this->folder->method('fileExists') ->will($this->returnValueMap([ ['avatar.jpg', true], ['avatar.png', false], @@ -135,7 +137,7 @@ public function testExiststJPG() { } public function testExistsPNG() { - $this->folder->method('nodeExists') + $this->folder->method('fileExists') ->will($this->returnValueMap([ ['avatar.jpg', false], ['avatar.png', true], From 92dc9e6899ac9aa80f49c796ff7ccf1b1fa70842 Mon Sep 17 00:00:00 2001 From: Roeland Jago Douma Date: Mon, 12 Sep 2016 09:53:31 +0200 Subject: [PATCH 04/14] Avatar migration step * Skip move avatar if avatars disabled Signed-off-by: Roeland Jago Douma --- lib/private/Repair.php | 7 ++ lib/private/Repair/NC11/MoveAvatars.php | 134 ++++++++++++++++++++++++ version.php | 2 +- 3 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 lib/private/Repair/NC11/MoveAvatars.php diff --git a/lib/private/Repair.php b/lib/private/Repair.php index bf441d03c3570..0af1dc9cc7443 100644 --- a/lib/private/Repair.php +++ b/lib/private/Repair.php @@ -36,6 +36,7 @@ use OC\Repair\Collation; use OC\Repair\DropOldJobs; use OC\Repair\MoveUpdaterStepFile; +use OC\Repair\NC11\MoveAvatars; use OC\Repair\OldGroupMembershipShares; use OC\Repair\RemoveGetETagEntries; use OC\Repair\RemoveOldShares; @@ -149,6 +150,12 @@ public static function getRepairSteps() { \OC::$server->getGroupManager() ), new MoveUpdaterStepFile(\OC::$server->getConfig()), + new MoveAvatars( + \OC::$server->getUserManager(), + \OC::$server->getRootFolder(), + \OC::$server->getAppDataDir('avatar'), + \OC::$server->getSystemConfig() + ), ]; } diff --git a/lib/private/Repair/NC11/MoveAvatars.php b/lib/private/Repair/NC11/MoveAvatars.php new file mode 100644 index 0000000000000..d0d78cb1fd603 --- /dev/null +++ b/lib/private/Repair/NC11/MoveAvatars.php @@ -0,0 +1,134 @@ + + * + * @author Roeland Jago Douma + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +namespace OC\Repair\NC11; + +use OC\SystemConfig; +use OCP\Files\File; +use OCP\Files\Folder; +use OCP\Files\IAppData; +use OCP\Files\IRootFolder; +use OCP\Files\NotFoundException; +use OCP\IUser; +use OCP\IUserManager; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; + +class MoveAvatars implements IRepairStep { + + /** @var IUserManager */ + private $userManager; + + /** @var IRootFolder */ + private $rootFolder; + + /** @var IAppData */ + private $appData; + + /** @var SystemConfig */ + private $systemConfig; + + /** + * MoveAvatars constructor. + * + * @param IUserManager $userManager + * @param IRootFolder $rootFolder + * @param IAppData $appData + * @param SystemConfig $systemConfig + */ + public function __construct(IUserManager $userManager, + IRootFolder $rootFolder, + IAppData $appData, + SystemConfig $systemConfig) { + $this->userManager = $userManager; + $this->rootFolder = $rootFolder; + $this->appData = $appData; + $this->systemConfig = $systemConfig; + } + + /** + * @return string + */ + public function getName() { + return 'Move avatars to AppData folder'; + } + + public function run(IOutput $output) { + if ($this->systemConfig->getValue('enable_avatars', true) === false) { + $output->info('Avatars are disabled'); + } else { + $output->startProgress($this->userCount()); + $this->moveAvatar($output); + $output->finishProgress(); + } + } + + private function moveAvatar(IOutput $output) { + $this->userManager->callForAllUsers(function (IUser $user) use ($output) { + if ($user->getLastLogin() !== 0) { + $uid = $user->getUID(); + + \OC\Files\Filesystem::initMountPoints($uid); + /** @var Folder $userFolder */ + $userFolder = $this->rootFolder->get($uid); + + try { + $userData = $this->appData->getFolder($uid); + } catch (NotFoundException $e) { + $userData = $this->appData->newFolder($uid); + } + + + $regex = '/^avatar\.([0-9]+\.)?(jpg|png)$/'; + $avatars = $userFolder->getDirectoryListing(); + + foreach ($avatars as $avatar) { + /** @var File $avatar */ + if (preg_match($regex, $avatar->getName())) { + /* + * This is not the most effective but it is the most abstract way + * to handle this. Avatars should be small anyways. + */ + $newAvatar = $userData->newFile($avatar->getName()); + $newAvatar->putContent($avatar->getContent()); + $avatar->delete(); + } + } + } + $output->advance(); + }); + } + + /** + * @return int + */ + private function userCount() { + $backends = $this->userManager->countUsers(); + $count = 0; + + foreach ($backends as $backend => $amount) { + $count += $amount; + } + + return $count; + } +} diff --git a/version.php b/version.php index 01a822708e3c5..96725a6bb4dda 100644 --- a/version.php +++ b/version.php @@ -25,7 +25,7 @@ // We only can count up. The 4. digit is only for the internal patchlevel to trigger DB upgrades // between betas, final and RCs. This is _not_ the public version number. Reset minor/patchlevel // when updating major/minor version number. -$OC_Version = array(9, 2, 0, 3); +$OC_Version = array(9, 2, 0, 4); // The human readable string $OC_VersionString = '11.0 alpha'; From 3260f695905cdc20692f1c490ec9f8c2d28e872c Mon Sep 17 00:00:00 2001 From: Roeland Jago Douma Date: Thu, 8 Sep 2016 15:20:39 +0200 Subject: [PATCH 05/14] Add for proper DI Signed-off-by: Roeland Jago Douma --- lib/private/AppFramework/DependencyInjection/DIContainer.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/private/AppFramework/DependencyInjection/DIContainer.php b/lib/private/AppFramework/DependencyInjection/DIContainer.php index 20351d1321c2c..b6f8d8f458d51 100644 --- a/lib/private/AppFramework/DependencyInjection/DIContainer.php +++ b/lib/private/AppFramework/DependencyInjection/DIContainer.php @@ -46,6 +46,7 @@ use OC\Core\Middleware\TwoFactorMiddleware; use OCP\AppFramework\IApi; use OCP\AppFramework\IAppContainer; +use OCP\Files\IAppData; class DIContainer extends SimpleContainer implements IAppContainer { @@ -164,6 +165,10 @@ public function __construct($appName, $urlParams = array()){ return $this->getServer()->getHTTPClientService(); }); + $this->registerService(IAppData::class, function (SimpleContainer $c) { + return $this->getServer()->getAppDataDir($c->query('AppName')); + }); + $this->registerService('OCP\\IGroupManager', function($c) { return $this->getServer()->getGroupManager(); }); From f23390ed02b8573236eb392c00fb5806196be5e0 Mon Sep 17 00:00:00 2001 From: Roeland Jago Douma Date: Mon, 12 Sep 2016 08:57:40 +0200 Subject: [PATCH 06/14] Kill users with the reserved name on login Signed-off-by: Roeland Jago Douma --- lib/private/legacy/util.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/private/legacy/util.php b/lib/private/legacy/util.php index cb52949779ff9..b8f3a93ba5024 100644 --- a/lib/private/legacy/util.php +++ b/lib/private/legacy/util.php @@ -311,10 +311,20 @@ public static function getUserQuota($userId) { * * @param String $userId * @param \OCP\Files\Folder $userDirectory + * @throws \RuntimeException */ public static function copySkeleton($userId, \OCP\Files\Folder $userDirectory) { - $skeletonDirectory = \OCP\Config::getSystemValue('skeletondirectory', \OC::$SERVERROOT . '/core/skeleton'); + $skeletonDirectory = \OC::$server->getConfig()->getSystemValue('skeletondirectory', \OC::$SERVERROOT . '/core/skeleton'); + $instanceId = \OC::$server->getConfig()->getSystemValue('instanceid', ''); + + if ($instanceId === null) { + throw new \RuntimeException('no instance id!'); + } + $appdata = 'appdata_' . $instanceId; + if ($userId === $appdata) { + throw new \RuntimeException('username is reserved name: ' . $appdata); + } if (!empty($skeletonDirectory)) { \OCP\Util::writeLog( From a961354c6232e37ef296dd0f3fb21083da8f3cc5 Mon Sep 17 00:00:00 2001 From: Roeland Jago Douma Date: Thu, 8 Sep 2016 15:21:21 +0200 Subject: [PATCH 07/14] Update autoloader Signed-off-by: Roeland Jago Douma --- lib/composer/composer/autoload_classmap.php | 9 +++++++++ lib/composer/composer/autoload_static.php | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 2fa4df4d9e923..f4e8644f9ad2d 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -107,6 +107,7 @@ 'OCP\\Files\\FileNameTooLongException' => $baseDir . '/lib/public/Files/FileNameTooLongException.php', 'OCP\\Files\\Folder' => $baseDir . '/lib/public/Files/Folder.php', 'OCP\\Files\\ForbiddenException' => $baseDir . '/lib/public/Files/ForbiddenException.php', + 'OCP\\Files\\IAppData' => $baseDir . '/lib/public/Files/IAppData.php', 'OCP\\Files\\IHomeStorage' => $baseDir . '/lib/public/Files/IHomeStorage.php', 'OCP\\Files\\IMimeTypeDetector' => $baseDir . '/lib/public/Files/IMimeTypeDetector.php', 'OCP\\Files\\IMimeTypeLoader' => $baseDir . '/lib/public/Files/IMimeTypeLoader.php', @@ -123,6 +124,9 @@ 'OCP\\Files\\NotPermittedException' => $baseDir . '/lib/public/Files/NotPermittedException.php', 'OCP\\Files\\ObjectStore\\IObjectStore' => $baseDir . '/lib/public/Files/ObjectStore/IObjectStore.php', 'OCP\\Files\\ReservedWordException' => $baseDir . '/lib/public/Files/ReservedWordException.php', + 'OCP\\Files\\SimpleFS\\ISimpleFile' => $baseDir . '/lib/public/Files/SimpleFS/ISimpleFile.php', + 'OCP\\Files\\SimpleFS\\ISimpleFolder' => $baseDir . '/lib/public/Files/SimpleFS/ISimpleFolder.php', + 'OCP\\Files\\SimpleFS\\ISimpleRoot' => $baseDir . '/lib/public/Files/SimpleFS/ISimpleRoot.php', 'OCP\\Files\\Storage' => $baseDir . '/lib/public/Files/Storage.php', 'OCP\\Files\\StorageAuthException' => $baseDir . '/lib/public/Files/StorageAuthException.php', 'OCP\\Files\\StorageBadConfigException' => $baseDir . '/lib/public/Files/StorageBadConfigException.php', @@ -459,6 +463,8 @@ 'OC\\Encryption\\Manager' => $baseDir . '/lib/private/Encryption/Manager.php', 'OC\\Encryption\\Update' => $baseDir . '/lib/private/Encryption/Update.php', 'OC\\Encryption\\Util' => $baseDir . '/lib/private/Encryption/Util.php', + 'OC\\Files\\AppData\\AppData' => $baseDir . '/lib/private/Files/AppData/AppData.php', + 'OC\\Files\\AppData\\Factory' => $baseDir . '/lib/private/Files/AppData/Factory.php', 'OC\\Files\\Cache\\Cache' => $baseDir . '/lib/private/Files/Cache/Cache.php', 'OC\\Files\\Cache\\CacheEntry' => $baseDir . '/lib/private/Files/Cache/CacheEntry.php', 'OC\\Files\\Cache\\FailedCache' => $baseDir . '/lib/private/Files/Cache/FailedCache.php', @@ -500,6 +506,8 @@ 'OC\\Files\\ObjectStore\\NoopScanner' => $baseDir . '/lib/private/Files/ObjectStore/NoopScanner.php', 'OC\\Files\\ObjectStore\\ObjectStoreStorage' => $baseDir . '/lib/private/Files/ObjectStore/ObjectStoreStorage.php', 'OC\\Files\\ObjectStore\\Swift' => $baseDir . '/lib/private/Files/ObjectStore/Swift.php', + 'OC\\Files\\SimpleFS\\SimpleFile' => $baseDir . '/lib/private/Files/SimpleFS/SimpleFile.php', + 'OC\\Files\\SimpleFS\\SimpleFolder' => $baseDir . '/lib/private/Files/SimpleFS/SimpleFolder.php', 'OC\\Files\\Storage\\Common' => $baseDir . '/lib/private/Files/Storage/Common.php', 'OC\\Files\\Storage\\CommonTest' => $baseDir . '/lib/private/Files/Storage/CommonTest.php', 'OC\\Files\\Storage\\DAV' => $baseDir . '/lib/private/Files/Storage/DAV.php', @@ -638,6 +646,7 @@ 'OC\\Repair\\FillETags' => $baseDir . '/lib/private/Repair/FillETags.php', 'OC\\Repair\\InnoDB' => $baseDir . '/lib/private/Repair/InnoDB.php', 'OC\\Repair\\MoveUpdaterStepFile' => $baseDir . '/lib/private/Repair/MoveUpdaterStepFile.php', + 'OC\\Repair\\NC11\\MoveAvatars' => $baseDir . '/lib/private/Repair/NC11/MoveAvatars.php', 'OC\\Repair\\OldGroupMembershipShares' => $baseDir . '/lib/private/Repair/OldGroupMembershipShares.php', 'OC\\Repair\\Preview' => $baseDir . '/lib/private/Repair/Preview.php', 'OC\\Repair\\RemoveGetETagEntries' => $baseDir . '/lib/private/Repair/RemoveGetETagEntries.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index ad493bfb0410a..7d3edcc2638c5 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -137,6 +137,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OCP\\Files\\FileNameTooLongException' => __DIR__ . '/../../..' . '/lib/public/Files/FileNameTooLongException.php', 'OCP\\Files\\Folder' => __DIR__ . '/../../..' . '/lib/public/Files/Folder.php', 'OCP\\Files\\ForbiddenException' => __DIR__ . '/../../..' . '/lib/public/Files/ForbiddenException.php', + 'OCP\\Files\\IAppData' => __DIR__ . '/../../..' . '/lib/public/Files/IAppData.php', 'OCP\\Files\\IHomeStorage' => __DIR__ . '/../../..' . '/lib/public/Files/IHomeStorage.php', 'OCP\\Files\\IMimeTypeDetector' => __DIR__ . '/../../..' . '/lib/public/Files/IMimeTypeDetector.php', 'OCP\\Files\\IMimeTypeLoader' => __DIR__ . '/../../..' . '/lib/public/Files/IMimeTypeLoader.php', @@ -153,6 +154,9 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OCP\\Files\\NotPermittedException' => __DIR__ . '/../../..' . '/lib/public/Files/NotPermittedException.php', 'OCP\\Files\\ObjectStore\\IObjectStore' => __DIR__ . '/../../..' . '/lib/public/Files/ObjectStore/IObjectStore.php', 'OCP\\Files\\ReservedWordException' => __DIR__ . '/../../..' . '/lib/public/Files/ReservedWordException.php', + 'OCP\\Files\\SimpleFS\\ISimpleFile' => __DIR__ . '/../../..' . '/lib/public/Files/SimpleFS/ISimpleFile.php', + 'OCP\\Files\\SimpleFS\\ISimpleFolder' => __DIR__ . '/../../..' . '/lib/public/Files/SimpleFS/ISimpleFolder.php', + 'OCP\\Files\\SimpleFS\\ISimpleRoot' => __DIR__ . '/../../..' . '/lib/public/Files/SimpleFS/ISimpleRoot.php', 'OCP\\Files\\Storage' => __DIR__ . '/../../..' . '/lib/public/Files/Storage.php', 'OCP\\Files\\StorageAuthException' => __DIR__ . '/../../..' . '/lib/public/Files/StorageAuthException.php', 'OCP\\Files\\StorageBadConfigException' => __DIR__ . '/../../..' . '/lib/public/Files/StorageBadConfigException.php', @@ -489,6 +493,8 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Encryption\\Manager' => __DIR__ . '/../../..' . '/lib/private/Encryption/Manager.php', 'OC\\Encryption\\Update' => __DIR__ . '/../../..' . '/lib/private/Encryption/Update.php', 'OC\\Encryption\\Util' => __DIR__ . '/../../..' . '/lib/private/Encryption/Util.php', + 'OC\\Files\\AppData\\AppData' => __DIR__ . '/../../..' . '/lib/private/Files/AppData/AppData.php', + 'OC\\Files\\AppData\\Factory' => __DIR__ . '/../../..' . '/lib/private/Files/AppData/Factory.php', 'OC\\Files\\Cache\\Cache' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/Cache.php', 'OC\\Files\\Cache\\CacheEntry' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/CacheEntry.php', 'OC\\Files\\Cache\\FailedCache' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/FailedCache.php', @@ -530,6 +536,8 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Files\\ObjectStore\\NoopScanner' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/NoopScanner.php', 'OC\\Files\\ObjectStore\\ObjectStoreStorage' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/ObjectStoreStorage.php', 'OC\\Files\\ObjectStore\\Swift' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/Swift.php', + 'OC\\Files\\SimpleFS\\SimpleFile' => __DIR__ . '/../../..' . '/lib/private/Files/SimpleFS/SimpleFile.php', + 'OC\\Files\\SimpleFS\\SimpleFolder' => __DIR__ . '/../../..' . '/lib/private/Files/SimpleFS/SimpleFolder.php', 'OC\\Files\\Storage\\Common' => __DIR__ . '/../../..' . '/lib/private/Files/Storage/Common.php', 'OC\\Files\\Storage\\CommonTest' => __DIR__ . '/../../..' . '/lib/private/Files/Storage/CommonTest.php', 'OC\\Files\\Storage\\DAV' => __DIR__ . '/../../..' . '/lib/private/Files/Storage/DAV.php', @@ -668,6 +676,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Repair\\FillETags' => __DIR__ . '/../../..' . '/lib/private/Repair/FillETags.php', 'OC\\Repair\\InnoDB' => __DIR__ . '/../../..' . '/lib/private/Repair/InnoDB.php', 'OC\\Repair\\MoveUpdaterStepFile' => __DIR__ . '/../../..' . '/lib/private/Repair/MoveUpdaterStepFile.php', + 'OC\\Repair\\NC11\\MoveAvatars' => __DIR__ . '/../../..' . '/lib/private/Repair/NC11/MoveAvatars.php', 'OC\\Repair\\OldGroupMembershipShares' => __DIR__ . '/../../..' . '/lib/private/Repair/OldGroupMembershipShares.php', 'OC\\Repair\\Preview' => __DIR__ . '/../../..' . '/lib/private/Repair/Preview.php', 'OC\\Repair\\RemoveGetETagEntries' => __DIR__ . '/../../..' . '/lib/private/Repair/RemoveGetETagEntries.php', From 851769adc821f0a8462081fe23afb5a4339eb7ad Mon Sep 17 00:00:00 2001 From: Roeland Jago Douma Date: Mon, 12 Sep 2016 15:40:51 +0200 Subject: [PATCH 08/14] Deprecate old app folder Signed-off-by: Roeland Jago Douma --- lib/private/Server.php | 1 + lib/public/IServerContainer.php | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/private/Server.php b/lib/private/Server.php index cd2cce5cb0bcb..b49e94b554e43 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -882,6 +882,7 @@ public function getUserFolder($userId = null) { * Returns an app-specific view in ownClouds data directory * * @return \OCP\Files\Folder + * @deprecated since 9.2.0 use IAppData */ public function getAppFolder() { $dir = '/' . \OC_App::getCurrentApp(); diff --git a/lib/public/IServerContainer.php b/lib/public/IServerContainer.php index b736af2899a78..354e39bd8f981 100644 --- a/lib/public/IServerContainer.php +++ b/lib/public/IServerContainer.php @@ -115,6 +115,7 @@ public function getUserFolder($userId = null); * * @return \OCP\Files\Folder * @since 6.0.0 + * @deprecated since 9.2.0 use IAppData */ public function getAppFolder(); From 735abbc8fbb982c01cc327f9a858a45b084e81dd Mon Sep 17 00:00:00 2001 From: Roeland Jago Douma Date: Wed, 14 Sep 2016 20:15:15 +0200 Subject: [PATCH 09/14] Use a backgroundjob to move avatars Signed-off-by: Roeland Jago Douma --- .../Repair/NC11/MoveAvatarBackgroundJob.php | 110 ++++++++++++++++++ lib/private/Repair/NC11/MoveAvatars.php | 86 ++------------ 2 files changed, 118 insertions(+), 78 deletions(-) create mode 100644 lib/private/Repair/NC11/MoveAvatarBackgroundJob.php diff --git a/lib/private/Repair/NC11/MoveAvatarBackgroundJob.php b/lib/private/Repair/NC11/MoveAvatarBackgroundJob.php new file mode 100644 index 0000000000000..4c16196f6e9ec --- /dev/null +++ b/lib/private/Repair/NC11/MoveAvatarBackgroundJob.php @@ -0,0 +1,110 @@ + + * + * @author Roeland Jago Douma + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +namespace OC\Repair\NC11; + +use OC\BackgroundJob\QueuedJob; +use OCP\Files\File; +use OCP\Files\Folder; +use OCP\Files\IAppData; +use OCP\Files\IRootFolder; +use OCP\Files\NotFoundException; +use OCP\ILogger; +use OCP\IUser; +use OCP\IUserManager; + +class MoveAvatarsBackgroundJob extends QueuedJob { + + /** @var IUserManager */ + private $userManager; + + /** @var IRootFolder */ + private $rootFolder; + + /** @var IAppData */ + private $appData; + + /** @var ILogger */ + private $logger; + + /** + * MoveAvatars constructor. + * + * @param IUserManager $userManager + * @param IRootFolder $rootFolder + * @param ILogger $logger + */ + public function __construct(IUserManager $userManager, + IRootFolder $rootFolder, + ILogger $logger) { + $this->userManager = $userManager; + $this->rootFolder = $rootFolder; + $this->logger = $logger; + $this->appData = \OC::$server->getAppDataDir('avatar'); + } + + public function run($arguments) { + $this->logger->info('Started migrating avatars to AppData folder'); + $this->moveAvatars(); + $this->logger->info('All avatars migrated to AppData folder'); + } + + private function moveAvatars() { + $counter = 0; + $this->userManager->callForAllUsers(function (IUser $user) use ($counter) { + if ($user->getLastLogin() !== 0) { + $uid = $user->getUID(); + + \OC\Files\Filesystem::initMountPoints($uid); + /** @var Folder $userFolder */ + $userFolder = $this->rootFolder->get($uid); + + try { + $userData = $this->appData->getFolder($uid); + } catch (NotFoundException $e) { + $userData = $this->appData->newFolder($uid); + } + + + $regex = '/^avatar\.([0-9]+\.)?(jpg|png)$/'; + $avatars = $userFolder->getDirectoryListing(); + + foreach ($avatars as $avatar) { + /** @var File $avatar */ + if (preg_match($regex, $avatar->getName())) { + /* + * This is not the most effective but it is the most abstract way + * to handle this. Avatars should be small anyways. + */ + $newAvatar = $userData->newFile($avatar->getName()); + $newAvatar->putContent($avatar->getContent()); + $avatar->delete(); + } + } + } + $counter++; + if ($counter % 100) { + $this->logger->info('{amount} avatars migrated', ['amount' => $counter]); + } + }); + } +} diff --git a/lib/private/Repair/NC11/MoveAvatars.php b/lib/private/Repair/NC11/MoveAvatars.php index d0d78cb1fd603..44402b1be4f5e 100644 --- a/lib/private/Repair/NC11/MoveAvatars.php +++ b/lib/private/Repair/NC11/MoveAvatars.php @@ -23,26 +23,14 @@ namespace OC\Repair\NC11; use OC\SystemConfig; -use OCP\Files\File; -use OCP\Files\Folder; -use OCP\Files\IAppData; -use OCP\Files\IRootFolder; -use OCP\Files\NotFoundException; -use OCP\IUser; -use OCP\IUserManager; +use OCP\BackgroundJob\IJobList; use OCP\Migration\IOutput; use OCP\Migration\IRepairStep; class MoveAvatars implements IRepairStep { - /** @var IUserManager */ - private $userManager; - - /** @var IRootFolder */ - private $rootFolder; - - /** @var IAppData */ - private $appData; + /** @var IJobList */ + private $jobList; /** @var SystemConfig */ private $systemConfig; @@ -50,18 +38,12 @@ class MoveAvatars implements IRepairStep { /** * MoveAvatars constructor. * - * @param IUserManager $userManager - * @param IRootFolder $rootFolder - * @param IAppData $appData + * @param IJobList $jobList * @param SystemConfig $systemConfig */ - public function __construct(IUserManager $userManager, - IRootFolder $rootFolder, - IAppData $appData, + public function __construct(IJobList $jobList, SystemConfig $systemConfig) { - $this->userManager = $userManager; - $this->rootFolder = $rootFolder; - $this->appData = $appData; + $this->jobList = $jobList; $this->systemConfig = $systemConfig; } @@ -69,66 +51,14 @@ public function __construct(IUserManager $userManager, * @return string */ public function getName() { - return 'Move avatars to AppData folder'; + return 'Add mover avatar background job'; } public function run(IOutput $output) { if ($this->systemConfig->getValue('enable_avatars', true) === false) { $output->info('Avatars are disabled'); } else { - $output->startProgress($this->userCount()); - $this->moveAvatar($output); - $output->finishProgress(); - } - } - - private function moveAvatar(IOutput $output) { - $this->userManager->callForAllUsers(function (IUser $user) use ($output) { - if ($user->getLastLogin() !== 0) { - $uid = $user->getUID(); - - \OC\Files\Filesystem::initMountPoints($uid); - /** @var Folder $userFolder */ - $userFolder = $this->rootFolder->get($uid); - - try { - $userData = $this->appData->getFolder($uid); - } catch (NotFoundException $e) { - $userData = $this->appData->newFolder($uid); - } - - - $regex = '/^avatar\.([0-9]+\.)?(jpg|png)$/'; - $avatars = $userFolder->getDirectoryListing(); - - foreach ($avatars as $avatar) { - /** @var File $avatar */ - if (preg_match($regex, $avatar->getName())) { - /* - * This is not the most effective but it is the most abstract way - * to handle this. Avatars should be small anyways. - */ - $newAvatar = $userData->newFile($avatar->getName()); - $newAvatar->putContent($avatar->getContent()); - $avatar->delete(); - } - } - } - $output->advance(); - }); - } - - /** - * @return int - */ - private function userCount() { - $backends = $this->userManager->countUsers(); - $count = 0; - - foreach ($backends as $backend => $amount) { - $count += $amount; + $this->jobList->add(MoveAvatarsBackgroundJob::class); } - - return $count; } } From 537af9bedd5b6e893df2fb862217ecc8fda4d6de Mon Sep 17 00:00:00 2001 From: Roeland Jago Douma Date: Wed, 14 Sep 2016 21:55:54 +0200 Subject: [PATCH 10/14] Update autoloader Signed-off-by: Roeland Jago Douma --- lib/composer/composer/autoload_classmap.php | 1 + lib/composer/composer/autoload_static.php | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index f4e8644f9ad2d..0ff46de07de0f 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -647,6 +647,7 @@ 'OC\\Repair\\InnoDB' => $baseDir . '/lib/private/Repair/InnoDB.php', 'OC\\Repair\\MoveUpdaterStepFile' => $baseDir . '/lib/private/Repair/MoveUpdaterStepFile.php', 'OC\\Repair\\NC11\\MoveAvatars' => $baseDir . '/lib/private/Repair/NC11/MoveAvatars.php', + 'OC\\Repair\\NC11\\MoveAvatarsBackgroundJob' => $baseDir . '/lib/private/Repair/NC11/MoveAvatarBackgroundJob.php', 'OC\\Repair\\OldGroupMembershipShares' => $baseDir . '/lib/private/Repair/OldGroupMembershipShares.php', 'OC\\Repair\\Preview' => $baseDir . '/lib/private/Repair/Preview.php', 'OC\\Repair\\RemoveGetETagEntries' => $baseDir . '/lib/private/Repair/RemoveGetETagEntries.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 7d3edcc2638c5..24058a22edb3a 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -677,6 +677,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Repair\\InnoDB' => __DIR__ . '/../../..' . '/lib/private/Repair/InnoDB.php', 'OC\\Repair\\MoveUpdaterStepFile' => __DIR__ . '/../../..' . '/lib/private/Repair/MoveUpdaterStepFile.php', 'OC\\Repair\\NC11\\MoveAvatars' => __DIR__ . '/../../..' . '/lib/private/Repair/NC11/MoveAvatars.php', + 'OC\\Repair\\NC11\\MoveAvatarsBackgroundJob' => __DIR__ . '/../../..' . '/lib/private/Repair/NC11/MoveAvatarBackgroundJob.php', 'OC\\Repair\\OldGroupMembershipShares' => __DIR__ . '/../../..' . '/lib/private/Repair/OldGroupMembershipShares.php', 'OC\\Repair\\Preview' => __DIR__ . '/../../..' . '/lib/private/Repair/Preview.php', 'OC\\Repair\\RemoveGetETagEntries' => __DIR__ . '/../../..' . '/lib/private/Repair/RemoveGetETagEntries.php', From 2578a8157386612dd225d19f44b208ccde6e8fad Mon Sep 17 00:00:00 2001 From: Roeland Jago Douma Date: Wed, 14 Sep 2016 21:59:33 +0200 Subject: [PATCH 11/14] Fix repair Signed-off-by: Roeland Jago Douma --- lib/private/Repair.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/private/Repair.php b/lib/private/Repair.php index 0af1dc9cc7443..2ba118b9c3736 100644 --- a/lib/private/Repair.php +++ b/lib/private/Repair.php @@ -151,9 +151,7 @@ public static function getRepairSteps() { ), new MoveUpdaterStepFile(\OC::$server->getConfig()), new MoveAvatars( - \OC::$server->getUserManager(), - \OC::$server->getRootFolder(), - \OC::$server->getAppDataDir('avatar'), + \OC::$server->getJobList(), \OC::$server->getSystemConfig() ), ]; From a7be37d73539bac8fd634279e225051b7ab9a8dd Mon Sep 17 00:00:00 2001 From: Roeland Jago Douma Date: Mon, 3 Oct 2016 14:20:33 +0200 Subject: [PATCH 12/14] DI fails for bg job Signed-off-by: Roeland Jago Douma --- .../Repair/NC11/MoveAvatarBackgroundJob.php | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/lib/private/Repair/NC11/MoveAvatarBackgroundJob.php b/lib/private/Repair/NC11/MoveAvatarBackgroundJob.php index 4c16196f6e9ec..993235146c9cf 100644 --- a/lib/private/Repair/NC11/MoveAvatarBackgroundJob.php +++ b/lib/private/Repair/NC11/MoveAvatarBackgroundJob.php @@ -48,17 +48,11 @@ class MoveAvatarsBackgroundJob extends QueuedJob { /** * MoveAvatars constructor. - * - * @param IUserManager $userManager - * @param IRootFolder $rootFolder - * @param ILogger $logger */ - public function __construct(IUserManager $userManager, - IRootFolder $rootFolder, - ILogger $logger) { - $this->userManager = $userManager; - $this->rootFolder = $rootFolder; - $this->logger = $logger; + public function __construct() { + $this->userManager = \OC::$server->getUserManager(); + $this->rootFolder = \OC::$server->getRootFolder(); + $this->logger = \OC::$server->getLogger(); $this->appData = \OC::$server->getAppDataDir('avatar'); } From 7512683ea92127b06cd3a77e7f53d213d9e2fdb6 Mon Sep 17 00:00:00 2001 From: Roeland Jago Douma Date: Tue, 4 Oct 2016 13:11:33 +0200 Subject: [PATCH 13/14] Fix avatar tests Signed-off-by: Roeland Jago Douma --- tests/lib/AvatarManagerTest.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/lib/AvatarManagerTest.php b/tests/lib/AvatarManagerTest.php index 0ad998af6d5b8..8ccc51d12e0f6 100644 --- a/tests/lib/AvatarManagerTest.php +++ b/tests/lib/AvatarManagerTest.php @@ -26,8 +26,8 @@ use OC\Avatar; use OC\AvatarManager; -use OCP\Files\Folder; -use OCP\Files\IRootFolder; +use OCP\Files\IAppData; +use OCP\Files\SimpleFS\ISimpleFolder; use OCP\IConfig; use OCP\IL10N; use OCP\ILogger; @@ -40,8 +40,8 @@ class AvatarManagerTest extends \Test\TestCase { /** @var IUserManager|\PHPUnit_Framework_MockObject_MockObject */ private $userManager; - /** @var IRootFolder|\PHPUnit_Framework_MockObject_MockObject */ - private $rootFolder; + /** @var IAppData|\PHPUnit_Framework_MockObject_MockObject */ + private $appData; /** @var IL10N|\PHPUnit_Framework_MockObject_MockObject */ private $l10n; /** @var ILogger|\PHPUnit_Framework_MockObject_MockObject */ @@ -55,14 +55,14 @@ public function setUp() { parent::setUp(); $this->userManager = $this->createMock(IUserManager::class); - $this->rootFolder = $this->createMock(IRootFolder::class); + $this->appData = $this->createMock(IAppData::class); $this->l10n = $this->createMock(IL10N::class); $this->logger = $this->createMock(ILogger::class); $this->config = $this->createMock(IConfig::class); $this->avatarManager = new AvatarManager( $this->userManager, - $this->rootFolder, + $this->appData, $this->l10n, $this->logger, $this->config @@ -94,11 +94,11 @@ public function testGetAvatarValidUser() { ->method('get') ->with('valid-user') ->willReturn($user); - $folder = $this->createMock(Folder::class); - $this->rootFolder + $folder = $this->createMock(ISimpleFolder::class); + $this->appData ->expects($this->once()) - ->method('get') - ->with('/valid-user') + ->method('getFolder') + ->with('valid-user') ->willReturn($folder); $expected = new Avatar($folder, $this->l10n, $user, $this->logger, $this->config);; From 316db0a97b0212aca2f36b4ee09675bf9809f4dd Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Wed, 5 Oct 2016 23:46:21 +0200 Subject: [PATCH 14/14] add proper exception documentation for ISimpleFS interface Signed-off-by: Morris Jobke --- lib/public/Files/SimpleFS/ISimpleRoot.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/public/Files/SimpleFS/ISimpleRoot.php b/lib/public/Files/SimpleFS/ISimpleRoot.php index a9b00540eb234..c2f9d4ff05d08 100644 --- a/lib/public/Files/SimpleFS/ISimpleRoot.php +++ b/lib/public/Files/SimpleFS/ISimpleRoot.php @@ -23,6 +23,7 @@ namespace OCP\Files\SimpleFS; use OCP\Files\NotFoundException; +use OCP\Files\NotPermittedException; /** * Interface ISimpleRoot @@ -38,6 +39,7 @@ interface ISimpleRoot { * @param string $name * @return ISimpleFolder * @throws NotFoundException + * @throws \RuntimeException * @since 9.2.0 */ public function getFolder($name); @@ -46,6 +48,8 @@ public function getFolder($name); * Get all the Folders * * @return ISimpleFolder[] + * @throws NotFoundException + * @throws \RuntimeException * @since 9.2.0 */ public function getDirectoryListing(); @@ -55,6 +59,8 @@ public function getDirectoryListing(); * * @param string $name * @return ISimpleFolder + * @throws NotPermittedException + * @throws \RuntimeException * @since 9.2.0 */ public function newFolder($name);