Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like Share20OCS 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
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 Share20OCS, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
46 | class Share20OCS { |
||
47 | |||
48 | /** @var IManager */ |
||
49 | private $shareManager; |
||
50 | /** @var IGroupManager */ |
||
51 | private $groupManager; |
||
52 | /** @var IUserManager */ |
||
53 | private $userManager; |
||
54 | /** @var IRequest */ |
||
55 | private $request; |
||
56 | /** @var IRootFolder */ |
||
57 | private $rootFolder; |
||
58 | /** @var IURLGenerator */ |
||
59 | private $urlGenerator; |
||
60 | /** @var IUser */ |
||
61 | private $currentUser; |
||
62 | /** @var IL10N */ |
||
63 | private $l; |
||
64 | |||
65 | /** |
||
66 | * Share20OCS constructor. |
||
67 | * |
||
68 | * @param IManager $shareManager |
||
69 | * @param IGroupManager $groupManager |
||
70 | * @param IUserManager $userManager |
||
71 | * @param IRequest $request |
||
72 | * @param IRootFolder $rootFolder |
||
73 | * @param IURLGenerator $urlGenerator |
||
74 | * @param IUser $currentUser |
||
75 | */ |
||
76 | public function __construct( |
||
77 | IManager $shareManager, |
||
78 | IGroupManager $groupManager, |
||
79 | IUserManager $userManager, |
||
80 | IRequest $request, |
||
81 | IRootFolder $rootFolder, |
||
82 | IURLGenerator $urlGenerator, |
||
83 | IUser $currentUser, |
||
84 | IL10N $l10n |
||
85 | ) { |
||
86 | $this->shareManager = $shareManager; |
||
87 | $this->userManager = $userManager; |
||
88 | $this->groupManager = $groupManager; |
||
89 | $this->request = $request; |
||
90 | $this->rootFolder = $rootFolder; |
||
91 | $this->urlGenerator = $urlGenerator; |
||
92 | $this->currentUser = $currentUser; |
||
93 | $this->l = $l10n; |
||
94 | } |
||
95 | |||
96 | /** |
||
97 | * Convert an IShare to an array for OCS output |
||
98 | * |
||
99 | * @param \OCP\Share\IShare $share |
||
100 | * @return array |
||
101 | * @throws NotFoundException In case the node can't be resolved. |
||
102 | */ |
||
103 | protected function formatShare(\OCP\Share\IShare $share) { |
||
174 | |||
175 | /** |
||
176 | * Get a specific share by id |
||
177 | * |
||
178 | * @param string $id |
||
179 | * @return \OC_OCS_Result |
||
180 | */ |
||
181 | public function getShare($id) { |
||
203 | |||
204 | /** |
||
205 | * Delete a share |
||
206 | * |
||
207 | * @param string $id |
||
208 | * @return \OC_OCS_Result |
||
209 | */ |
||
210 | public function deleteShare($id) { |
||
238 | |||
239 | /** |
||
240 | * @return \OC_OCS_Result |
||
241 | */ |
||
242 | public function createShare() { |
||
419 | |||
420 | /** |
||
421 | * @param \OCP\Files\File|\OCP\Files\Folder $node |
||
422 | * @return \OC_OCS_Result |
||
423 | */ |
||
424 | private function getSharedWithMe($node = null) { |
||
443 | |||
444 | /** |
||
445 | * @param \OCP\Files\Folder $folder |
||
446 | * @return \OC_OCS_Result |
||
447 | */ |
||
448 | private function getSharesInDir($folder) { |
||
476 | |||
477 | /** |
||
478 | * The getShares function. |
||
479 | * |
||
480 | * - Get shares by the current user |
||
481 | * - Get shares by the current user and reshares (?reshares=true) |
||
482 | * - Get shares with the current user (?shared_with_me=true) |
||
483 | * - Get shares for a specific path (?path=...) |
||
484 | * - Get all shares in a folder (?subfiles=true&path=..) |
||
485 | * |
||
486 | * @return \OC_OCS_Result |
||
487 | */ |
||
488 | public function getShares() { |
||
558 | |||
559 | /** |
||
560 | * @param int $id |
||
561 | * @return \OC_OCS_Result |
||
562 | */ |
||
563 | public function updateShare($id) { |
||
564 | if (!$this->shareManager->shareApiEnabled()) { |
||
565 | return new \OC_OCS_Result(null, 404, $this->l->t('Share API is disabled')); |
||
566 | } |
||
567 | |||
568 | try { |
||
569 | $share = $this->getShareById($id); |
||
570 | } catch (ShareNotFound $e) { |
||
571 | return new \OC_OCS_Result(null, 404, $this->l->t('Wrong share ID, share doesn\'t exist')); |
||
572 | } |
||
573 | |||
574 | $share->getNode()->lock(\OCP\Lock\ILockingProvider::LOCK_SHARED); |
||
575 | |||
576 | View Code Duplication | if (!$this->canAccessShare($share, false)) { |
|
577 | $share->getNode()->unlock(ILockingProvider::LOCK_SHARED); |
||
578 | return new \OC_OCS_Result(null, 404, $this->l->t('Wrong share ID, share doesn\'t exist')); |
||
579 | } |
||
580 | |||
581 | $permissions = $this->request->getParam('permissions', null); |
||
582 | $password = $this->request->getParam('password', null); |
||
583 | $publicUpload = $this->request->getParam('publicUpload', null); |
||
584 | $expireDate = $this->request->getParam('expireDate', null); |
||
585 | |||
586 | /* |
||
587 | * expirationdate, password and publicUpload only make sense for link shares |
||
588 | */ |
||
589 | if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) { |
||
590 | if ($permissions === null && $password === null && $publicUpload === null && $expireDate === null) { |
||
591 | $share->getNode()->unlock(ILockingProvider::LOCK_SHARED); |
||
592 | return new \OC_OCS_Result(null, 400, 'Wrong or no update parameter given'); |
||
593 | } |
||
594 | |||
595 | $newPermissions = null; |
||
596 | if ($publicUpload === 'true') { |
||
597 | $newPermissions = \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE; |
||
598 | } else if ($publicUpload === 'false') { |
||
599 | $newPermissions = \OCP\Constants::PERMISSION_READ; |
||
600 | } |
||
601 | |||
602 | if ($permissions !== null) { |
||
603 | $newPermissions = (int)$permissions; |
||
604 | } |
||
605 | |||
606 | if ($newPermissions !== null && |
||
607 | !in_array($newPermissions, [ |
||
608 | \OCP\Constants::PERMISSION_READ, |
||
609 | \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE, // legacy |
||
610 | \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE, // correct |
||
611 | \OCP\Constants::PERMISSION_CREATE, // hidden file list |
||
612 | ]) |
||
613 | ) { |
||
614 | $share->getNode()->unlock(ILockingProvider::LOCK_SHARED); |
||
615 | return new \OC_OCS_Result(null, 400, $this->l->t('Can\'t change permissions for public share links')); |
||
616 | } |
||
617 | |||
618 | if ( |
||
619 | // legacy |
||
620 | $newPermissions === (\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE) || |
||
621 | // correct |
||
622 | $newPermissions === (\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE) |
||
623 | ) { |
||
624 | View Code Duplication | if (!$this->shareManager->shareApiLinkAllowPublicUpload()) { |
|
625 | $share->getNode()->unlock(ILockingProvider::LOCK_SHARED); |
||
626 | return new \OC_OCS_Result(null, 403, $this->l->t('Public upload disabled by the administrator')); |
||
627 | } |
||
628 | |||
629 | View Code Duplication | if (!($share->getNode() instanceof \OCP\Files\Folder)) { |
|
630 | $share->getNode()->unlock(ILockingProvider::LOCK_SHARED); |
||
631 | return new \OC_OCS_Result(null, 400, $this->l->t('Public upload is only possible for publicly shared folders')); |
||
632 | } |
||
633 | |||
634 | // normalize to correct public upload permissions |
||
635 | $newPermissions = \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE; |
||
636 | } |
||
637 | |||
638 | if ($newPermissions !== null) { |
||
639 | $share->setPermissions($newPermissions); |
||
640 | } |
||
641 | |||
642 | if ($expireDate === '') { |
||
643 | $share->setExpirationDate(null); |
||
644 | View Code Duplication | } else if ($expireDate !== null) { |
|
645 | try { |
||
646 | $expireDate = $this->parseDate($expireDate); |
||
647 | } catch (\Exception $e) { |
||
648 | $share->getNode()->unlock(ILockingProvider::LOCK_SHARED); |
||
649 | return new \OC_OCS_Result(null, 400, $e->getMessage()); |
||
650 | } |
||
651 | $share->setExpirationDate($expireDate); |
||
652 | } |
||
653 | |||
654 | if ($password === '') { |
||
655 | $share->setPassword(null); |
||
656 | } else if ($password !== null) { |
||
657 | $share->setPassword($password); |
||
658 | } |
||
659 | |||
660 | } else { |
||
661 | // For other shares only permissions is valid. |
||
662 | if ($permissions === null) { |
||
663 | $share->getNode()->unlock(ILockingProvider::LOCK_SHARED); |
||
664 | return new \OC_OCS_Result(null, 400, $this->l->t('Wrong or no update parameter given')); |
||
665 | } else { |
||
666 | $permissions = (int)$permissions; |
||
667 | $share->setPermissions($permissions); |
||
668 | } |
||
669 | } |
||
670 | |||
671 | if ($permissions !== null) { |
||
672 | /* Check if this is an incomming share */ |
||
673 | $incomingShares = $this->shareManager->getSharedWith($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_USER, $share->getNode(), -1, 0); |
||
674 | $incomingShares = array_merge($incomingShares, $this->shareManager->getSharedWith($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_GROUP, $share->getNode(), -1, 0)); |
||
675 | |||
676 | if (!empty($incomingShares)) { |
||
677 | $maxPermissions = 0; |
||
678 | foreach ($incomingShares as $incomingShare) { |
||
679 | $maxPermissions |= $incomingShare->getPermissions(); |
||
680 | } |
||
681 | |||
682 | View Code Duplication | if ($share->getPermissions() & ~$maxPermissions) { |
|
683 | $share->getNode()->unlock(ILockingProvider::LOCK_SHARED); |
||
684 | return new \OC_OCS_Result(null, 404, $this->l->t('Cannot increase permissions')); |
||
685 | } |
||
686 | } |
||
687 | } |
||
688 | |||
689 | |||
690 | try { |
||
691 | $share = $this->shareManager->updateShare($share); |
||
692 | } catch (\Exception $e) { |
||
693 | $share->getNode()->unlock(ILockingProvider::LOCK_SHARED); |
||
694 | return new \OC_OCS_Result(null, 400, $e->getMessage()); |
||
695 | } |
||
696 | |||
697 | $share->getNode()->unlock(\OCP\Lock\ILockingProvider::LOCK_SHARED); |
||
698 | |||
699 | return new \OC_OCS_Result($this->formatShare($share)); |
||
700 | } |
||
701 | |||
702 | /** |
||
703 | * @param \OCP\Share\IShare $share |
||
704 | * @return bool |
||
705 | */ |
||
706 | protected function canAccessShare(\OCP\Share\IShare $share, $checkGroups = true) { |
||
707 | // A file with permissions 0 can't be accessed by us. So Don't show it |
||
708 | if ($share->getPermissions() === 0) { |
||
709 | return false; |
||
710 | } |
||
711 | |||
712 | // Owner of the file and the sharer of the file can always get share |
||
713 | if ($share->getShareOwner() === $this->currentUser->getUID() || |
||
714 | $share->getSharedBy() === $this->currentUser->getUID() |
||
715 | ) { |
||
716 | return true; |
||
717 | } |
||
718 | |||
719 | // If the share is shared with you (or a group you are a member of) |
||
720 | if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER && |
||
721 | $share->getSharedWith() === $this->currentUser->getUID()) { |
||
722 | return true; |
||
723 | } |
||
724 | |||
725 | if ($checkGroups && $share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) { |
||
726 | $sharedWith = $this->groupManager->get($share->getSharedWith()); |
||
727 | if ($sharedWith->inGroup($this->currentUser)) { |
||
728 | return true; |
||
729 | } |
||
730 | } |
||
731 | |||
732 | return false; |
||
733 | } |
||
734 | |||
735 | /** |
||
736 | * Make sure that the passed date is valid ISO 8601 |
||
737 | * So YYYY-MM-DD |
||
738 | * If not throw an exception |
||
739 | * |
||
740 | * @param string $expireDate |
||
741 | * |
||
742 | * @throws \Exception |
||
743 | * @return \DateTime |
||
744 | */ |
||
745 | private function parseDate($expireDate) { |
||
760 | |||
761 | /** |
||
762 | * Since we have multiple providers but the OCS Share API v1 does |
||
763 | * not support this we need to check all backends. |
||
764 | * |
||
765 | * @param string $id |
||
766 | * @return \OCP\Share\IShare |
||
767 | * @throws ShareNotFound |
||
768 | */ |
||
769 | private function getShareById($id) { |
||
785 | } |
||
786 |
This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.