Completed
Push — master ( 8f8ae9...3a7ad7 )
by Roeland
08:35
created

Shared_Updater::postShareHook()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 16
rs 8.8571
cc 6
eloc 9
nc 5
nop 1
1
<?php
2
/**
3
 * @author Björn Schießle <[email protected]>
4
 * @author Joas Schilling <[email protected]>
5
 * @author Michael Gapczynski <[email protected]>
6
 * @author Morris Jobke <[email protected]>
7
 * @author Robin Appelman <[email protected]>
8
 * @author Roeland Jago Douma <[email protected]>
9
 * @author Vincent Petry <[email protected]>
10
 *
11
 * @copyright Copyright (c) 2016, ownCloud, Inc.
12
 * @license AGPL-3.0
13
 *
14
 * This code is free software: you can redistribute it and/or modify
15
 * it under the terms of the GNU Affero General Public License, version 3,
16
 * as published by the Free Software Foundation.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
 * GNU Affero General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU Affero General Public License, version 3,
24
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
25
 *
26
 */
27
28
namespace OC\Files\Cache;
29
30
class Shared_Updater {
31
32
	/**
33
	 * @param array $params
34
	 */
35
	static public function renameHook($params) {
36
		self::renameChildren($params['oldpath'], $params['newpath']);
37
		self::moveShareToShare($params['newpath']);
38
	}
39
40
	/**
41
	 * Fix for https://github.com/owncloud/core/issues/20769
42
	 *
43
	 * The owner is allowed to move their files (if they are shared) into a receiving folder
44
	 * In this case we need to update the parent of the moved share. Since they are
45
	 * effectively handing over ownership of the file the rest of the code needs to know
46
	 * they need to build up the reshare tree.
47
	 *
48
	 * @param string $path
49
	 */
50
	static private function moveShareToShare($path) {
51
		$userFolder = \OC::$server->getUserFolder();
52
53
		// If the user folder can't be constructed (e.g. link share) just return.
54
		if ($userFolder === null) {
55
			return;
56
		}
57
58
		$src = $userFolder->get($path);
59
60
		$shareManager = \OC::$server->getShareManager();
61
62
		$shares = $shareManager->getSharesBy($userFolder->getOwner()->getUID(), \OCP\Share::SHARE_TYPE_USER, $src, false, -1);
63
		$shares = array_merge($shares, $shareManager->getSharesBy($userFolder->getOwner()->getUID(), \OCP\Share::SHARE_TYPE_GROUP, $src, false, -1));
64
65
		// If the path we move is not a share we don't care
66
		if (empty($shares)) {
67
			return;
68
		}
69
70
		// Check if the destination is inside a share
71
		$mountManager = \OC::$server->getMountManager();
72
		$dstMount = $mountManager->find($src->getPath());
73
		if (!($dstMount instanceof \OCA\Files_Sharing\SharedMount)) {
74
			return;
75
		}
76
77
		$newOwner = $dstMount->getShare()->getShareOwner();
78
79
		//Ownership is moved over
80
		foreach ($shares as $share) {
81
			/** @var \OCP\Share\IShare $share */
82
			$share->setShareOwner($newOwner);
83
			$shareManager->updateShare($share);
84
		}
85
	}
86
87
	/**
88
	 * clean up oc_share table from files which are no longer exists
89
	 *
90
	 * This fixes issues from updates from files_sharing < 0.3.5.6 (ownCloud 4.5)
91
	 * It will just be called during the update of the app
92
	 */
93
	static public function fixBrokenSharesOnAppUpdate() {
94
		// delete all shares where the original file no longer exists
95
		$findAndRemoveShares = \OCP\DB::prepare('DELETE FROM `*PREFIX*share` ' .
96
			'WHERE `item_type` IN (\'file\', \'folder\') ' .
97
			'AND `file_source` NOT IN (SELECT `fileid` FROM `*PREFIX*filecache`)'
98
		);
99
		$findAndRemoveShares->execute(array());
100
	}
101
102
	/**
103
	 * rename mount point from the children if the parent was renamed
104
	 *
105
	 * @param string $oldPath old path relative to data/user/files
106
	 * @param string $newPath new path relative to data/user/files
107
	 */
108
	static private function renameChildren($oldPath, $newPath) {
109
110
		$absNewPath =  \OC\Files\Filesystem::normalizePath('/' . \OCP\User::getUser() . '/files/' . $newPath);
111
		$absOldPath =  \OC\Files\Filesystem::normalizePath('/' . \OCP\User::getUser() . '/files/' . $oldPath);
112
113
		$mountManager = \OC\Files\Filesystem::getMountManager();
114
		$mountedShares = $mountManager->findIn('/' . \OCP\User::getUser() . '/files/' . $oldPath);
115
		foreach ($mountedShares as $mount) {
116
			if ($mount->getStorage()->instanceOfStorage('OCA\Files_Sharing\ISharedStorage')) {
117
				$mountPoint = $mount->getMountPoint();
118
				$target = str_replace($absOldPath, $absNewPath, $mountPoint);
119
				$mount->moveMount($target);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class OC\Files\Mount\MountPoint as the method moveMount() does only exist in the following sub-classes of OC\Files\Mount\MountPoint: OCA\Files_External\Lib\PersonalMount, OCA\Files_Sharing\External\Mount, OCA\Files_Sharing\SharedMount. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
120
			}
121
		}
122
	}
123
124
}
125