| Total Complexity | 60 |
| Total Lines | 585 |
| Duplicated Lines | 0 % |
| Changes | 0 | ||
Complex classes like ShareController often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use ShareController, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 74 | class ShareController extends AuthPublicShareController { |
||
| 75 | |||
| 76 | /** @var IConfig */ |
||
| 77 | protected $config; |
||
| 78 | /** @var IUserManager */ |
||
| 79 | protected $userManager; |
||
| 80 | /** @var ILogger */ |
||
| 81 | protected $logger; |
||
| 82 | /** @var \OCP\Activity\IManager */ |
||
| 83 | protected $activityManager; |
||
| 84 | /** @var IPreview */ |
||
| 85 | protected $previewManager; |
||
| 86 | /** @var IRootFolder */ |
||
| 87 | protected $rootFolder; |
||
| 88 | /** @var FederatedShareProvider */ |
||
| 89 | protected $federatedShareProvider; |
||
| 90 | /** @var EventDispatcherInterface */ |
||
| 91 | protected $eventDispatcher; |
||
| 92 | /** @var IL10N */ |
||
| 93 | protected $l10n; |
||
| 94 | /** @var Defaults */ |
||
| 95 | protected $defaults; |
||
| 96 | /** @var ShareManager */ |
||
| 97 | protected $shareManager; |
||
| 98 | |||
| 99 | /** @var Share\IShare */ |
||
| 100 | protected $share; |
||
| 101 | |||
| 102 | /** |
||
| 103 | * @param string $appName |
||
| 104 | * @param IRequest $request |
||
| 105 | * @param IConfig $config |
||
| 106 | * @param IURLGenerator $urlGenerator |
||
| 107 | * @param IUserManager $userManager |
||
| 108 | * @param ILogger $logger |
||
| 109 | * @param \OCP\Activity\IManager $activityManager |
||
| 110 | * @param \OCP\Share\IManager $shareManager |
||
| 111 | * @param ISession $session |
||
| 112 | * @param IPreview $previewManager |
||
| 113 | * @param IRootFolder $rootFolder |
||
| 114 | * @param FederatedShareProvider $federatedShareProvider |
||
| 115 | * @param EventDispatcherInterface $eventDispatcher |
||
| 116 | * @param IL10N $l10n |
||
| 117 | * @param Defaults $defaults |
||
| 118 | */ |
||
| 119 | public function __construct(string $appName, |
||
| 120 | IRequest $request, |
||
| 121 | IConfig $config, |
||
| 122 | IURLGenerator $urlGenerator, |
||
| 123 | IUserManager $userManager, |
||
| 124 | ILogger $logger, |
||
| 125 | \OCP\Activity\IManager $activityManager, |
||
| 126 | ShareManager $shareManager, |
||
| 127 | ISession $session, |
||
| 128 | IPreview $previewManager, |
||
| 129 | IRootFolder $rootFolder, |
||
| 130 | FederatedShareProvider $federatedShareProvider, |
||
| 131 | EventDispatcherInterface $eventDispatcher, |
||
| 132 | IL10N $l10n, |
||
| 133 | Defaults $defaults) { |
||
| 134 | parent::__construct($appName, $request, $session, $urlGenerator); |
||
| 135 | |||
| 136 | $this->config = $config; |
||
| 137 | $this->userManager = $userManager; |
||
| 138 | $this->logger = $logger; |
||
| 139 | $this->activityManager = $activityManager; |
||
| 140 | $this->previewManager = $previewManager; |
||
| 141 | $this->rootFolder = $rootFolder; |
||
| 142 | $this->federatedShareProvider = $federatedShareProvider; |
||
| 143 | $this->eventDispatcher = $eventDispatcher; |
||
| 144 | $this->l10n = $l10n; |
||
| 145 | $this->defaults = $defaults; |
||
| 146 | $this->shareManager = $shareManager; |
||
| 147 | } |
||
| 148 | |||
| 149 | /** |
||
| 150 | * @PublicPage |
||
| 151 | * @NoCSRFRequired |
||
| 152 | * |
||
| 153 | * Show the authentication page |
||
| 154 | * The form has to submit to the authenticate method route |
||
| 155 | */ |
||
| 156 | public function showAuthenticate(): TemplateResponse { |
||
| 157 | $templateParameters = ['share' => $this->share]; |
||
| 158 | |||
| 159 | $event = new GenericEvent(null, $templateParameters); |
||
| 160 | $this->eventDispatcher->dispatch('OCA\Files_Sharing::loadAdditionalScripts::publicShareAuth', $event); |
||
| 161 | |||
| 162 | $response = new TemplateResponse('core', 'publicshareauth', $templateParameters, 'guest'); |
||
| 163 | if ($this->share->getSendPasswordByTalk()) { |
||
| 164 | $csp = new ContentSecurityPolicy(); |
||
| 165 | $csp->addAllowedConnectDomain('*'); |
||
| 166 | $csp->addAllowedMediaDomain('blob:'); |
||
| 167 | $csp->allowEvalScript(true); |
||
| 168 | $response->setContentSecurityPolicy($csp); |
||
| 169 | } |
||
| 170 | |||
| 171 | return $response; |
||
| 172 | } |
||
| 173 | |||
| 174 | /** |
||
| 175 | * The template to show when authentication failed |
||
| 176 | */ |
||
| 177 | protected function showAuthFailed(): TemplateResponse { |
||
| 178 | $templateParameters = ['share' => $this->share, 'wrongpw' => true]; |
||
| 179 | |||
| 180 | $event = new GenericEvent(null, $templateParameters); |
||
| 181 | $this->eventDispatcher->dispatch('OCA\Files_Sharing::loadAdditionalScripts::publicShareAuth', $event); |
||
| 182 | |||
| 183 | $response = new TemplateResponse('core', 'publicshareauth', $templateParameters, 'guest'); |
||
| 184 | if ($this->share->getSendPasswordByTalk()) { |
||
| 185 | $csp = new ContentSecurityPolicy(); |
||
| 186 | $csp->addAllowedConnectDomain('*'); |
||
| 187 | $csp->addAllowedMediaDomain('blob:'); |
||
| 188 | $csp->allowEvalScript(true); |
||
| 189 | $response->setContentSecurityPolicy($csp); |
||
| 190 | } |
||
| 191 | |||
| 192 | return $response; |
||
| 193 | } |
||
| 194 | |||
| 195 | protected function verifyPassword(string $password): bool { |
||
| 196 | return $this->shareManager->checkPassword($this->share, $password); |
||
| 197 | } |
||
| 198 | |||
| 199 | protected function getPasswordHash(): string { |
||
| 200 | return $this->share->getPassword(); |
||
| 201 | } |
||
| 202 | |||
| 203 | public function isValidToken(): bool { |
||
| 204 | try { |
||
| 205 | $this->share = $this->shareManager->getShareByToken($this->getToken()); |
||
| 206 | } catch (ShareNotFound $e) { |
||
| 207 | return false; |
||
| 208 | } |
||
| 209 | |||
| 210 | return true; |
||
| 211 | } |
||
| 212 | |||
| 213 | protected function isPasswordProtected(): bool { |
||
| 214 | return $this->share->getPassword() !== null; |
||
| 215 | } |
||
| 216 | |||
| 217 | protected function authSucceeded() { |
||
| 218 | // For share this was always set so it is still used in other apps |
||
| 219 | $this->session->set('public_link_authenticated', (string)$this->share->getId()); |
||
| 220 | } |
||
| 221 | |||
| 222 | protected function authFailed() { |
||
| 223 | $this->emitAccessShareHook($this->share, 403, 'Wrong password'); |
||
| 224 | } |
||
| 225 | |||
| 226 | /** |
||
| 227 | * throws hooks when a share is attempted to be accessed |
||
| 228 | * |
||
| 229 | * @param \OCP\Share\IShare|string $share the Share instance if available, |
||
| 230 | * otherwise token |
||
| 231 | * @param int $errorCode |
||
| 232 | * @param string $errorMessage |
||
| 233 | * @throws \OC\HintException |
||
| 234 | * @throws \OC\ServerNotAvailableException |
||
| 235 | */ |
||
| 236 | protected function emitAccessShareHook($share, $errorCode = 200, $errorMessage = '') { |
||
| 261 | } |
||
| 262 | } |
||
| 263 | |||
| 264 | /** |
||
| 265 | * Validate the permissions of the share |
||
| 266 | * |
||
| 267 | * @param Share\IShare $share |
||
| 268 | * @return bool |
||
| 269 | */ |
||
| 270 | private function validateShare(\OCP\Share\IShare $share) { |
||
| 272 | } |
||
| 273 | |||
| 274 | /** |
||
| 275 | * @PublicPage |
||
| 276 | * @NoCSRFRequired |
||
| 277 | * |
||
| 278 | |||
| 279 | * @param string $path |
||
| 280 | * @return TemplateResponse |
||
| 281 | * @throws NotFoundException |
||
| 282 | * @throws \Exception |
||
| 283 | */ |
||
| 284 | public function showShare($path = ''): TemplateResponse { |
||
| 285 | \OC_User::setIncognitoMode(true); |
||
| 286 | |||
| 287 | // Check whether share exists |
||
| 288 | try { |
||
| 289 | $share = $this->shareManager->getShareByToken($this->getToken()); |
||
| 290 | } catch (ShareNotFound $e) { |
||
| 291 | $this->emitAccessShareHook($this->getToken(), 404, 'Share not found'); |
||
| 292 | throw new NotFoundException(); |
||
| 293 | } |
||
| 294 | |||
| 295 | if (!$this->validateShare($share)) { |
||
| 296 | throw new NotFoundException(); |
||
| 297 | } |
||
| 298 | // We can't get the path of a file share |
||
| 299 | try { |
||
| 300 | if ($share->getNode() instanceof \OCP\Files\File && $path !== '') { |
||
| 301 | $this->emitAccessShareHook($share, 404, 'Share not found'); |
||
| 302 | throw new NotFoundException(); |
||
| 303 | } |
||
| 304 | } catch (\Exception $e) { |
||
| 305 | $this->emitAccessShareHook($share, 404, 'Share not found'); |
||
| 306 | throw $e; |
||
| 307 | } |
||
| 308 | |||
| 309 | $shareTmpl = []; |
||
| 310 | $shareTmpl['displayName'] = $this->userManager->get($share->getShareOwner())->getDisplayName(); |
||
| 311 | $shareTmpl['owner'] = $share->getShareOwner(); |
||
| 312 | $shareTmpl['filename'] = $share->getNode()->getName(); |
||
| 313 | $shareTmpl['directory_path'] = $share->getTarget(); |
||
| 314 | $shareTmpl['note'] = $share->getNote(); |
||
| 315 | $shareTmpl['mimetype'] = $share->getNode()->getMimetype(); |
||
| 316 | $shareTmpl['previewSupported'] = $this->previewManager->isMimeSupported($share->getNode()->getMimetype()); |
||
| 317 | $shareTmpl['dirToken'] = $this->getToken(); |
||
| 318 | $shareTmpl['sharingToken'] = $this->getToken(); |
||
| 319 | $shareTmpl['server2serversharing'] = $this->federatedShareProvider->isOutgoingServer2serverShareEnabled(); |
||
| 320 | $shareTmpl['protected'] = $share->getPassword() !== null ? 'true' : 'false'; |
||
|
|
|||
| 321 | $shareTmpl['dir'] = ''; |
||
| 322 | $shareTmpl['nonHumanFileSize'] = $share->getNode()->getSize(); |
||
| 323 | $shareTmpl['fileSize'] = \OCP\Util::humanFileSize($share->getNode()->getSize()); |
||
| 324 | $shareTmpl['hideDownload'] = $share->getHideDownload(); |
||
| 325 | |||
| 326 | // Show file list |
||
| 327 | $hideFileList = false; |
||
| 328 | if ($share->getNode() instanceof \OCP\Files\Folder) { |
||
| 329 | /** @var \OCP\Files\Folder $rootFolder */ |
||
| 330 | $rootFolder = $share->getNode(); |
||
| 331 | |||
| 332 | try { |
||
| 333 | $folderNode = $rootFolder->get($path); |
||
| 334 | } catch (\OCP\Files\NotFoundException $e) { |
||
| 335 | $this->emitAccessShareHook($share, 404, 'Share not found'); |
||
| 336 | throw new NotFoundException(); |
||
| 337 | } |
||
| 338 | |||
| 339 | $shareTmpl['dir'] = $rootFolder->getRelativePath($folderNode->getPath()); |
||
| 340 | |||
| 341 | /* |
||
| 342 | * The OC_Util methods require a view. This just uses the node API |
||
| 343 | */ |
||
| 344 | $freeSpace = $share->getNode()->getStorage()->free_space($share->getNode()->getInternalPath()); |
||
| 345 | if ($freeSpace < \OCP\Files\FileInfo::SPACE_UNLIMITED) { |
||
| 346 | $freeSpace = max($freeSpace, 0); |
||
| 347 | } else { |
||
| 348 | $freeSpace = (INF > 0) ? INF: PHP_INT_MAX; // work around https://bugs.php.net/bug.php?id=69188 |
||
| 349 | } |
||
| 350 | |||
| 351 | $hideFileList = !($share->getPermissions() & \OCP\Constants::PERMISSION_READ); |
||
| 352 | $maxUploadFilesize = $freeSpace; |
||
| 353 | |||
| 354 | $folder = new Template('files', 'list', ''); |
||
| 355 | $folder->assign('dir', $rootFolder->getRelativePath($folderNode->getPath())); |
||
| 356 | $folder->assign('dirToken', $this->getToken()); |
||
| 357 | $folder->assign('permissions', \OCP\Constants::PERMISSION_READ); |
||
| 358 | $folder->assign('isPublic', true); |
||
| 359 | $folder->assign('hideFileList', $hideFileList); |
||
| 360 | $folder->assign('publicUploadEnabled', 'no'); |
||
| 361 | $folder->assign('showgridview', true); |
||
| 362 | $folder->assign('uploadMaxFilesize', $maxUploadFilesize); |
||
| 363 | $folder->assign('uploadMaxHumanFilesize', \OCP\Util::humanFileSize($maxUploadFilesize)); |
||
| 364 | $folder->assign('freeSpace', $freeSpace); |
||
| 365 | $folder->assign('usedSpacePercent', 0); |
||
| 366 | $folder->assign('trash', false); |
||
| 367 | $shareTmpl['folder'] = $folder->fetchPage(); |
||
| 368 | } |
||
| 369 | |||
| 370 | $shareTmpl['hideFileList'] = $hideFileList; |
||
| 371 | $shareTmpl['shareOwner'] = $this->userManager->get($share->getShareOwner())->getDisplayName(); |
||
| 372 | $shareTmpl['downloadURL'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.downloadShare', ['token' => $this->getToken()]); |
||
| 373 | $shareTmpl['shareUrl'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $this->getToken()]); |
||
| 374 | $shareTmpl['maxSizeAnimateGif'] = $this->config->getSystemValue('max_filesize_animated_gifs_public_sharing', 10); |
||
| 375 | $shareTmpl['previewEnabled'] = $this->config->getSystemValue('enable_previews', true); |
||
| 376 | $shareTmpl['previewMaxX'] = $this->config->getSystemValue('preview_max_x', 1024); |
||
| 377 | $shareTmpl['previewMaxY'] = $this->config->getSystemValue('preview_max_y', 1024); |
||
| 378 | $shareTmpl['disclaimer'] = $this->config->getAppValue('core', 'shareapi_public_link_disclaimertext', null); |
||
| 379 | $shareTmpl['previewURL'] = $shareTmpl['downloadURL']; |
||
| 380 | $ogPreview = ''; |
||
| 381 | if ($shareTmpl['previewSupported']) { |
||
| 382 | $shareTmpl['previewImage'] = $this->urlGenerator->linkToRouteAbsolute( 'files_sharing.PublicPreview.getPreview', |
||
| 383 | ['x' => 200, 'y' => 200, 'file' => $shareTmpl['directory_path'], 'token' => $shareTmpl['dirToken']]); |
||
| 384 | $ogPreview = $shareTmpl['previewImage']; |
||
| 385 | |||
| 386 | // We just have direct previews for image files |
||
| 387 | if ($share->getNode()->getMimePart() === 'image') { |
||
| 388 | $shareTmpl['previewURL'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.publicpreview.directLink', ['token' => $this->getToken()]); |
||
| 389 | |||
| 390 | $ogPreview = $shareTmpl['previewURL']; |
||
| 391 | |||
| 392 | //Whatapp is kind of picky about their size requirements |
||
| 393 | if ($this->request->isUserAgent(['/^WhatsApp/'])) { |
||
| 394 | $ogPreview = $this->urlGenerator->linkToRouteAbsolute('files_sharing.PublicPreview.getPreview', [ |
||
| 395 | 'token' => $this->getToken(), |
||
| 396 | 'x' => 256, |
||
| 397 | 'y' => 256, |
||
| 398 | 'a' => true, |
||
| 399 | ]); |
||
| 400 | } |
||
| 401 | } |
||
| 402 | } else { |
||
| 403 | $shareTmpl['previewImage'] = $this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'favicon-fb.png')); |
||
| 404 | $ogPreview = $shareTmpl['previewImage']; |
||
| 405 | } |
||
| 406 | |||
| 407 | // Load files we need |
||
| 408 | \OCP\Util::addScript('files', 'file-upload'); |
||
| 409 | \OCP\Util::addStyle('files_sharing', 'publicView'); |
||
| 410 | \OCP\Util::addScript('files_sharing', 'public'); |
||
| 411 | \OCP\Util::addScript('files_sharing', 'templates'); |
||
| 412 | \OCP\Util::addScript('files_sharing', 'public_note'); |
||
| 413 | \OCP\Util::addScript('files', 'fileactions'); |
||
| 414 | \OCP\Util::addScript('files', 'fileactionsmenu'); |
||
| 415 | \OCP\Util::addScript('files', 'jquery.fileupload'); |
||
| 416 | \OCP\Util::addScript('files_sharing', 'files_drop'); |
||
| 417 | |||
| 418 | if (isset($shareTmpl['folder'])) { |
||
| 419 | // JS required for folders |
||
| 420 | \OCP\Util::addStyle('files', 'merged'); |
||
| 421 | \OCP\Util::addScript('files', 'filesummary'); |
||
| 422 | \OCP\Util::addScript('files', 'templates'); |
||
| 423 | \OCP\Util::addScript('files', 'breadcrumb'); |
||
| 424 | \OCP\Util::addScript('files', 'fileinfomodel'); |
||
| 425 | \OCP\Util::addScript('files', 'newfilemenu'); |
||
| 426 | \OCP\Util::addScript('files', 'files'); |
||
| 427 | \OCP\Util::addScript('files', 'filemultiselectmenu'); |
||
| 428 | \OCP\Util::addScript('files', 'filelist'); |
||
| 429 | \OCP\Util::addScript('files', 'keyboardshortcuts'); |
||
| 430 | } |
||
| 431 | |||
| 432 | // OpenGraph Support: http://ogp.me/ |
||
| 433 | \OCP\Util::addHeader('meta', ['property' => "og:title", 'content' => $shareTmpl['filename']]); |
||
| 434 | \OCP\Util::addHeader('meta', ['property' => "og:description", 'content' => $this->defaults->getName() . ($this->defaults->getSlogan() !== '' ? ' - ' . $this->defaults->getSlogan() : '')]); |
||
| 435 | \OCP\Util::addHeader('meta', ['property' => "og:site_name", 'content' => $this->defaults->getName()]); |
||
| 436 | \OCP\Util::addHeader('meta', ['property' => "og:url", 'content' => $shareTmpl['shareUrl']]); |
||
| 437 | \OCP\Util::addHeader('meta', ['property' => "og:type", 'content' => "object"]); |
||
| 438 | \OCP\Util::addHeader('meta', ['property' => "og:image", 'content' => $ogPreview]); |
||
| 439 | |||
| 440 | $this->eventDispatcher->dispatch('OCA\Files_Sharing::loadAdditionalScripts'); |
||
| 441 | |||
| 442 | $csp = new \OCP\AppFramework\Http\ContentSecurityPolicy(); |
||
| 443 | $csp->addAllowedFrameDomain('\'self\''); |
||
| 444 | |||
| 445 | $response = new PublicTemplateResponse($this->appName, 'public', $shareTmpl); |
||
| 446 | $response->setHeaderTitle($shareTmpl['filename']); |
||
| 447 | $response->setHeaderDetails($this->l10n->t('shared by %s', [$shareTmpl['displayName']])); |
||
| 448 | if (!$share->getHideDownload()) { |
||
| 449 | $response->setHeaderActions([ |
||
| 450 | new SimpleMenuAction('download', $this->l10n->t('Download'), 'icon-download-white', $shareTmpl['downloadURL'], 0), |
||
| 451 | new SimpleMenuAction('download', $this->l10n->t('Download'), 'icon-download', $shareTmpl['downloadURL'], 10, $shareTmpl['fileSize']), |
||
| 452 | new LinkMenuAction($this->l10n->t('Direct link'), 'icon-public', $shareTmpl['previewURL']), |
||
| 453 | new ExternalShareMenuAction($this->l10n->t('Add to your Nextcloud'), 'icon-external', $shareTmpl['owner'], $shareTmpl['displayName'], $shareTmpl['filename']), |
||
| 454 | ]); |
||
| 455 | } |
||
| 456 | |||
| 457 | $response->setContentSecurityPolicy($csp); |
||
| 458 | |||
| 459 | $this->emitAccessShareHook($share); |
||
| 460 | |||
| 461 | return $response; |
||
| 462 | } |
||
| 463 | |||
| 464 | /** |
||
| 465 | * @PublicPage |
||
| 466 | * @NoCSRFRequired |
||
| 467 | * |
||
| 468 | * @param string $token |
||
| 469 | * @param string $files |
||
| 470 | * @param string $path |
||
| 471 | * @param string $downloadStartSecret |
||
| 472 | * @return void|\OCP\AppFramework\Http\Response |
||
| 473 | * @throws NotFoundException |
||
| 474 | */ |
||
| 475 | public function downloadShare($token, $files = null, $path = '', $downloadStartSecret = '') { |
||
| 476 | \OC_User::setIncognitoMode(true); |
||
| 477 | |||
| 478 | $share = $this->shareManager->getShareByToken($token); |
||
| 479 | |||
| 480 | if(!($share->getPermissions() & \OCP\Constants::PERMISSION_READ)) { |
||
| 481 | return new \OCP\AppFramework\Http\DataResponse('Share is read-only'); |
||
| 482 | } |
||
| 483 | |||
| 484 | $files_list = null; |
||
| 485 | if (!is_null($files)) { // download selected files |
||
| 486 | $files_list = json_decode($files); |
||
| 487 | // in case we get only a single file |
||
| 488 | if ($files_list === null) { |
||
| 489 | $files_list = [$files]; |
||
| 490 | } |
||
| 491 | // Just in case $files is a single int like '1234' |
||
| 492 | if (!is_array($files_list)) { |
||
| 493 | $files_list = [$files_list]; |
||
| 494 | } |
||
| 495 | } |
||
| 496 | |||
| 497 | |||
| 498 | if (!$this->validateShare($share)) { |
||
| 499 | throw new NotFoundException(); |
||
| 500 | } |
||
| 501 | |||
| 502 | $userFolder = $this->rootFolder->getUserFolder($share->getShareOwner()); |
||
| 503 | $originalSharePath = $userFolder->getRelativePath($share->getNode()->getPath()); |
||
| 504 | |||
| 505 | |||
| 506 | // Single file share |
||
| 507 | if ($share->getNode() instanceof \OCP\Files\File) { |
||
| 508 | // Single file download |
||
| 509 | $this->singleFileDownloaded($share, $share->getNode()); |
||
| 510 | } |
||
| 511 | // Directory share |
||
| 512 | else { |
||
| 513 | /** @var \OCP\Files\Folder $node */ |
||
| 514 | $node = $share->getNode(); |
||
| 515 | |||
| 516 | // Try to get the path |
||
| 517 | if ($path !== '') { |
||
| 518 | try { |
||
| 519 | $node = $node->get($path); |
||
| 520 | } catch (NotFoundException $e) { |
||
| 521 | $this->emitAccessShareHook($share, 404, 'Share not found'); |
||
| 522 | return new NotFoundResponse(); |
||
| 523 | } |
||
| 524 | } |
||
| 525 | |||
| 526 | $originalSharePath = $userFolder->getRelativePath($node->getPath()); |
||
| 527 | |||
| 528 | if ($node instanceof \OCP\Files\File) { |
||
| 529 | // Single file download |
||
| 530 | $this->singleFileDownloaded($share, $share->getNode()); |
||
| 531 | } else if (!empty($files_list)) { |
||
| 532 | $this->fileListDownloaded($share, $files_list, $node); |
||
| 533 | } else { |
||
| 534 | // The folder is downloaded |
||
| 535 | $this->singleFileDownloaded($share, $share->getNode()); |
||
| 536 | } |
||
| 537 | } |
||
| 538 | |||
| 539 | /* FIXME: We should do this all nicely in OCP */ |
||
| 540 | OC_Util::tearDownFS(); |
||
| 541 | OC_Util::setupFS($share->getShareOwner()); |
||
| 542 | |||
| 543 | /** |
||
| 544 | * this sets a cookie to be able to recognize the start of the download |
||
| 545 | * the content must not be longer than 32 characters and must only contain |
||
| 546 | * alphanumeric characters |
||
| 547 | */ |
||
| 548 | if (!empty($downloadStartSecret) |
||
| 549 | && !isset($downloadStartSecret[32]) |
||
| 550 | && preg_match('!^[a-zA-Z0-9]+$!', $downloadStartSecret) === 1) { |
||
| 551 | |||
| 552 | // FIXME: set on the response once we use an actual app framework response |
||
| 553 | setcookie('ocDownloadStarted', $downloadStartSecret, time() + 20, '/'); |
||
| 554 | } |
||
| 555 | |||
| 556 | $this->emitAccessShareHook($share); |
||
| 557 | |||
| 558 | $server_params = array( 'head' => $this->request->getMethod() === 'HEAD' ); |
||
| 559 | |||
| 560 | /** |
||
| 561 | * Http range requests support |
||
| 562 | */ |
||
| 563 | if (isset($_SERVER['HTTP_RANGE'])) { |
||
| 564 | $server_params['range'] = $this->request->getHeader('Range'); |
||
| 565 | } |
||
| 566 | |||
| 567 | // download selected files |
||
| 568 | if (!is_null($files) && $files !== '') { |
||
| 569 | // FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well |
||
| 570 | // after dispatching the request which results in a "Cannot modify header information" notice. |
||
| 571 | OC_Files::get($originalSharePath, $files_list, $server_params); |
||
| 572 | exit(); |
||
| 573 | } else { |
||
| 574 | // FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well |
||
| 575 | // after dispatching the request which results in a "Cannot modify header information" notice. |
||
| 576 | OC_Files::get(dirname($originalSharePath), basename($originalSharePath), $server_params); |
||
| 577 | exit(); |
||
| 578 | } |
||
| 579 | } |
||
| 580 | |||
| 581 | /** |
||
| 582 | * create activity for every downloaded file |
||
| 583 | * |
||
| 584 | * @param Share\IShare $share |
||
| 585 | * @param array $files_list |
||
| 586 | * @param \OCP\Files\Folder $node |
||
| 587 | */ |
||
| 588 | protected function fileListDownloaded(Share\IShare $share, array $files_list, \OCP\Files\Folder $node) { |
||
| 589 | foreach ($files_list as $file) { |
||
| 590 | $subNode = $node->get($file); |
||
| 591 | $this->singleFileDownloaded($share, $subNode); |
||
| 592 | } |
||
| 593 | |||
| 594 | } |
||
| 595 | |||
| 596 | /** |
||
| 597 | * create activity if a single file was downloaded from a link share |
||
| 598 | * |
||
| 599 | * @param Share\IShare $share |
||
| 600 | */ |
||
| 601 | protected function singleFileDownloaded(Share\IShare $share, \OCP\Files\Node $node) { |
||
| 602 | |||
| 603 | $fileId = $node->getId(); |
||
| 604 | |||
| 605 | $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy()); |
||
| 606 | $userNodeList = $userFolder->getById($fileId); |
||
| 607 | $userNode = $userNodeList[0]; |
||
| 608 | $ownerFolder = $this->rootFolder->getUserFolder($share->getShareOwner()); |
||
| 609 | $userPath = $userFolder->getRelativePath($userNode->getPath()); |
||
| 610 | $ownerPath = $ownerFolder->getRelativePath($node->getPath()); |
||
| 611 | |||
| 612 | $parameters = [$userPath]; |
||
| 613 | |||
| 614 | if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) { |
||
| 615 | if ($node instanceof \OCP\Files\File) { |
||
| 616 | $subject = Downloads::SUBJECT_SHARED_FILE_BY_EMAIL_DOWNLOADED; |
||
| 617 | } else { |
||
| 618 | $subject = Downloads::SUBJECT_SHARED_FOLDER_BY_EMAIL_DOWNLOADED; |
||
| 619 | } |
||
| 620 | $parameters[] = $share->getSharedWith(); |
||
| 621 | } else { |
||
| 622 | if ($node instanceof \OCP\Files\File) { |
||
| 623 | $subject = Downloads::SUBJECT_PUBLIC_SHARED_FILE_DOWNLOADED; |
||
| 624 | } else { |
||
| 625 | $subject = Downloads::SUBJECT_PUBLIC_SHARED_FOLDER_DOWNLOADED; |
||
| 626 | } |
||
| 627 | } |
||
| 628 | |||
| 629 | $this->publishActivity($subject, $parameters, $share->getSharedBy(), $fileId, $userPath); |
||
| 630 | |||
| 631 | if ($share->getShareOwner() !== $share->getSharedBy()) { |
||
| 632 | $parameters[0] = $ownerPath; |
||
| 633 | $this->publishActivity($subject, $parameters, $share->getShareOwner(), $fileId, $ownerPath); |
||
| 634 | } |
||
| 635 | } |
||
| 636 | |||
| 637 | /** |
||
| 638 | * publish activity |
||
| 639 | * |
||
| 640 | * @param string $subject |
||
| 641 | * @param array $parameters |
||
| 642 | * @param string $affectedUser |
||
| 643 | * @param int $fileId |
||
| 644 | * @param string $filePath |
||
| 645 | */ |
||
| 646 | protected function publishActivity($subject, |
||
| 659 | } |
||
| 660 | |||
| 661 | |||
| 662 | } |
||
| 663 |