Passed
Push — master ( e0b2c9...936f63 )
by Robin
30:56 queued 14:22
created

getUserMountsForProviderClasses()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 2
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Christoph Wurst <[email protected]>
6
 * @author Morris Jobke <[email protected]>
7
 * @author Robin Appelman <[email protected]>
8
 * @author Roeland Jago Douma <[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
namespace OC\Files\Config;
26
27
use OC\Hooks\Emitter;
28
use OC\Hooks\EmitterTrait;
29
use OCP\Diagnostics\IEventLogger;
30
use OCP\Files\Config\IHomeMountProvider;
31
use OCP\Files\Config\IMountProvider;
32
use OCP\Files\Config\IMountProviderCollection;
33
use OCP\Files\Config\IRootMountProvider;
34
use OCP\Files\Config\IUserMountCache;
35
use OCP\Files\Mount\IMountManager;
36
use OCP\Files\Mount\IMountPoint;
37
use OCP\Files\Storage\IStorageFactory;
38
use OCP\IUser;
39
40
class MountProviderCollection implements IMountProviderCollection, Emitter {
0 ignored issues
show
Deprecated Code introduced by
The interface OC\Hooks\Emitter has been deprecated: 18.0.0 use events and the \OCP\EventDispatcher\IEventDispatcher service ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

40
class MountProviderCollection implements IMountProviderCollection, /** @scrutinizer ignore-deprecated */ Emitter {

This interface has been deprecated. The supplier of the interface has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the interface will be removed and what other interface to use instead.

Loading history...
41
	use EmitterTrait;
0 ignored issues
show
Deprecated Code introduced by
The trait OC\Hooks\EmitterTrait has been deprecated: 18.0.0 use events and the \OCP\EventDispatcher\IEventDispatcher service ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

41
	use /** @scrutinizer ignore-deprecated */ EmitterTrait;

This trait has been deprecated. The supplier of the trait has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the trait will be removed and what other trait to use instead.

Loading history...
42
43
	/**
44
	 * @var \OCP\Files\Config\IHomeMountProvider[]
45
	 */
46
	private $homeProviders = [];
47
48
	/**
49
	 * @var \OCP\Files\Config\IMountProvider[]
50
	 */
51
	private $providers = [];
52
53
	/** @var \OCP\Files\Config\IRootMountProvider[] */
54
	private $rootProviders = [];
55
56
	/**
57
	 * @var \OCP\Files\Storage\IStorageFactory
58
	 */
59
	private $loader;
60
61
	/**
62
	 * @var \OCP\Files\Config\IUserMountCache
63
	 */
64
	private $mountCache;
65
66
	/** @var callable[] */
67
	private $mountFilters = [];
68
69
	private IEventLogger $eventLogger;
70
71
	/**
72
	 * @param \OCP\Files\Storage\IStorageFactory $loader
73
	 * @param IUserMountCache $mountCache
74
	 */
75
	public function __construct(
76
		IStorageFactory $loader,
77
		IUserMountCache $mountCache,
78
		IEventLogger $eventLogger
79
	) {
80
		$this->loader = $loader;
81
		$this->mountCache = $mountCache;
82
		$this->eventLogger = $eventLogger;
83
	}
84
85
	private function getMountsFromProvider(IMountProvider $provider, IUser $user, IStorageFactory $loader): array {
86
		$class = str_replace('\\', '_', get_class($provider));
87
		$uid = $user->getUID();
88
		$this->eventLogger->start('fs:setup:provider:' . $class, "Getting mounts from $class for $uid");
89
		$mounts = $provider->getMountsForUser($user, $loader) ?? [];
90
		$this->eventLogger->end('fs:setup:provider:' . $class);
91
		return $mounts;
92
	}
93
94
	/**
95
	 * @param IUser $user
96
	 * @param IMountProvider[] $providers
97
	 * @return IMountPoint[]
98
	 */
99
	private function getUserMountsForProviders(IUser $user, array $providers): array {
100
		$loader = $this->loader;
101
		$mounts = array_map(function (IMountProvider $provider) use ($user, $loader) {
102
			return $this->getMountsFromProvider($provider, $user, $loader);
103
		}, $providers);
104
		$mounts = array_reduce($mounts, function (array $mounts, array $providerMounts) {
105
			return array_merge($mounts, $providerMounts);
106
		}, []);
107
		return $this->filterMounts($user, $mounts);
108
	}
109
110
	public function getMountsForUser(IUser $user): array {
111
		return $this->getUserMountsForProviders($user, $this->providers);
112
	}
113
114
	public function getUserMountsForProviderClasses(IUser $user, array $mountProviderClasses): array {
115
		$providers = array_filter(
116
			$this->providers,
117
			fn (IMountProvider $mountProvider) => (in_array(get_class($mountProvider), $mountProviderClasses))
118
		);
119
		return $this->getUserMountsForProviders($user, $providers);
120
	}
121
122
	public function addMountForUser(IUser $user, IMountManager $mountManager, callable $providerFilter = null) {
123
		// shared mount provider gets to go last since it needs to know existing files
124
		// to check for name collisions
125
		$firstMounts = [];
126
		if ($providerFilter) {
127
			$providers = array_filter($this->providers, $providerFilter);
128
		} else {
129
			$providers = $this->providers;
130
		}
131
		$firstProviders = array_filter($providers, function (IMountProvider $provider) {
132
			return (get_class($provider) !== 'OCA\Files_Sharing\MountProvider');
133
		});
134
		$lastProviders = array_filter($providers, function (IMountProvider $provider) {
135
			return (get_class($provider) === 'OCA\Files_Sharing\MountProvider');
136
		});
137
		foreach ($firstProviders as $provider) {
138
			$mounts = $this->getMountsFromProvider($provider, $user, $this->loader);
139
			$firstMounts = array_merge($firstMounts, $mounts);
140
		}
141
		$firstMounts = $this->filterMounts($user, $firstMounts);
142
		array_walk($firstMounts, [$mountManager, 'addMount']);
143
144
		$lateMounts = [];
145
		foreach ($lastProviders as $provider) {
146
			$mounts = $this->getMountsFromProvider($provider, $user, $this->loader);
147
			$lateMounts = array_merge($lateMounts, $mounts);
148
		}
149
150
		$lateMounts = $this->filterMounts($user, $lateMounts);
151
		$this->eventLogger->start("fs:setup:add-mounts", "Add mounts to the filesystem");
152
		array_walk($lateMounts, [$mountManager, 'addMount']);
153
		$this->eventLogger->end("fs:setup:add-mounts");
154
155
		return array_merge($lateMounts, $firstMounts);
156
	}
157
158
	/**
159
	 * Get the configured home mount for this user
160
	 *
161
	 * @param \OCP\IUser $user
162
	 * @return \OCP\Files\Mount\IMountPoint
163
	 * @since 9.1.0
164
	 */
165
	public function getHomeMountForUser(IUser $user) {
166
		/** @var \OCP\Files\Config\IHomeMountProvider[] $providers */
167
		$providers = array_reverse($this->homeProviders); // call the latest registered provider first to give apps an opportunity to overwrite builtin
168
		foreach ($providers as $homeProvider) {
169
			if ($mount = $homeProvider->getHomeMountForUser($user, $this->loader)) {
170
				$mount->setMountPoint('/' . $user->getUID()); //make sure the mountpoint is what we expect
171
				return $mount;
172
			}
173
		}
174
		throw new \Exception('No home storage configured for user ' . $user);
0 ignored issues
show
Bug introduced by
Are you sure $user of type OCP\IUser can be used in concatenation? Consider adding a __toString()-method. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

174
		throw new \Exception('No home storage configured for user ' . /** @scrutinizer ignore-type */ $user);
Loading history...
175
	}
176
177
	/**
178
	 * Add a provider for mount points
179
	 *
180
	 * @param \OCP\Files\Config\IMountProvider $provider
181
	 */
182
	public function registerProvider(IMountProvider $provider) {
183
		$this->providers[] = $provider;
184
185
		$this->emit('\OC\Files\Config', 'registerMountProvider', [$provider]);
186
	}
187
188
	public function registerMountFilter(callable $filter) {
189
		$this->mountFilters[] = $filter;
190
	}
191
192
	private function filterMounts(IUser $user, array $mountPoints) {
193
		return array_filter($mountPoints, function (IMountPoint $mountPoint) use ($user) {
194
			foreach ($this->mountFilters as $filter) {
195
				if ($filter($mountPoint, $user) === false) {
196
					return false;
197
				}
198
			}
199
			return true;
200
		});
201
	}
202
203
	/**
204
	 * Add a provider for home mount points
205
	 *
206
	 * @param \OCP\Files\Config\IHomeMountProvider $provider
207
	 * @since 9.1.0
208
	 */
209
	public function registerHomeProvider(IHomeMountProvider $provider) {
210
		$this->homeProviders[] = $provider;
211
		$this->emit('\OC\Files\Config', 'registerHomeMountProvider', [$provider]);
212
	}
213
214
	/**
215
	 * Get the mount cache which can be used to search for mounts without setting up the filesystem
216
	 *
217
	 * @return IUserMountCache
218
	 */
219
	public function getMountCache() {
220
		return $this->mountCache;
221
	}
222
223
	public function registerRootProvider(IRootMountProvider $provider) {
224
		$this->rootProviders[] = $provider;
225
	}
226
227
	/**
228
	 * Get all root mountpoints
229
	 *
230
	 * @return \OCP\Files\Mount\IMountPoint[]
231
	 * @since 20.0.0
232
	 */
233
	public function getRootMounts(): array {
234
		$loader = $this->loader;
235
		$mounts = array_map(function (IRootMountProvider $provider) use ($loader) {
236
			return $provider->getRootMounts($loader);
237
		}, $this->rootProviders);
238
		$mounts = array_reduce($mounts, function (array $mounts, array $providerMounts) {
239
			return array_merge($mounts, $providerMounts);
240
		}, []);
241
		return $mounts;
242
	}
243
244
	public function clearProviders() {
245
		$this->providers = [];
246
		$this->homeProviders = [];
247
		$this->rootProviders = [];
248
	}
249
250
	public function getProviders(): array {
251
		return $this->providers;
252
	}
253
}
254