Completed
Push — stable10 ( 65dd17...7321ba )
by Björn
10:16
created

MountProvider::groupShares()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 24
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 5
eloc 14
nc 6
nop 1
dl 0
loc 24
rs 8.5125
c 2
b 0
f 0
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 OCP\Files\Config\IMountProvider;
29
use OCP\Files\Storage\IStorageFactory;
30
use OCP\IConfig;
31
use OCP\ILogger;
32
use OCP\IUser;
33
use OCP\Share\IManager;
34
35
class MountProvider implements IMountProvider {
36
	/**
37
	 * @var \OCP\IConfig
38
	 */
39
	protected $config;
40
41
	/**
42
	 * @var IManager
43
	 */
44
	protected $shareManager;
45
46
	/**
47
	 * @var ILogger
48
	 */
49
	protected $logger;
50
51
	/**
52
	 * @param \OCP\IConfig $config
53
	 * @param IManager $shareManager
54
	 * @param ILogger $logger
55
	 */
56
	public function __construct(IConfig $config, IManager $shareManager, ILogger $logger) {
57
		$this->config = $config;
58
		$this->shareManager = $shareManager;
59
		$this->logger = $logger;
60
	}
61
62
63
	/**
64
	 * Get all mountpoints applicable for the user and check for shares where we need to update the etags
65
	 *
66
	 * @param \OCP\IUser $user
67
	 * @param \OCP\Files\Storage\IStorageFactory $storageFactory
68
	 * @return \OCP\Files\Mount\IMountPoint[]
69
	 */
70
	public function getMountsForUser(IUser $user, IStorageFactory $storageFactory) {
71
		$shares = $this->shareManager->getSharedWith($user->getUID(), \OCP\Share::SHARE_TYPE_USER, null, -1);
72
		$shares = array_merge($shares, $this->shareManager->getSharedWith($user->getUID(), \OCP\Share::SHARE_TYPE_GROUP, null, -1));
73
		// filter out excluded shares and group shares that includes self
74
		$shares = array_filter($shares, function (\OCP\Share\IShare $share) use ($user) {
75
			return $share->getPermissions() > 0 && $share->getShareOwner() !== $user->getUID();
76
		});
77
78
		$superShares = $this->buildSuperShares($shares, $user);
79
80
		$mounts = [];
81
		foreach ($superShares as $share) {
82
			try {
83
				$mounts[] = new SharedMount(
84
					'\OC\Files\Storage\Shared',
85
					$mounts,
86
					[
87
						'user' => $user->getUID(),
88
						// parent share
89
						'superShare' => $share[0],
90
						// children/component of the superShare
91
						'groupedShares' => $share[1],
92
					],
93
					$storageFactory
94
				);
95
			} catch (\Exception $e) {
96
				$this->logger->logException($e);
97
				$this->logger->error('Error while trying to create shared mount');
98
			}
99
		}
100
101
		// array_filter removes the null values from the array
102
		return array_filter($mounts);
103
	}
104
105
	/**
106
	 * Groups shares by path (nodeId) and target path
107
	 *
108
	 * @param \OCP\Share\IShare[] $shares
109
	 * @return \OCP\Share\IShare[][] array of grouped shares, each element in the
110
	 * array is a group which itself is an array of shares
111
	 */
112
	private function groupShares(array $shares) {
113
		$tmp = [];
114
115
		foreach ($shares as $share) {
116
			if (!isset($tmp[$share->getNodeId()])) {
117
				$tmp[$share->getNodeId()] = [];
118
			}
119
			$tmp[$share->getNodeId()][] = $share;
120
		}
121
122
		$result = [];
123
		// sort by stime, the super share will be based on the least recent share
124
		foreach ($tmp as &$tmp2) {
125
			@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...
126
				if ($a->getShareTime() < $b->getShareTime()) {
127
					return -1;
128
				}
129
				return 1;
130
			});
131
			$result[] = $tmp2;
132
		}
133
134
		return array_values($result);
135
	}
136
137
	/**
138
	 * Build super shares (virtual share) by grouping them by node id and target,
139
	 * then for each group compute the super share and return it along with the matching
140
	 * grouped shares. The most permissive permissions are used based on the permissions
141
	 * of all shares within the group.
142
	 *
143
	 * @param \OCP\Share\IShare[] $allShares
144
	 * @param \OCP\IUser $user user
145
	 * @return array Tuple of [superShare, groupedShares]
146
	 */
147
	private function buildSuperShares(array $allShares, \OCP\IUser $user) {
148
		$result = [];
149
150
		$groupedShares = $this->groupShares($allShares);
151
152
		/** @var \OCP\Share\IShare[] $shares */
153
		foreach ($groupedShares as $shares) {
154
			if (count($shares) === 0) {
155
				continue;
156
			}
157
158
			$superShare = $this->shareManager->newShare();
159
160
			// compute super share based on first entry of the group
161
			$superShare->setId($shares[0]->getId())
162
				->setShareOwner($shares[0]->getShareOwner())
163
				->setNodeId($shares[0]->getNodeId())
164
				->setTarget($shares[0]->getTarget());
165
166
			// use most permissive permissions
167
			$permissions = 0;
168
			foreach ($shares as $share) {
169
				$permissions |= $share->getPermissions();
170
				if ($share->getTarget() !== $superShare->getTarget()) {
171
					// adjust target, for database consistency
172
					$share->setTarget($superShare->getTarget());
173
					$this->shareManager->moveShare($share, $user->getUID());
174
				}
175
			}
176
177
			$superShare->setPermissions($permissions);
178
179
			$result[] = [$superShare, $shares];
180
		}
181
182
		return $result;
183
	}
184
}
185