Completed
Push — stable12 ( a63043...ca2f2c )
by Morris
15:51
created

MountProvider::getMountsForUser()   B

Complexity

Conditions 5
Paths 10

Size

Total Lines 52

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
nc 10
nop 2
dl 0
loc 52
rs 8.7361
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Morris Jobke <[email protected]>
6
 * @author Robin Appelman <[email protected]>
7
 * @author Roeland Jago Douma <[email protected]>
8
 * @author Vincent Petry <[email protected]>
9
 *
10
 * @license AGPL-3.0
11
 *
12
 * This code is free software: you can redistribute it and/or modify
13
 * it under the terms of the GNU Affero General Public License, version 3,
14
 * as published by the Free Software Foundation.
15
 *
16
 * This program is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
 * GNU Affero General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU Affero General Public License, version 3,
22
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
23
 *
24
 */
25
26
namespace OCA\Files_Sharing;
27
28
use OC\Cache\CappedMemoryCache;
29
use OC\Files\View;
30
use OCP\Files\Config\IMountProvider;
31
use OCP\Files\Storage\IStorageFactory;
32
use OCP\IConfig;
33
use OCP\ILogger;
34
use OCP\IUser;
35
use OCP\Share\IManager;
36
37
class MountProvider implements IMountProvider {
38
	/**
39
	 * @var \OCP\IConfig
40
	 */
41
	protected $config;
42
43
	/**
44
	 * @var IManager
45
	 */
46
	protected $shareManager;
47
48
	/**
49
	 * @var ILogger
50
	 */
51
	protected $logger;
52
53
	/**
54
	 * @param \OCP\IConfig $config
55
	 * @param IManager $shareManager
56
	 * @param ILogger $logger
57
	 */
58
	public function __construct(IConfig $config, IManager $shareManager, ILogger $logger) {
59
		$this->config = $config;
60
		$this->shareManager = $shareManager;
61
		$this->logger = $logger;
62
	}
63
64
65
	/**
66
	 * Get all mountpoints applicable for the user and check for shares where we need to update the etags
67
	 *
68
	 * @param \OCP\IUser $user
69
	 * @param \OCP\Files\Storage\IStorageFactory $storageFactory
70
	 * @return \OCP\Files\Mount\IMountPoint[]
71
	 */
72
	public function getMountsForUser(IUser $user, IStorageFactory $storageFactory) {
73
74
		$shares = $this->shareManager->getSharedWith($user->getUID(), \OCP\Share::SHARE_TYPE_USER, null, -1);
75
		$shares = array_merge($shares, $this->shareManager->getSharedWith($user->getUID(), \OCP\Share::SHARE_TYPE_GROUP, null, -1));
76
		$shares = array_merge($shares, $this->shareManager->getSharedWith($user->getUID(), \OCP\Share::SHARE_TYPE_CIRCLE, null, -1));
77
78
		// filter out excluded shares and group shares that includes self
79
		$shares = array_filter($shares, function (\OCP\Share\IShare $share) use ($user) {
80
			return $share->getPermissions() > 0 && $share->getShareOwner() !== $user->getUID();
81
		});
82
83
		$superShares = $this->buildSuperShares($shares, $user);
84
85
		$mounts = [];
86
		$view = new View('/' . $user->getUID() . '/files');
87
		$ownerViews = [];
88
		$sharingDisabledForUser = $this->shareManager->sharingDisabledForUser($user->getUID());
89
		$foldersExistCache = new CappedMemoryCache();
90
		foreach ($superShares as $share) {
91
			try {
92
				/** @var \OCP\Share\IShare $parentShare */
93
				$parentShare = $share[0];
94
				$owner = $parentShare->getShareOwner();
95
				if (!isset($ownerViews[$owner])) {
96
					$ownerViews[$owner] = new View('/' . $parentShare->getShareOwner() . '/files');
97
				}
98
				$mount = new SharedMount(
99
					'\OCA\Files_Sharing\SharedStorage',
100
					$mounts,
101
					[
102
						'user' => $user->getUID(),
103
						// parent share
104
						'superShare' => $parentShare,
105
						// children/component of the superShare
106
						'groupedShares' => $share[1],
107
						'ownerView' => $ownerViews[$owner],
108
						'sharingDisabledForUser' => $sharingDisabledForUser
109
					],
110
					$storageFactory,
111
					$view,
112
					$foldersExistCache
113
				);
114
				$mounts[$mount->getMountPoint()] = $mount;
115
			} catch (\Exception $e) {
116
				$this->logger->logException($e);
117
				$this->logger->error('Error while trying to create shared mount');
118
			}
119
		}
120
121
		// array_filter removes the null values from the array
122
		return array_values(array_filter($mounts));
123
	}
124
125
	/**
126
	 * Groups shares by path (nodeId) and target path
127
	 *
128
	 * @param \OCP\Share\IShare[] $shares
129
	 * @return \OCP\Share\IShare[][] array of grouped shares, each element in the
130
	 * array is a group which itself is an array of shares
131
	 */
132
	private function groupShares(array $shares) {
133
		$tmp = [];
134
135
		foreach ($shares as $share) {
136
			if (!isset($tmp[$share->getNodeId()])) {
137
				$tmp[$share->getNodeId()] = [];
138
			}
139
			$tmp[$share->getNodeId()][] = $share;
140
		}
141
142
		$result = [];
143
		// sort by stime, the super share will be based on the least recent share
144
		foreach ($tmp as &$tmp2) {
145
			@usort($tmp2, function($a, $b) {
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
146
				if ($a->getShareTime() <= $b->getShareTime()) {
147
					return -1;
148
				}
149
				return 1;
150
			});
151
			$result[] = $tmp2;
152
		}
153
154
		return array_values($result);
155
	}
156
157
	/**
158
	 * Build super shares (virtual share) by grouping them by node id and target,
159
	 * then for each group compute the super share and return it along with the matching
160
	 * grouped shares. The most permissive permissions are used based on the permissions
161
	 * of all shares within the group.
162
	 *
163
	 * @param \OCP\Share\IShare[] $allShares
164
	 * @param \OCP\IUser $user user
165
	 * @return array Tuple of [superShare, groupedShares]
166
	 */
167
	private function buildSuperShares(array $allShares, \OCP\IUser $user) {
168
		$result = [];
169
170
		$groupedShares = $this->groupShares($allShares);
171
172
		/** @var \OCP\Share\IShare[] $shares */
173
		foreach ($groupedShares as $shares) {
174
			if (count($shares) === 0) {
175
				continue;
176
			}
177
178
			$superShare = $this->shareManager->newShare();
179
180
			// compute super share based on first entry of the group
181
			$superShare->setId($shares[0]->getId())
182
				->setShareOwner($shares[0]->getShareOwner())
183
				->setNodeId($shares[0]->getNodeId())
184
				->setTarget($shares[0]->getTarget());
185
186
			// use most permissive permissions
187
			$permissions = 0;
188
			foreach ($shares as $share) {
189
				$permissions |= $share->getPermissions();
190
				if ($share->getTarget() !== $superShare->getTarget()) {
191
					// adjust target, for database consistency
192
					$share->setTarget($superShare->getTarget());
193
					try {
194
						$this->shareManager->moveShare($share, $user->getUID());
195
					} catch (\InvalidArgumentException $e) {
196
						// ignore as it is not important and we don't want to
197
						// block FS setup
198
199
						// the subsequent code anyway only uses the target of the
200
						// super share
201
202
						// such issue can usually happen when dealing with
203
						// null groups which usually appear with group backend
204
						// caching inconsistencies
205
						$this->logger->debug(
206
							'Could not adjust share target for share ' . $share->getId() . ' to make it consistent: ' . $e->getMessage(),
207
							['app' => 'files_sharing']
208
						);
209
					}
210
				}
211
				if (!is_null($share->getNodeCacheEntry())) {
212
					$superShare->setNodeCacheEntry($share->getNodeCacheEntry());
213
				}
214
			}
215
216
			$superShare->setPermissions($permissions);
217
218
			$result[] = [$superShare, $shares];
219
		}
220
221
		return $result;
222
	}
223
}
224