|
1 | | -<?php |
| 1 | +<?php declare(strict_types=1); |
| 2 | + |
2 | 3 | /** |
3 | 4 | * @copyright Copyright (c) 2016, ownCloud, Inc. |
4 | 5 | * |
|
28 | 29 |
|
29 | 30 | namespace OCA\Files\Command; |
30 | 31 |
|
31 | | -use OC\Files\Filesystem; |
32 | | -use OC\Files\View; |
33 | | -use OCP\Files\FileInfo; |
34 | | -use OCP\Files\IHomeStorage; |
35 | | -use OCP\Files\IRootFolder; |
36 | | -use OCP\Files\Mount\IMountManager; |
| 32 | +use OCA\Files\Exception\TransferOwnershipException; |
| 33 | +use OCA\Files\Service\OwnershipTransferService; |
37 | 34 | use OCP\IUser; |
38 | 35 | use OCP\IUserManager; |
39 | | -use OCP\Share\IManager; |
40 | | -use OCP\Share\IShare; |
41 | 36 | use Symfony\Component\Console\Command\Command; |
42 | | -use Symfony\Component\Console\Helper\ProgressBar; |
43 | 37 | use Symfony\Component\Console\Input\InputArgument; |
44 | 38 | use Symfony\Component\Console\Input\InputInterface; |
45 | 39 | use Symfony\Component\Console\Input\InputOption; |
46 | 40 | use Symfony\Component\Console\Output\OutputInterface; |
47 | 41 |
|
48 | 42 | class TransferOwnership extends Command { |
49 | 43 |
|
50 | | - /** @var IUserManager $userManager */ |
| 44 | + /** @var IUserManager */ |
51 | 45 | private $userManager; |
52 | 46 |
|
53 | | - /** @var IManager */ |
54 | | - private $shareManager; |
55 | | - |
56 | | - /** @var IMountManager */ |
57 | | - private $mountManager; |
58 | | - |
59 | | - /** @var FileInfo[] */ |
60 | | - private $allFiles = []; |
61 | | - |
62 | | - /** @var FileInfo[] */ |
63 | | - private $encryptedFiles = []; |
64 | | - |
65 | | - /** @var IShare[] */ |
66 | | - private $shares = []; |
67 | | - |
68 | | - /** @var string */ |
69 | | - private $sourceUser; |
70 | | - |
71 | | - /** @var string */ |
72 | | - private $destinationUser; |
73 | | - |
74 | | - /** @var string */ |
75 | | - private $sourcePath; |
76 | | - |
77 | | - /** @var string */ |
78 | | - private $finalTarget; |
| 47 | + /** @var OwnershipTransferService */ |
| 48 | + private $transferService; |
79 | 49 |
|
80 | 50 | public function __construct(IUserManager $userManager, |
81 | | - IManager $shareManager, |
82 | | - IMountManager $mountManager, |
83 | | - IRootFolder $rootFolder) { |
84 | | - $this->userManager = $userManager; |
85 | | - $this->shareManager = $shareManager; |
86 | | - $this->mountManager = $mountManager; |
| 51 | + OwnershipTransferService $transferService) { |
87 | 52 | parent::__construct(); |
| 53 | + $this->userManager = $userManager; |
| 54 | + $this->transferService = $transferService; |
88 | 55 | } |
89 | 56 |
|
90 | 57 | protected function configure() { |
@@ -115,192 +82,28 @@ protected function execute(InputInterface $input, OutputInterface $output) { |
115 | 82 | $destinationUserObject = $this->userManager->get($input->getArgument('destination-user')); |
116 | 83 |
|
117 | 84 | if (!$sourceUserObject instanceof IUser) { |
118 | | - $output->writeln("<error>Unknown source user $this->sourceUser</error>"); |
| 85 | + $output->writeln("<error>Unknown source user " . $input->getArgument('source-user') . "</error>"); |
119 | 86 | return 1; |
120 | 87 | } |
121 | 88 |
|
122 | 89 | if (!$destinationUserObject instanceof IUser) { |
123 | | - $output->writeln("<error>Unknown destination user $this->destinationUser</error>"); |
| 90 | + $output->writeln("<error>Unknown destination user " . $input->getArgument('destination-user') . "</error>"); |
124 | 91 | return 1; |
125 | 92 | } |
126 | 93 |
|
127 | | - $this->sourceUser = $sourceUserObject->getUID(); |
128 | | - $this->destinationUser = $destinationUserObject->getUID(); |
129 | | - $sourcePathOption = ltrim($input->getOption('path'), '/'); |
130 | | - $this->sourcePath = rtrim($this->sourceUser . '/files/' . $sourcePathOption, '/'); |
131 | | - |
132 | | - // target user has to be ready |
133 | | - if (!\OC::$server->getEncryptionManager()->isReadyForUser($this->destinationUser)) { |
134 | | - $output->writeln("<error>The target user is not ready to accept files. The user has at least to be logged in once.</error>"); |
135 | | - return 2; |
136 | | - } |
137 | | - |
138 | | - $date = date('Y-m-d H-i-s'); |
139 | | - $this->finalTarget = "$this->destinationUser/files/transferred from $this->sourceUser on $date"; |
140 | | - |
141 | | - // setup filesystem |
142 | | - Filesystem::initMountPoints($this->sourceUser); |
143 | | - Filesystem::initMountPoints($this->destinationUser); |
144 | | - |
145 | | - $view = new View(); |
146 | | - if (!$view->is_dir($this->sourcePath)) { |
147 | | - $output->writeln("<error>Unknown path provided: $sourcePathOption</error>"); |
148 | | - return 1; |
149 | | - } |
150 | | - |
151 | | - // analyse source folder |
152 | | - $this->analyse($output); |
153 | | - |
154 | | - // collect all the shares |
155 | | - $this->collectUsersShares($output); |
156 | | - |
157 | | - // transfer the files |
158 | | - $this->transfer($output); |
159 | | - |
160 | | - // restore the shares |
161 | | - $this->restoreShares($output); |
162 | | - } |
163 | | - |
164 | | - private function walkFiles(View $view, $path, \Closure $callBack) { |
165 | | - foreach ($view->getDirectoryContent($path) as $fileInfo) { |
166 | | - if (!$callBack($fileInfo)) { |
167 | | - return; |
168 | | - } |
169 | | - if ($fileInfo->getType() === FileInfo::TYPE_FOLDER) { |
170 | | - $this->walkFiles($view, $fileInfo->getPath(), $callBack); |
171 | | - } |
172 | | - } |
173 | | - } |
174 | | - |
175 | | - /** |
176 | | - * @param OutputInterface $output |
177 | | - * @throws \Exception |
178 | | - */ |
179 | | - protected function analyse(OutputInterface $output) { |
180 | | - $view = new View(); |
181 | | - |
182 | | - $output->writeln('Validating quota'); |
183 | | - $size = $view->getFileInfo($this->sourcePath, false)->getSize(false); |
184 | | - $freeSpace = $view->free_space($this->destinationUser . '/files/'); |
185 | | - if ($size > $freeSpace) { |
186 | | - $output->writeln('<error>Target user does not have enough free space available</error>'); |
187 | | - throw new \Exception('Execution terminated'); |
188 | | - } |
189 | | - |
190 | | - $output->writeln("Analysing files of $this->sourceUser ..."); |
191 | | - $progress = new ProgressBar($output); |
192 | | - $progress->start(); |
193 | | - $self = $this; |
194 | | - |
195 | | - $this->walkFiles($view, $this->sourcePath, |
196 | | - function (FileInfo $fileInfo) use ($progress, $self) { |
197 | | - if ($fileInfo->getType() === FileInfo::TYPE_FOLDER) { |
198 | | - // only analyze into folders from main storage, |
199 | | - if (!$fileInfo->getStorage()->instanceOfStorage(IHomeStorage::class)) { |
200 | | - return false; |
201 | | - } |
202 | | - return true; |
203 | | - } |
204 | | - $progress->advance(); |
205 | | - $this->allFiles[] = $fileInfo; |
206 | | - if ($fileInfo->isEncrypted()) { |
207 | | - $this->encryptedFiles[] = $fileInfo; |
208 | | - } |
209 | | - return true; |
210 | | - }); |
211 | | - $progress->finish(); |
212 | | - $output->writeln(''); |
213 | | - |
214 | | - // no file is allowed to be encrypted |
215 | | - if (!empty($this->encryptedFiles)) { |
216 | | - $output->writeln("<error>Some files are encrypted - please decrypt them first</error>"); |
217 | | - foreach($this->encryptedFiles as $encryptedFile) { |
218 | | - /** @var FileInfo $encryptedFile */ |
219 | | - $output->writeln(" " . $encryptedFile->getPath()); |
220 | | - } |
221 | | - throw new \Exception('Execution terminated.'); |
222 | | - } |
223 | | - } |
224 | | - |
225 | | - /** |
226 | | - * @param OutputInterface $output |
227 | | - */ |
228 | | - private function collectUsersShares(OutputInterface $output) { |
229 | | - $output->writeln("Collecting all share information for files and folder of $this->sourceUser ..."); |
230 | | - |
231 | | - $progress = new ProgressBar($output, count($this->shares)); |
232 | | - foreach([\OCP\Share::SHARE_TYPE_GROUP, \OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_LINK, \OCP\Share::SHARE_TYPE_REMOTE, \OCP\Share::SHARE_TYPE_ROOM] as $shareType) { |
233 | | - $offset = 0; |
234 | | - while (true) { |
235 | | - $sharePage = $this->shareManager->getSharesBy($this->sourceUser, $shareType, null, true, 50, $offset); |
236 | | - $progress->advance(count($sharePage)); |
237 | | - if (empty($sharePage)) { |
238 | | - break; |
239 | | - } |
240 | | - $this->shares = array_merge($this->shares, $sharePage); |
241 | | - $offset += 50; |
242 | | - } |
| 94 | + try { |
| 95 | + $this->transferService->transfer( |
| 96 | + $sourceUserObject, |
| 97 | + $destinationUserObject, |
| 98 | + ltrim($input->getOption('path'), '/'), |
| 99 | + $output |
| 100 | + ); |
| 101 | + } catch (TransferOwnershipException $e) { |
| 102 | + $output->writeln("<error>" . $e->getMessage() . "</error>"); |
| 103 | + return $e->getCode() !== 0 ? $e->getCode() : 1; |
243 | 104 | } |
244 | 105 |
|
245 | | - $progress->finish(); |
246 | | - $output->writeln(''); |
| 106 | + return 0; |
247 | 107 | } |
248 | 108 |
|
249 | | - /** |
250 | | - * @param OutputInterface $output |
251 | | - */ |
252 | | - protected function transfer(OutputInterface $output) { |
253 | | - $view = new View(); |
254 | | - $output->writeln("Transferring files to $this->finalTarget ..."); |
255 | | - |
256 | | - // This change will help user to transfer the folder specified using --path option. |
257 | | - // Else only the content inside folder is transferred which is not correct. |
258 | | - if($this->sourcePath !== "$this->sourceUser/files") { |
259 | | - $view->mkdir($this->finalTarget); |
260 | | - $this->finalTarget = $this->finalTarget . '/' . basename($this->sourcePath); |
261 | | - } |
262 | | - $view->rename($this->sourcePath, $this->finalTarget); |
263 | | - if (!is_dir("$this->sourceUser/files")) { |
264 | | - // because the files folder is moved away we need to recreate it |
265 | | - $view->mkdir("$this->sourceUser/files"); |
266 | | - } |
267 | | - } |
268 | | - |
269 | | - /** |
270 | | - * @param OutputInterface $output |
271 | | - */ |
272 | | - private function restoreShares(OutputInterface $output) { |
273 | | - $output->writeln("Restoring shares ..."); |
274 | | - $progress = new ProgressBar($output, count($this->shares)); |
275 | | - |
276 | | - foreach($this->shares as $share) { |
277 | | - try { |
278 | | - if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER && |
279 | | - $share->getSharedWith() === $this->destinationUser) { |
280 | | - // Unmount the shares before deleting, so we don't try to get the storage later on. |
281 | | - $shareMountPoint = $this->mountManager->find('/' . $this->destinationUser . '/files' . $share->getTarget()); |
282 | | - if ($shareMountPoint) { |
283 | | - $this->mountManager->removeMount($shareMountPoint->getMountPoint()); |
284 | | - } |
285 | | - $this->shareManager->deleteShare($share); |
286 | | - } else { |
287 | | - if ($share->getShareOwner() === $this->sourceUser) { |
288 | | - $share->setShareOwner($this->destinationUser); |
289 | | - } |
290 | | - if ($share->getSharedBy() === $this->sourceUser) { |
291 | | - $share->setSharedBy($this->destinationUser); |
292 | | - } |
293 | | - |
294 | | - $this->shareManager->updateShare($share); |
295 | | - } |
296 | | - } catch (\OCP\Files\NotFoundException $e) { |
297 | | - $output->writeln('<error>Share with id ' . $share->getId() . ' points at deleted file, skipping</error>'); |
298 | | - } catch (\Exception $e) { |
299 | | - $output->writeln('<error>Could not restore share with id ' . $share->getId() . ':' . $e->getTraceAsString() . '</error>'); |
300 | | - } |
301 | | - $progress->advance(); |
302 | | - } |
303 | | - $progress->finish(); |
304 | | - $output->writeln(''); |
305 | | - } |
306 | 109 | } |
0 commit comments