Completed
Pull Request — master (#5231)
by Morris
16:38
created
lib/private/Files/Config/UserMountCache.php 3 patches
Unused Use Statements   -1 removed lines patch added patch discarded remove patch
@@ -24,7 +24,6 @@
 block discarded – undo
24 24
 
25 25
 namespace OC\Files\Config;
26 26
 
27
-use OC\DB\QueryBuilder\Literal;
28 27
 use OCA\Files_Sharing\SharedMount;
29 28
 use OCP\DB\QueryBuilder\IQueryBuilder;
30 29
 use OCP\Files\Config\ICachedMountInfo;
Please login to merge, or discard this patch.
Indentation   +320 added lines, -320 removed lines patch added patch discarded remove patch
@@ -42,324 +42,324 @@
 block discarded – undo
42 42
  * Cache mounts points per user in the cache so we can easilly look them up
43 43
  */
44 44
 class UserMountCache implements IUserMountCache {
45
-	/**
46
-	 * @var IDBConnection
47
-	 */
48
-	private $connection;
49
-
50
-	/**
51
-	 * @var IUserManager
52
-	 */
53
-	private $userManager;
54
-
55
-	/**
56
-	 * Cached mount info.
57
-	 * Map of $userId to ICachedMountInfo.
58
-	 *
59
-	 * @var ICache
60
-	 **/
61
-	private $mountsForUsers;
62
-
63
-	/**
64
-	 * @var ILogger
65
-	 */
66
-	private $logger;
67
-
68
-	/**
69
-	 * @var ICache
70
-	 */
71
-	private $cacheInfoCache;
72
-
73
-	/**
74
-	 * UserMountCache constructor.
75
-	 *
76
-	 * @param IDBConnection $connection
77
-	 * @param IUserManager $userManager
78
-	 * @param ILogger $logger
79
-	 */
80
-	public function __construct(IDBConnection $connection, IUserManager $userManager, ILogger $logger) {
81
-		$this->connection = $connection;
82
-		$this->userManager = $userManager;
83
-		$this->logger = $logger;
84
-		$this->cacheInfoCache = new CappedMemoryCache();
85
-		$this->mountsForUsers = new CappedMemoryCache();
86
-	}
87
-
88
-	public function registerMounts(IUser $user, array $mounts) {
89
-		// filter out non-proper storages coming from unit tests
90
-		$mounts = array_filter($mounts, function (IMountPoint $mount) {
91
-			return $mount instanceof SharedMount || $mount->getStorage() && $mount->getStorage()->getCache();
92
-		});
93
-		/** @var ICachedMountInfo[] $newMounts */
94
-		$newMounts = array_map(function (IMountPoint $mount) use ($user) {
95
-			// filter out any storages which aren't scanned yet since we aren't interested in files from those storages (yet)
96
-			if ($mount->getStorageRootId() === -1) {
97
-				return null;
98
-			} else {
99
-				return new LazyStorageMountInfo($user, $mount);
100
-			}
101
-		}, $mounts);
102
-		$newMounts = array_values(array_filter($newMounts));
103
-
104
-		$cachedMounts = $this->getMountsForUser($user);
105
-		$mountDiff = function (ICachedMountInfo $mount1, ICachedMountInfo $mount2) {
106
-			// since we are only looking for mounts for a specific user comparing on root id is enough
107
-			return $mount1->getRootId() - $mount2->getRootId();
108
-		};
109
-
110
-		/** @var ICachedMountInfo[] $addedMounts */
111
-		$addedMounts = array_udiff($newMounts, $cachedMounts, $mountDiff);
112
-		/** @var ICachedMountInfo[] $removedMounts */
113
-		$removedMounts = array_udiff($cachedMounts, $newMounts, $mountDiff);
114
-
115
-		$changedMounts = $this->findChangedMounts($newMounts, $cachedMounts);
116
-
117
-		foreach ($addedMounts as $mount) {
118
-			$this->addToCache($mount);
119
-			$this->mountsForUsers[$user->getUID()][] = $mount;
120
-		}
121
-		foreach ($removedMounts as $mount) {
122
-			$this->removeFromCache($mount);
123
-			$index = array_search($mount, $this->mountsForUsers[$user->getUID()]);
124
-			unset($this->mountsForUsers[$user->getUID()][$index]);
125
-		}
126
-		foreach ($changedMounts as $mount) {
127
-			$this->updateCachedMount($mount);
128
-		}
129
-	}
130
-
131
-	/**
132
-	 * @param ICachedMountInfo[] $newMounts
133
-	 * @param ICachedMountInfo[] $cachedMounts
134
-	 * @return ICachedMountInfo[]
135
-	 */
136
-	private function findChangedMounts(array $newMounts, array $cachedMounts) {
137
-		$changed = [];
138
-		foreach ($newMounts as $newMount) {
139
-			foreach ($cachedMounts as $cachedMount) {
140
-				if (
141
-					$newMount->getRootId() === $cachedMount->getRootId() &&
142
-					(
143
-						$newMount->getMountPoint() !== $cachedMount->getMountPoint() ||
144
-						$newMount->getStorageId() !== $cachedMount->getStorageId() ||
145
-						$newMount->getMountId() !== $cachedMount->getMountId()
146
-					)
147
-				) {
148
-					$changed[] = $newMount;
149
-				}
150
-			}
151
-		}
152
-		return $changed;
153
-	}
154
-
155
-	private function addToCache(ICachedMountInfo $mount) {
156
-		if ($mount->getStorageId() !== -1) {
157
-			$this->connection->insertIfNotExist('*PREFIX*mounts', [
158
-				'storage_id' => $mount->getStorageId(),
159
-				'root_id' => $mount->getRootId(),
160
-				'user_id' => $mount->getUser()->getUID(),
161
-				'mount_point' => $mount->getMountPoint(),
162
-				'mount_id' => $mount->getMountId()
163
-			], ['root_id', 'user_id']);
164
-		} else {
165
-			// in some cases this is legitimate, like orphaned shares
166
-			$this->logger->debug('Could not get storage info for mount at ' . $mount->getMountPoint());
167
-		}
168
-	}
169
-
170
-	private function updateCachedMount(ICachedMountInfo $mount) {
171
-		$builder = $this->connection->getQueryBuilder();
172
-
173
-		$query = $builder->update('mounts')
174
-			->set('storage_id', $builder->createNamedParameter($mount->getStorageId()))
175
-			->set('mount_point', $builder->createNamedParameter($mount->getMountPoint()))
176
-			->set('mount_id', $builder->createNamedParameter($mount->getMountId(), IQueryBuilder::PARAM_INT))
177
-			->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID())))
178
-			->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT)));
179
-
180
-		$query->execute();
181
-	}
182
-
183
-	private function removeFromCache(ICachedMountInfo $mount) {
184
-		$builder = $this->connection->getQueryBuilder();
185
-
186
-		$query = $builder->delete('mounts')
187
-			->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID())))
188
-			->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT)));
189
-		$query->execute();
190
-	}
191
-
192
-	private function dbRowToMountInfo(array $row) {
193
-		$user = $this->userManager->get($row['user_id']);
194
-		if (is_null($user)) {
195
-			return null;
196
-		}
197
-		return new CachedMountInfo($user, (int)$row['storage_id'], (int)$row['root_id'], $row['mount_point'], $row['mount_id'], isset($row['path']) ? $row['path'] : '');
198
-	}
199
-
200
-	/**
201
-	 * @param IUser $user
202
-	 * @return ICachedMountInfo[]
203
-	 */
204
-	public function getMountsForUser(IUser $user) {
205
-		if (!isset($this->mountsForUsers[$user->getUID()])) {
206
-			$builder = $this->connection->getQueryBuilder();
207
-			$query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path')
208
-				->from('mounts', 'm')
209
-				->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
210
-				->where($builder->expr()->eq('user_id', $builder->createPositionalParameter($user->getUID())));
211
-
212
-			$rows = $query->execute()->fetchAll();
213
-
214
-			$this->mountsForUsers[$user->getUID()] = array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
215
-		}
216
-		return $this->mountsForUsers[$user->getUID()];
217
-	}
218
-
219
-	/**
220
-	 * @param int $numericStorageId
221
-	 * @param string|null $user limit the results to a single user
222
-	 * @return CachedMountInfo[]
223
-	 */
224
-	public function getMountsForStorageId($numericStorageId, $user = null) {
225
-		$builder = $this->connection->getQueryBuilder();
226
-		$query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path')
227
-			->from('mounts', 'm')
228
-			->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
229
-			->where($builder->expr()->eq('storage_id', $builder->createPositionalParameter($numericStorageId, IQueryBuilder::PARAM_INT)));
230
-
231
-		if ($user) {
232
-			$query->andWhere($builder->expr()->eq('user_id', $builder->createPositionalParameter($user)));
233
-		}
234
-
235
-		$rows = $query->execute()->fetchAll();
236
-
237
-		return array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
238
-	}
239
-
240
-	/**
241
-	 * @param int $rootFileId
242
-	 * @return CachedMountInfo[]
243
-	 */
244
-	public function getMountsForRootId($rootFileId) {
245
-		$builder = $this->connection->getQueryBuilder();
246
-		$query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path')
247
-			->from('mounts', 'm')
248
-			->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
249
-			->where($builder->expr()->eq('root_id', $builder->createPositionalParameter($rootFileId, IQueryBuilder::PARAM_INT)));
250
-
251
-		$rows = $query->execute()->fetchAll();
252
-
253
-		return array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
254
-	}
255
-
256
-	/**
257
-	 * @param $fileId
258
-	 * @return array
259
-	 * @throws \OCP\Files\NotFoundException
260
-	 */
261
-	private function getCacheInfoFromFileId($fileId) {
262
-		if (!isset($this->cacheInfoCache[$fileId])) {
263
-			$builder = $this->connection->getQueryBuilder();
264
-			$query = $builder->select('storage', 'path', 'mimetype')
265
-				->from('filecache')
266
-				->where($builder->expr()->eq('fileid', $builder->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)));
267
-
268
-			$row = $query->execute()->fetch();
269
-			if (is_array($row)) {
270
-				$this->cacheInfoCache[$fileId] = [
271
-					(int)$row['storage'],
272
-					$row['path'],
273
-					(int)$row['mimetype']
274
-				];
275
-			} else {
276
-				throw new NotFoundException('File with id "' . $fileId . '" not found');
277
-			}
278
-		}
279
-		return $this->cacheInfoCache[$fileId];
280
-	}
281
-
282
-	/**
283
-	 * @param int $fileId
284
-	 * @param string|null $user optionally restrict the results to a single user
285
-	 * @return ICachedMountInfo[]
286
-	 * @since 9.0.0
287
-	 */
288
-	public function getMountsForFileId($fileId, $user = null) {
289
-		try {
290
-			list($storageId, $internalPath) = $this->getCacheInfoFromFileId($fileId);
291
-		} catch (NotFoundException $e) {
292
-			return [];
293
-		}
294
-		$mountsForStorage = $this->getMountsForStorageId($storageId, $user);
295
-
296
-		// filter mounts that are from the same storage but a different directory
297
-		return array_filter($mountsForStorage, function (ICachedMountInfo $mount) use ($internalPath, $fileId) {
298
-			if ($fileId === $mount->getRootId()) {
299
-				return true;
300
-			}
301
-			$internalMountPath = $mount->getRootInternalPath();
302
-
303
-			return $internalMountPath === '' || substr($internalPath, 0, strlen($internalMountPath) + 1) === $internalMountPath . '/';
304
-		});
305
-	}
306
-
307
-	/**
308
-	 * Remove all cached mounts for a user
309
-	 *
310
-	 * @param IUser $user
311
-	 */
312
-	public function removeUserMounts(IUser $user) {
313
-		$builder = $this->connection->getQueryBuilder();
314
-
315
-		$query = $builder->delete('mounts')
316
-			->where($builder->expr()->eq('user_id', $builder->createNamedParameter($user->getUID())));
317
-		$query->execute();
318
-	}
319
-
320
-	public function removeUserStorageMount($storageId, $userId) {
321
-		$builder = $this->connection->getQueryBuilder();
322
-
323
-		$query = $builder->delete('mounts')
324
-			->where($builder->expr()->eq('user_id', $builder->createNamedParameter($userId)))
325
-			->andWhere($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)));
326
-		$query->execute();
327
-	}
328
-
329
-	public function remoteStorageMounts($storageId) {
330
-		$builder = $this->connection->getQueryBuilder();
331
-
332
-		$query = $builder->delete('mounts')
333
-			->where($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)));
334
-		$query->execute();
335
-	}
336
-
337
-	public function getUsedSpaceForUsers(array $users) {
338
-		$builder = $this->connection->getQueryBuilder();
339
-
340
-		$slash = $builder->createNamedParameter('/');
341
-
342
-		$mountPoint = $builder->func()->concat(
343
-			$builder->func()->concat($slash, 'user_id'),
344
-			$slash
345
-		);
346
-
347
-		$userIds = array_map(function (IUser $user) {
348
-			return $user->getUID();
349
-		}, $users);
350
-
351
-		$query = $builder->select('m.user_id', 'f.size')
352
-			->from('mounts', 'm')
353
-			->innerJoin('m', 'filecache', 'f',
354
-				$builder->expr()->andX(
355
-					$builder->expr()->eq('m.storage_id', 'f.storage'),
356
-					$builder->expr()->eq('f.path', $builder->createNamedParameter('files'))
357
-				))
358
-			->where($builder->expr()->eq('m.mount_point', $mountPoint))
359
-			->andWhere($builder->expr()->in('m.user_id', $builder->createNamedParameter($userIds, IQueryBuilder::PARAM_STR_ARRAY)));
360
-
361
-		$result = $query->execute();
362
-
363
-		return $result->fetchAll(\PDO::FETCH_KEY_PAIR);
364
-	}
45
+    /**
46
+     * @var IDBConnection
47
+     */
48
+    private $connection;
49
+
50
+    /**
51
+     * @var IUserManager
52
+     */
53
+    private $userManager;
54
+
55
+    /**
56
+     * Cached mount info.
57
+     * Map of $userId to ICachedMountInfo.
58
+     *
59
+     * @var ICache
60
+     **/
61
+    private $mountsForUsers;
62
+
63
+    /**
64
+     * @var ILogger
65
+     */
66
+    private $logger;
67
+
68
+    /**
69
+     * @var ICache
70
+     */
71
+    private $cacheInfoCache;
72
+
73
+    /**
74
+     * UserMountCache constructor.
75
+     *
76
+     * @param IDBConnection $connection
77
+     * @param IUserManager $userManager
78
+     * @param ILogger $logger
79
+     */
80
+    public function __construct(IDBConnection $connection, IUserManager $userManager, ILogger $logger) {
81
+        $this->connection = $connection;
82
+        $this->userManager = $userManager;
83
+        $this->logger = $logger;
84
+        $this->cacheInfoCache = new CappedMemoryCache();
85
+        $this->mountsForUsers = new CappedMemoryCache();
86
+    }
87
+
88
+    public function registerMounts(IUser $user, array $mounts) {
89
+        // filter out non-proper storages coming from unit tests
90
+        $mounts = array_filter($mounts, function (IMountPoint $mount) {
91
+            return $mount instanceof SharedMount || $mount->getStorage() && $mount->getStorage()->getCache();
92
+        });
93
+        /** @var ICachedMountInfo[] $newMounts */
94
+        $newMounts = array_map(function (IMountPoint $mount) use ($user) {
95
+            // filter out any storages which aren't scanned yet since we aren't interested in files from those storages (yet)
96
+            if ($mount->getStorageRootId() === -1) {
97
+                return null;
98
+            } else {
99
+                return new LazyStorageMountInfo($user, $mount);
100
+            }
101
+        }, $mounts);
102
+        $newMounts = array_values(array_filter($newMounts));
103
+
104
+        $cachedMounts = $this->getMountsForUser($user);
105
+        $mountDiff = function (ICachedMountInfo $mount1, ICachedMountInfo $mount2) {
106
+            // since we are only looking for mounts for a specific user comparing on root id is enough
107
+            return $mount1->getRootId() - $mount2->getRootId();
108
+        };
109
+
110
+        /** @var ICachedMountInfo[] $addedMounts */
111
+        $addedMounts = array_udiff($newMounts, $cachedMounts, $mountDiff);
112
+        /** @var ICachedMountInfo[] $removedMounts */
113
+        $removedMounts = array_udiff($cachedMounts, $newMounts, $mountDiff);
114
+
115
+        $changedMounts = $this->findChangedMounts($newMounts, $cachedMounts);
116
+
117
+        foreach ($addedMounts as $mount) {
118
+            $this->addToCache($mount);
119
+            $this->mountsForUsers[$user->getUID()][] = $mount;
120
+        }
121
+        foreach ($removedMounts as $mount) {
122
+            $this->removeFromCache($mount);
123
+            $index = array_search($mount, $this->mountsForUsers[$user->getUID()]);
124
+            unset($this->mountsForUsers[$user->getUID()][$index]);
125
+        }
126
+        foreach ($changedMounts as $mount) {
127
+            $this->updateCachedMount($mount);
128
+        }
129
+    }
130
+
131
+    /**
132
+     * @param ICachedMountInfo[] $newMounts
133
+     * @param ICachedMountInfo[] $cachedMounts
134
+     * @return ICachedMountInfo[]
135
+     */
136
+    private function findChangedMounts(array $newMounts, array $cachedMounts) {
137
+        $changed = [];
138
+        foreach ($newMounts as $newMount) {
139
+            foreach ($cachedMounts as $cachedMount) {
140
+                if (
141
+                    $newMount->getRootId() === $cachedMount->getRootId() &&
142
+                    (
143
+                        $newMount->getMountPoint() !== $cachedMount->getMountPoint() ||
144
+                        $newMount->getStorageId() !== $cachedMount->getStorageId() ||
145
+                        $newMount->getMountId() !== $cachedMount->getMountId()
146
+                    )
147
+                ) {
148
+                    $changed[] = $newMount;
149
+                }
150
+            }
151
+        }
152
+        return $changed;
153
+    }
154
+
155
+    private function addToCache(ICachedMountInfo $mount) {
156
+        if ($mount->getStorageId() !== -1) {
157
+            $this->connection->insertIfNotExist('*PREFIX*mounts', [
158
+                'storage_id' => $mount->getStorageId(),
159
+                'root_id' => $mount->getRootId(),
160
+                'user_id' => $mount->getUser()->getUID(),
161
+                'mount_point' => $mount->getMountPoint(),
162
+                'mount_id' => $mount->getMountId()
163
+            ], ['root_id', 'user_id']);
164
+        } else {
165
+            // in some cases this is legitimate, like orphaned shares
166
+            $this->logger->debug('Could not get storage info for mount at ' . $mount->getMountPoint());
167
+        }
168
+    }
169
+
170
+    private function updateCachedMount(ICachedMountInfo $mount) {
171
+        $builder = $this->connection->getQueryBuilder();
172
+
173
+        $query = $builder->update('mounts')
174
+            ->set('storage_id', $builder->createNamedParameter($mount->getStorageId()))
175
+            ->set('mount_point', $builder->createNamedParameter($mount->getMountPoint()))
176
+            ->set('mount_id', $builder->createNamedParameter($mount->getMountId(), IQueryBuilder::PARAM_INT))
177
+            ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID())))
178
+            ->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT)));
179
+
180
+        $query->execute();
181
+    }
182
+
183
+    private function removeFromCache(ICachedMountInfo $mount) {
184
+        $builder = $this->connection->getQueryBuilder();
185
+
186
+        $query = $builder->delete('mounts')
187
+            ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID())))
188
+            ->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT)));
189
+        $query->execute();
190
+    }
191
+
192
+    private function dbRowToMountInfo(array $row) {
193
+        $user = $this->userManager->get($row['user_id']);
194
+        if (is_null($user)) {
195
+            return null;
196
+        }
197
+        return new CachedMountInfo($user, (int)$row['storage_id'], (int)$row['root_id'], $row['mount_point'], $row['mount_id'], isset($row['path']) ? $row['path'] : '');
198
+    }
199
+
200
+    /**
201
+     * @param IUser $user
202
+     * @return ICachedMountInfo[]
203
+     */
204
+    public function getMountsForUser(IUser $user) {
205
+        if (!isset($this->mountsForUsers[$user->getUID()])) {
206
+            $builder = $this->connection->getQueryBuilder();
207
+            $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path')
208
+                ->from('mounts', 'm')
209
+                ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
210
+                ->where($builder->expr()->eq('user_id', $builder->createPositionalParameter($user->getUID())));
211
+
212
+            $rows = $query->execute()->fetchAll();
213
+
214
+            $this->mountsForUsers[$user->getUID()] = array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
215
+        }
216
+        return $this->mountsForUsers[$user->getUID()];
217
+    }
218
+
219
+    /**
220
+     * @param int $numericStorageId
221
+     * @param string|null $user limit the results to a single user
222
+     * @return CachedMountInfo[]
223
+     */
224
+    public function getMountsForStorageId($numericStorageId, $user = null) {
225
+        $builder = $this->connection->getQueryBuilder();
226
+        $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path')
227
+            ->from('mounts', 'm')
228
+            ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
229
+            ->where($builder->expr()->eq('storage_id', $builder->createPositionalParameter($numericStorageId, IQueryBuilder::PARAM_INT)));
230
+
231
+        if ($user) {
232
+            $query->andWhere($builder->expr()->eq('user_id', $builder->createPositionalParameter($user)));
233
+        }
234
+
235
+        $rows = $query->execute()->fetchAll();
236
+
237
+        return array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
238
+    }
239
+
240
+    /**
241
+     * @param int $rootFileId
242
+     * @return CachedMountInfo[]
243
+     */
244
+    public function getMountsForRootId($rootFileId) {
245
+        $builder = $this->connection->getQueryBuilder();
246
+        $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path')
247
+            ->from('mounts', 'm')
248
+            ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
249
+            ->where($builder->expr()->eq('root_id', $builder->createPositionalParameter($rootFileId, IQueryBuilder::PARAM_INT)));
250
+
251
+        $rows = $query->execute()->fetchAll();
252
+
253
+        return array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
254
+    }
255
+
256
+    /**
257
+     * @param $fileId
258
+     * @return array
259
+     * @throws \OCP\Files\NotFoundException
260
+     */
261
+    private function getCacheInfoFromFileId($fileId) {
262
+        if (!isset($this->cacheInfoCache[$fileId])) {
263
+            $builder = $this->connection->getQueryBuilder();
264
+            $query = $builder->select('storage', 'path', 'mimetype')
265
+                ->from('filecache')
266
+                ->where($builder->expr()->eq('fileid', $builder->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)));
267
+
268
+            $row = $query->execute()->fetch();
269
+            if (is_array($row)) {
270
+                $this->cacheInfoCache[$fileId] = [
271
+                    (int)$row['storage'],
272
+                    $row['path'],
273
+                    (int)$row['mimetype']
274
+                ];
275
+            } else {
276
+                throw new NotFoundException('File with id "' . $fileId . '" not found');
277
+            }
278
+        }
279
+        return $this->cacheInfoCache[$fileId];
280
+    }
281
+
282
+    /**
283
+     * @param int $fileId
284
+     * @param string|null $user optionally restrict the results to a single user
285
+     * @return ICachedMountInfo[]
286
+     * @since 9.0.0
287
+     */
288
+    public function getMountsForFileId($fileId, $user = null) {
289
+        try {
290
+            list($storageId, $internalPath) = $this->getCacheInfoFromFileId($fileId);
291
+        } catch (NotFoundException $e) {
292
+            return [];
293
+        }
294
+        $mountsForStorage = $this->getMountsForStorageId($storageId, $user);
295
+
296
+        // filter mounts that are from the same storage but a different directory
297
+        return array_filter($mountsForStorage, function (ICachedMountInfo $mount) use ($internalPath, $fileId) {
298
+            if ($fileId === $mount->getRootId()) {
299
+                return true;
300
+            }
301
+            $internalMountPath = $mount->getRootInternalPath();
302
+
303
+            return $internalMountPath === '' || substr($internalPath, 0, strlen($internalMountPath) + 1) === $internalMountPath . '/';
304
+        });
305
+    }
306
+
307
+    /**
308
+     * Remove all cached mounts for a user
309
+     *
310
+     * @param IUser $user
311
+     */
312
+    public function removeUserMounts(IUser $user) {
313
+        $builder = $this->connection->getQueryBuilder();
314
+
315
+        $query = $builder->delete('mounts')
316
+            ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($user->getUID())));
317
+        $query->execute();
318
+    }
319
+
320
+    public function removeUserStorageMount($storageId, $userId) {
321
+        $builder = $this->connection->getQueryBuilder();
322
+
323
+        $query = $builder->delete('mounts')
324
+            ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($userId)))
325
+            ->andWhere($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)));
326
+        $query->execute();
327
+    }
328
+
329
+    public function remoteStorageMounts($storageId) {
330
+        $builder = $this->connection->getQueryBuilder();
331
+
332
+        $query = $builder->delete('mounts')
333
+            ->where($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)));
334
+        $query->execute();
335
+    }
336
+
337
+    public function getUsedSpaceForUsers(array $users) {
338
+        $builder = $this->connection->getQueryBuilder();
339
+
340
+        $slash = $builder->createNamedParameter('/');
341
+
342
+        $mountPoint = $builder->func()->concat(
343
+            $builder->func()->concat($slash, 'user_id'),
344
+            $slash
345
+        );
346
+
347
+        $userIds = array_map(function (IUser $user) {
348
+            return $user->getUID();
349
+        }, $users);
350
+
351
+        $query = $builder->select('m.user_id', 'f.size')
352
+            ->from('mounts', 'm')
353
+            ->innerJoin('m', 'filecache', 'f',
354
+                $builder->expr()->andX(
355
+                    $builder->expr()->eq('m.storage_id', 'f.storage'),
356
+                    $builder->expr()->eq('f.path', $builder->createNamedParameter('files'))
357
+                ))
358
+            ->where($builder->expr()->eq('m.mount_point', $mountPoint))
359
+            ->andWhere($builder->expr()->in('m.user_id', $builder->createNamedParameter($userIds, IQueryBuilder::PARAM_STR_ARRAY)));
360
+
361
+        $result = $query->execute();
362
+
363
+        return $result->fetchAll(\PDO::FETCH_KEY_PAIR);
364
+    }
365 365
 }
Please login to merge, or discard this patch.
Spacing   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -87,11 +87,11 @@  discard block
 block discarded – undo
87 87
 
88 88
 	public function registerMounts(IUser $user, array $mounts) {
89 89
 		// filter out non-proper storages coming from unit tests
90
-		$mounts = array_filter($mounts, function (IMountPoint $mount) {
90
+		$mounts = array_filter($mounts, function(IMountPoint $mount) {
91 91
 			return $mount instanceof SharedMount || $mount->getStorage() && $mount->getStorage()->getCache();
92 92
 		});
93 93
 		/** @var ICachedMountInfo[] $newMounts */
94
-		$newMounts = array_map(function (IMountPoint $mount) use ($user) {
94
+		$newMounts = array_map(function(IMountPoint $mount) use ($user) {
95 95
 			// filter out any storages which aren't scanned yet since we aren't interested in files from those storages (yet)
96 96
 			if ($mount->getStorageRootId() === -1) {
97 97
 				return null;
@@ -102,7 +102,7 @@  discard block
 block discarded – undo
102 102
 		$newMounts = array_values(array_filter($newMounts));
103 103
 
104 104
 		$cachedMounts = $this->getMountsForUser($user);
105
-		$mountDiff = function (ICachedMountInfo $mount1, ICachedMountInfo $mount2) {
105
+		$mountDiff = function(ICachedMountInfo $mount1, ICachedMountInfo $mount2) {
106 106
 			// since we are only looking for mounts for a specific user comparing on root id is enough
107 107
 			return $mount1->getRootId() - $mount2->getRootId();
108 108
 		};
@@ -163,7 +163,7 @@  discard block
 block discarded – undo
163 163
 			], ['root_id', 'user_id']);
164 164
 		} else {
165 165
 			// in some cases this is legitimate, like orphaned shares
166
-			$this->logger->debug('Could not get storage info for mount at ' . $mount->getMountPoint());
166
+			$this->logger->debug('Could not get storage info for mount at '.$mount->getMountPoint());
167 167
 		}
168 168
 	}
169 169
 
@@ -194,7 +194,7 @@  discard block
 block discarded – undo
194 194
 		if (is_null($user)) {
195 195
 			return null;
196 196
 		}
197
-		return new CachedMountInfo($user, (int)$row['storage_id'], (int)$row['root_id'], $row['mount_point'], $row['mount_id'], isset($row['path']) ? $row['path'] : '');
197
+		return new CachedMountInfo($user, (int) $row['storage_id'], (int) $row['root_id'], $row['mount_point'], $row['mount_id'], isset($row['path']) ? $row['path'] : '');
198 198
 	}
199 199
 
200 200
 	/**
@@ -268,12 +268,12 @@  discard block
 block discarded – undo
268 268
 			$row = $query->execute()->fetch();
269 269
 			if (is_array($row)) {
270 270
 				$this->cacheInfoCache[$fileId] = [
271
-					(int)$row['storage'],
271
+					(int) $row['storage'],
272 272
 					$row['path'],
273
-					(int)$row['mimetype']
273
+					(int) $row['mimetype']
274 274
 				];
275 275
 			} else {
276
-				throw new NotFoundException('File with id "' . $fileId . '" not found');
276
+				throw new NotFoundException('File with id "'.$fileId.'" not found');
277 277
 			}
278 278
 		}
279 279
 		return $this->cacheInfoCache[$fileId];
@@ -294,13 +294,13 @@  discard block
 block discarded – undo
294 294
 		$mountsForStorage = $this->getMountsForStorageId($storageId, $user);
295 295
 
296 296
 		// filter mounts that are from the same storage but a different directory
297
-		return array_filter($mountsForStorage, function (ICachedMountInfo $mount) use ($internalPath, $fileId) {
297
+		return array_filter($mountsForStorage, function(ICachedMountInfo $mount) use ($internalPath, $fileId) {
298 298
 			if ($fileId === $mount->getRootId()) {
299 299
 				return true;
300 300
 			}
301 301
 			$internalMountPath = $mount->getRootInternalPath();
302 302
 
303
-			return $internalMountPath === '' || substr($internalPath, 0, strlen($internalMountPath) + 1) === $internalMountPath . '/';
303
+			return $internalMountPath === '' || substr($internalPath, 0, strlen($internalMountPath) + 1) === $internalMountPath.'/';
304 304
 		});
305 305
 	}
306 306
 
@@ -344,7 +344,7 @@  discard block
 block discarded – undo
344 344
 			$slash
345 345
 		);
346 346
 
347
-		$userIds = array_map(function (IUser $user) {
347
+		$userIds = array_map(function(IUser $user) {
348 348
 			return $user->getUID();
349 349
 		}, $users);
350 350
 
Please login to merge, or discard this patch.
settings/templates/users/part.userlist.php 1 patch
Spacing   +16 added lines, -16 removed lines patch added patch discarded remove patch
@@ -1,15 +1,15 @@  discard block
 block discarded – undo
1
-<table id="userlist" class="hascontrols grid" data-groups="<?php p($_['allGroups']);?>">
1
+<table id="userlist" class="hascontrols grid" data-groups="<?php p($_['allGroups']); ?>">
2 2
 	<thead>
3 3
 		<tr>
4 4
 			<th id="headerAvatar" scope="col"></th>
5 5
 			<th id="headerName" scope="col"><?php p($l->t('Username'))?></th>
6
-			<th id="headerDisplayName" scope="col"><?php p($l->t( 'Full name' )); ?></th>
7
-			<th id="headerPassword" scope="col"><?php p($l->t( 'Password' )); ?></th>
8
-			<th class="mailAddress" scope="col"><?php p($l->t( 'Email' )); ?></th>
9
-			<th id="headerGroups" scope="col"><?php p($l->t( 'Groups' )); ?></th>
10
-		<?php if(is_array($_['subadmins']) || $_['subadmins']): ?>
6
+			<th id="headerDisplayName" scope="col"><?php p($l->t('Full name')); ?></th>
7
+			<th id="headerPassword" scope="col"><?php p($l->t('Password')); ?></th>
8
+			<th class="mailAddress" scope="col"><?php p($l->t('Email')); ?></th>
9
+			<th id="headerGroups" scope="col"><?php p($l->t('Groups')); ?></th>
10
+		<?php if (is_array($_['subadmins']) || $_['subadmins']): ?>
11 11
 			<th id="headerSubAdmins" scope="col"><?php p($l->t('Group admin for')); ?></th>
12
-		<?php endif;?>
12
+		<?php endif; ?>
13 13
 			<th id="headerQuota" scope="col"><?php p($l->t('Quota')); ?></th>
14 14
 			<th class="storageLocation" scope="col"><?php p($l->t('Storage location')); ?></th>
15 15
 			<th class="userBackend" scope="col"><?php p($l->t('User backend')); ?></th>
@@ -37,27 +37,27 @@  discard block
 block discarded – undo
37 37
 			<td class="groups"><div class="groupsListContainer multiselect button"
38 38
 				><span class="title groupsList"></span><span class="icon-triangle-s"></span></div>
39 39
 			</td>
40
-		<?php if(is_array($_['subadmins']) || $_['subadmins']): ?>
40
+		<?php if (is_array($_['subadmins']) || $_['subadmins']): ?>
41 41
 			<td class="subadmins"><div class="groupsListContainer multiselect button"
42 42
 				><span class="title groupsList"></span><span class="icon-triangle-s"></span></div>
43 43
 			</td>
44
-		<?php endif;?>
44
+		<?php endif; ?>
45 45
 			<td class="quota">
46 46
 				<div class="quota_progress_container"><div class="quota_progress"></div></div>
47 47
 				<select class="quota-user" data-inputtitle="<?php p($l->t('Please enter storage quota (ex: "512 MB" or "12 GB")')) ?>">
48 48
 					<option	value='default'>
49
-						<?php p($l->t('Default'));?>
49
+						<?php p($l->t('Default')); ?>
50 50
 					</option>
51 51
 					<option value='none'>
52
-						<?php p($l->t('Unlimited'));?>
52
+						<?php p($l->t('Unlimited')); ?>
53 53
 					</option>
54
-					<?php foreach($_['quota_preset'] as $preset):?>
55
-						<option value='<?php p($preset);?>'>
56
-							<?php p($preset);?>
54
+					<?php foreach ($_['quota_preset'] as $preset):?>
55
+						<option value='<?php p($preset); ?>'>
56
+							<?php p($preset); ?>
57 57
 						</option>
58
-					<?php endforeach;?>
58
+					<?php endforeach; ?>
59 59
 					<option value='other' data-new>
60
-						<?php p($l->t('Other'));?> ...
60
+						<?php p($l->t('Other')); ?> ...
61 61
 					</option>
62 62
 				</select>
63 63
 			</td>
Please login to merge, or discard this patch.
settings/Controller/UsersController.php 2 patches
Indentation   +955 added lines, -955 removed lines patch added patch discarded remove patch
@@ -60,960 +60,960 @@
 block discarded – undo
60 60
  * @package OC\Settings\Controller
61 61
  */
62 62
 class UsersController extends Controller {
63
-	/** @var IL10N */
64
-	private $l10n;
65
-	/** @var IUserSession */
66
-	private $userSession;
67
-	/** @var bool */
68
-	private $isAdmin;
69
-	/** @var IUserManager */
70
-	private $userManager;
71
-	/** @var IGroupManager */
72
-	private $groupManager;
73
-	/** @var IConfig */
74
-	private $config;
75
-	/** @var ILogger */
76
-	private $log;
77
-	/** @var IMailer */
78
-	private $mailer;
79
-	/** @var bool contains the state of the encryption app */
80
-	private $isEncryptionAppEnabled;
81
-	/** @var bool contains the state of the admin recovery setting */
82
-	private $isRestoreEnabled = false;
83
-	/** @var IAppManager */
84
-	private $appManager;
85
-	/** @var IAvatarManager */
86
-	private $avatarManager;
87
-	/** @var AccountManager */
88
-	private $accountManager;
89
-	/** @var ISecureRandom */
90
-	private $secureRandom;
91
-	/** @var NewUserMailHelper */
92
-	private $newUserMailHelper;
93
-	/** @var ITimeFactory */
94
-	private $timeFactory;
95
-	/** @var ICrypto */
96
-	private $crypto;
97
-	/** @var Manager */
98
-	private $keyManager;
99
-	/** @var IJobList */
100
-	private $jobList;
101
-	/** @var IUserMountCache */
102
-	private $userMountCache;
103
-
104
-	/**
105
-	 * @param string $appName
106
-	 * @param IRequest $request
107
-	 * @param IUserManager $userManager
108
-	 * @param IGroupManager $groupManager
109
-	 * @param IUserSession $userSession
110
-	 * @param IConfig $config
111
-	 * @param bool $isAdmin
112
-	 * @param IL10N $l10n
113
-	 * @param ILogger $log
114
-	 * @param IMailer $mailer
115
-	 * @param IURLGenerator $urlGenerator
116
-	 * @param IAppManager $appManager
117
-	 * @param IAvatarManager $avatarManager
118
-	 * @param AccountManager $accountManager
119
-	 * @param ISecureRandom $secureRandom
120
-	 * @param NewUserMailHelper $newUserMailHelper
121
-	 * @param ITimeFactory $timeFactory
122
-	 * @param ICrypto $crypto
123
-	 * @param Manager $keyManager
124
-	 * @param IJobList $jobList
125
-	 * @param IUserMountCache $userMountCache
126
-	 */
127
-	public function __construct($appName,
128
-								IRequest $request,
129
-								IUserManager $userManager,
130
-								IGroupManager $groupManager,
131
-								IUserSession $userSession,
132
-								IConfig $config,
133
-								$isAdmin,
134
-								IL10N $l10n,
135
-								ILogger $log,
136
-								IMailer $mailer,
137
-								IURLGenerator $urlGenerator,
138
-								IAppManager $appManager,
139
-								IAvatarManager $avatarManager,
140
-								AccountManager $accountManager,
141
-								ISecureRandom $secureRandom,
142
-								NewUserMailHelper $newUserMailHelper,
143
-								ITimeFactory $timeFactory,
144
-								ICrypto $crypto,
145
-								Manager $keyManager,
146
-								IJobList $jobList,
147
-								IUserMountCache $userMountCache) {
148
-		parent::__construct($appName, $request);
149
-		$this->userManager = $userManager;
150
-		$this->groupManager = $groupManager;
151
-		$this->userSession = $userSession;
152
-		$this->config = $config;
153
-		$this->isAdmin = $isAdmin;
154
-		$this->l10n = $l10n;
155
-		$this->log = $log;
156
-		$this->mailer = $mailer;
157
-		$this->appManager = $appManager;
158
-		$this->avatarManager = $avatarManager;
159
-		$this->accountManager = $accountManager;
160
-		$this->secureRandom = $secureRandom;
161
-		$this->newUserMailHelper = $newUserMailHelper;
162
-		$this->timeFactory = $timeFactory;
163
-		$this->crypto = $crypto;
164
-		$this->keyManager = $keyManager;
165
-		$this->jobList = $jobList;
166
-		$this->userMountCache = $userMountCache;
167
-
168
-		// check for encryption state - TODO see formatUserForIndex
169
-		$this->isEncryptionAppEnabled = $appManager->isEnabledForUser('encryption');
170
-		if ($this->isEncryptionAppEnabled) {
171
-			// putting this directly in empty is possible in PHP 5.5+
172
-			$result = $config->getAppValue('encryption', 'recoveryAdminEnabled', 0);
173
-			$this->isRestoreEnabled = !empty($result);
174
-		}
175
-	}
176
-
177
-	/**
178
-	 * @param IUser $user
179
-	 * @param array $userGroups
180
-	 * @return array
181
-	 */
182
-	private function formatUserForIndex(IUser $user, array $userGroups = null) {
183
-
184
-		// TODO: eliminate this encryption specific code below and somehow
185
-		// hook in additional user info from other apps
186
-
187
-		// recovery isn't possible if admin or user has it disabled and encryption
188
-		// is enabled - so we eliminate the else paths in the conditional tree
189
-		// below
190
-		$restorePossible = false;
191
-
192
-		if ($this->isEncryptionAppEnabled) {
193
-			if ($this->isRestoreEnabled) {
194
-				// check for the users recovery setting
195
-				$recoveryMode = $this->config->getUserValue($user->getUID(), 'encryption', 'recoveryEnabled', '0');
196
-				// method call inside empty is possible with PHP 5.5+
197
-				$recoveryModeEnabled = !empty($recoveryMode);
198
-				if ($recoveryModeEnabled) {
199
-					// user also has recovery mode enabled
200
-					$restorePossible = true;
201
-				}
202
-			}
203
-		} else {
204
-			// recovery is possible if encryption is disabled (plain files are
205
-			// available)
206
-			$restorePossible = true;
207
-		}
208
-
209
-		$subAdminGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($user);
210
-		foreach ($subAdminGroups as $key => $subAdminGroup) {
211
-			$subAdminGroups[$key] = $subAdminGroup->getGID();
212
-		}
213
-
214
-		$displayName = $user->getEMailAddress();
215
-		if (is_null($displayName)) {
216
-			$displayName = '';
217
-		}
218
-
219
-		$avatarAvailable = false;
220
-		try {
221
-			$avatarAvailable = $this->avatarManager->getAvatar($user->getUID())->exists();
222
-		} catch (\Exception $e) {
223
-			//No avatar yet
224
-		}
225
-
226
-		return [
227
-			'name' => $user->getUID(),
228
-			'displayname' => $user->getDisplayName(),
229
-			'groups' => (empty($userGroups)) ? $this->groupManager->getUserGroupIds($user) : $userGroups,
230
-			'subadmin' => $subAdminGroups,
231
-			'quota' => $user->getQuota(),
232
-			'quota_bytes' => Util::computerFileSize($user->getQuota()),
233
-			'storageLocation' => $user->getHome(),
234
-			'lastLogin' => $user->getLastLogin() * 1000,
235
-			'backend' => $user->getBackendClassName(),
236
-			'email' => $displayName,
237
-			'isRestoreDisabled' => !$restorePossible,
238
-			'isAvatarAvailable' => $avatarAvailable,
239
-			'isEnabled' => $user->isEnabled(),
240
-		];
241
-	}
242
-
243
-	/**
244
-	 * @param array $userIDs Array with schema [$uid => $displayName]
245
-	 * @return IUser[]
246
-	 */
247
-	private function getUsersForUID(array $userIDs) {
248
-		$users = [];
249
-		foreach ($userIDs as $uid => $displayName) {
250
-			$users[$uid] = $this->userManager->get($uid);
251
-		}
252
-		return $users;
253
-	}
254
-
255
-	/**
256
-	 * @NoAdminRequired
257
-	 *
258
-	 * @param int $offset
259
-	 * @param int $limit
260
-	 * @param string $gid GID to filter for
261
-	 * @param string $pattern Pattern to search for in the username
262
-	 * @param string $backend Backend to filter for (class-name)
263
-	 * @return DataResponse
264
-	 *
265
-	 * TODO: Tidy up and write unit tests - code is mainly static method calls
266
-	 */
267
-	public function index($offset = 0, $limit = 10, $gid = '', $pattern = '', $backend = '') {
268
-		// Remove backends
269
-		if (!empty($backend)) {
270
-			$activeBackends = $this->userManager->getBackends();
271
-			$this->userManager->clearBackends();
272
-			foreach ($activeBackends as $singleActiveBackend) {
273
-				if ($backend === get_class($singleActiveBackend)) {
274
-					$this->userManager->registerBackend($singleActiveBackend);
275
-					break;
276
-				}
277
-			}
278
-		}
279
-
280
-		$userObjects = [];
281
-		$users = [];
282
-		if ($this->isAdmin) {
283
-			if ($gid !== '' && $gid !== '_disabledUsers') {
284
-				$batch = $this->getUsersForUID($this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset));
285
-			} else {
286
-				$batch = $this->userManager->search($pattern, $limit, $offset);
287
-			}
288
-
289
-			foreach ($batch as $user) {
290
-				if (($gid !== '_disabledUsers' && $user->isEnabled()) ||
291
-					($gid === '_disabledUsers' && !$user->isEnabled())
292
-				) {
293
-					$userObjects[] = $user;
294
-					$users[] = $this->formatUserForIndex($user);
295
-				}
296
-			}
297
-
298
-		} else {
299
-			$subAdminOfGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
300
-			// New class returns IGroup[] so convert back
301
-			$gids = [];
302
-			foreach ($subAdminOfGroups as $group) {
303
-				$gids[] = $group->getGID();
304
-			}
305
-			$subAdminOfGroups = $gids;
306
-
307
-			// Set the $gid parameter to an empty value if the subadmin has no rights to access a specific group
308
-			if ($gid !== '' && $gid !== '_disabledUsers' && !in_array($gid, $subAdminOfGroups)) {
309
-				$gid = '';
310
-			}
311
-
312
-			// Batch all groups the user is subadmin of when a group is specified
313
-			$batch = [];
314
-			if ($gid === '') {
315
-				foreach ($subAdminOfGroups as $group) {
316
-					$groupUsers = $this->groupManager->displayNamesInGroup($group, $pattern, $limit, $offset);
317
-
318
-					foreach ($groupUsers as $uid => $displayName) {
319
-						$batch[$uid] = $displayName;
320
-					}
321
-				}
322
-			} else {
323
-				$batch = $this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset);
324
-			}
325
-			$batch = $this->getUsersForUID($batch);
326
-
327
-			foreach ($batch as $user) {
328
-				// Only add the groups, this user is a subadmin of
329
-				$userGroups = array_values(array_intersect(
330
-					$this->groupManager->getUserGroupIds($user),
331
-					$subAdminOfGroups
332
-				));
333
-				if (($gid !== '_disabledUsers' && $user->isEnabled()) ||
334
-					($gid === '_disabledUsers' && !$user->isEnabled())
335
-				) {
336
-					$userObjects[] = $user;
337
-					$users[] = $this->formatUserForIndex($user, $userGroups);
338
-				}
339
-			}
340
-		}
341
-
342
-		$usedSpace = $this->userMountCache->getUsedSpaceForUsers($userObjects);
343
-
344
-		foreach ($users as &$userData) {
345
-			$userData['size'] = isset($usedSpace[$userData['name']]) ? $usedSpace[$userData['name']] : 0;
346
-		}
347
-
348
-		return new DataResponse($users);
349
-	}
350
-
351
-	/**
352
-	 * @NoAdminRequired
353
-	 * @PasswordConfirmationRequired
354
-	 *
355
-	 * @param string $username
356
-	 * @param string $password
357
-	 * @param array $groups
358
-	 * @param string $email
359
-	 * @return DataResponse
360
-	 */
361
-	public function create($username, $password, array $groups = [], $email = '') {
362
-		if ($email !== '' && !$this->mailer->validateMailAddress($email)) {
363
-			return new DataResponse(
364
-				[
365
-					'message' => (string)$this->l10n->t('Invalid mail address')
366
-				],
367
-				Http::STATUS_UNPROCESSABLE_ENTITY
368
-			);
369
-		}
370
-
371
-		$currentUser = $this->userSession->getUser();
372
-
373
-		if (!$this->isAdmin) {
374
-			if (!empty($groups)) {
375
-				foreach ($groups as $key => $group) {
376
-					$groupObject = $this->groupManager->get($group);
377
-					if ($groupObject === null) {
378
-						unset($groups[$key]);
379
-						continue;
380
-					}
381
-
382
-					if (!$this->groupManager->getSubAdmin()->isSubAdminofGroup($currentUser, $groupObject)) {
383
-						unset($groups[$key]);
384
-					}
385
-				}
386
-			}
387
-
388
-			if (empty($groups)) {
389
-				return new DataResponse(
390
-					[
391
-						'message' => $this->l10n->t('No valid group selected'),
392
-					],
393
-					Http::STATUS_FORBIDDEN
394
-				);
395
-			}
396
-		}
397
-
398
-		if ($this->userManager->userExists($username)) {
399
-			return new DataResponse(
400
-				[
401
-					'message' => (string)$this->l10n->t('A user with that name already exists.')
402
-				],
403
-				Http::STATUS_CONFLICT
404
-			);
405
-		}
406
-
407
-		$generatePasswordResetToken = false;
408
-		if ($password === '') {
409
-			if ($email === '') {
410
-				return new DataResponse(
411
-					[
412
-						'message' => (string)$this->l10n->t('To send a password link to the user an email address is required.')
413
-					],
414
-					Http::STATUS_UNPROCESSABLE_ENTITY
415
-				);
416
-			}
417
-
418
-			$password = $this->secureRandom->generate(32);
419
-			$generatePasswordResetToken = true;
420
-		}
421
-
422
-		try {
423
-			$user = $this->userManager->createUser($username, $password);
424
-		} catch (\Exception $exception) {
425
-			$message = $exception->getMessage();
426
-			if (!$message) {
427
-				$message = $this->l10n->t('Unable to create user.');
428
-			}
429
-			return new DataResponse(
430
-				[
431
-					'message' => (string)$message,
432
-				],
433
-				Http::STATUS_FORBIDDEN
434
-			);
435
-		}
436
-
437
-		if ($user instanceof IUser) {
438
-			if ($groups !== null) {
439
-				foreach ($groups as $groupName) {
440
-					$group = $this->groupManager->get($groupName);
441
-
442
-					if (empty($group)) {
443
-						$group = $this->groupManager->createGroup($groupName);
444
-					}
445
-					$group->addUser($user);
446
-				}
447
-			}
448
-			/**
449
-			 * Send new user mail only if a mail is set
450
-			 */
451
-			if ($email !== '') {
452
-				$user->setEMailAddress($email);
453
-				try {
454
-					$emailTemplate = $this->newUserMailHelper->generateTemplate($user, $generatePasswordResetToken);
455
-					$this->newUserMailHelper->sendMail($user, $emailTemplate);
456
-				} catch (\Exception $e) {
457
-					$this->log->error("Can't send new user mail to $email: " . $e->getMessage(), ['app' => 'settings']);
458
-				}
459
-			}
460
-			// fetch users groups
461
-			$userGroups = $this->groupManager->getUserGroupIds($user);
462
-
463
-			return new DataResponse(
464
-				$this->formatUserForIndex($user, $userGroups),
465
-				Http::STATUS_CREATED
466
-			);
467
-		}
468
-
469
-		return new DataResponse(
470
-			[
471
-				'message' => (string)$this->l10n->t('Unable to create user.')
472
-			],
473
-			Http::STATUS_FORBIDDEN
474
-		);
475
-
476
-	}
477
-
478
-	/**
479
-	 * @NoAdminRequired
480
-	 * @PasswordConfirmationRequired
481
-	 *
482
-	 * @param string $id
483
-	 * @return DataResponse
484
-	 */
485
-	public function destroy($id) {
486
-		$userId = $this->userSession->getUser()->getUID();
487
-		$user = $this->userManager->get($id);
488
-
489
-		if ($userId === $id) {
490
-			return new DataResponse(
491
-				[
492
-					'status' => 'error',
493
-					'data' => [
494
-						'message' => (string)$this->l10n->t('Unable to delete user.')
495
-					]
496
-				],
497
-				Http::STATUS_FORBIDDEN
498
-			);
499
-		}
500
-
501
-		if (!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
502
-			return new DataResponse(
503
-				[
504
-					'status' => 'error',
505
-					'data' => [
506
-						'message' => (string)$this->l10n->t('Authentication error')
507
-					]
508
-				],
509
-				Http::STATUS_FORBIDDEN
510
-			);
511
-		}
512
-
513
-		if ($user) {
514
-			if ($user->delete()) {
515
-				return new DataResponse(
516
-					[
517
-						'status' => 'success',
518
-						'data' => [
519
-							'username' => $id
520
-						]
521
-					],
522
-					Http::STATUS_NO_CONTENT
523
-				);
524
-			}
525
-		}
526
-
527
-		return new DataResponse(
528
-			[
529
-				'status' => 'error',
530
-				'data' => [
531
-					'message' => (string)$this->l10n->t('Unable to delete user.')
532
-				]
533
-			],
534
-			Http::STATUS_FORBIDDEN
535
-		);
536
-	}
537
-
538
-	/**
539
-	 * @NoAdminRequired
540
-	 *
541
-	 * @param string $id
542
-	 * @param int $enabled
543
-	 * @return DataResponse
544
-	 */
545
-	public function setEnabled($id, $enabled) {
546
-		$enabled = (bool)$enabled;
547
-		if ($enabled) {
548
-			$errorMsgGeneral = (string)$this->l10n->t('Error while enabling user.');
549
-		} else {
550
-			$errorMsgGeneral = (string)$this->l10n->t('Error while disabling user.');
551
-		}
552
-
553
-		$userId = $this->userSession->getUser()->getUID();
554
-		$user = $this->userManager->get($id);
555
-
556
-		if ($userId === $id) {
557
-			return new DataResponse(
558
-				[
559
-					'status' => 'error',
560
-					'data' => [
561
-						'message' => $errorMsgGeneral
562
-					]
563
-				], Http::STATUS_FORBIDDEN
564
-			);
565
-		}
566
-
567
-		if ($user) {
568
-			if (!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
569
-				return new DataResponse(
570
-					[
571
-						'status' => 'error',
572
-						'data' => [
573
-							'message' => (string)$this->l10n->t('Authentication error')
574
-						]
575
-					],
576
-					Http::STATUS_FORBIDDEN
577
-				);
578
-			}
579
-
580
-			$user->setEnabled($enabled);
581
-			return new DataResponse(
582
-				[
583
-					'status' => 'success',
584
-					'data' => [
585
-						'username' => $id,
586
-						'enabled' => $enabled
587
-					]
588
-				]
589
-			);
590
-		} else {
591
-			return new DataResponse(
592
-				[
593
-					'status' => 'error',
594
-					'data' => [
595
-						'message' => $errorMsgGeneral
596
-					]
597
-				],
598
-				Http::STATUS_FORBIDDEN
599
-			);
600
-		}
601
-
602
-	}
603
-
604
-	/**
605
-	 * Set the mail address of a user
606
-	 *
607
-	 * @NoAdminRequired
608
-	 * @NoSubadminRequired
609
-	 * @PasswordConfirmationRequired
610
-	 *
611
-	 * @param string $account
612
-	 * @param bool $onlyVerificationCode only return verification code without updating the data
613
-	 * @return DataResponse
614
-	 */
615
-	public function getVerificationCode($account, $onlyVerificationCode) {
616
-
617
-		$user = $this->userSession->getUser();
618
-
619
-		if ($user === null) {
620
-			return new DataResponse([], Http::STATUS_BAD_REQUEST);
621
-		}
622
-
623
-		$accountData = $this->accountManager->getUser($user);
624
-		$cloudId = $user->getCloudId();
625
-		$message = "Use my Federated Cloud ID to share with me: " . $cloudId;
626
-		$signature = $this->signMessage($user, $message);
627
-
628
-		$code = $message . ' ' . $signature;
629
-		$codeMd5 = $message . ' ' . md5($signature);
630
-
631
-		switch ($account) {
632
-			case 'verify-twitter':
633
-				$accountData[AccountManager::PROPERTY_TWITTER]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
634
-				$msg = $this->l10n->t('In order to verify your Twitter account, post the following tweet on Twitter (please make sure to post it without any line breaks):');
635
-				$code = $codeMd5;
636
-				$type = AccountManager::PROPERTY_TWITTER;
637
-				$data = $accountData[AccountManager::PROPERTY_TWITTER]['value'];
638
-				$accountData[AccountManager::PROPERTY_TWITTER]['signature'] = $signature;
639
-				break;
640
-			case 'verify-website':
641
-				$accountData[AccountManager::PROPERTY_WEBSITE]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
642
-				$msg = $this->l10n->t('In order to verify your Website, store the following content in your web-root at \'.well-known/CloudIdVerificationCode.txt\' (please make sure that the complete text is in one line):');
643
-				$type = AccountManager::PROPERTY_WEBSITE;
644
-				$data = $accountData[AccountManager::PROPERTY_WEBSITE]['value'];
645
-				$accountData[AccountManager::PROPERTY_WEBSITE]['signature'] = $signature;
646
-				break;
647
-			default:
648
-				return new DataResponse([], Http::STATUS_BAD_REQUEST);
649
-		}
650
-
651
-		if ($onlyVerificationCode === false) {
652
-			$this->accountManager->updateUser($user, $accountData);
653
-
654
-			$this->jobList->add('OC\Settings\BackgroundJobs\VerifyUserData',
655
-				[
656
-					'verificationCode' => $code,
657
-					'data' => $data,
658
-					'type' => $type,
659
-					'uid' => $user->getUID(),
660
-					'try' => 0,
661
-					'lastRun' => $this->getCurrentTime()
662
-				]
663
-			);
664
-		}
665
-
666
-		return new DataResponse(['msg' => $msg, 'code' => $code]);
667
-	}
668
-
669
-	/**
670
-	 * get current timestamp
671
-	 *
672
-	 * @return int
673
-	 */
674
-	protected function getCurrentTime() {
675
-		return time();
676
-	}
677
-
678
-	/**
679
-	 * sign message with users private key
680
-	 *
681
-	 * @param IUser $user
682
-	 * @param string $message
683
-	 *
684
-	 * @return string base64 encoded signature
685
-	 */
686
-	protected function signMessage(IUser $user, $message) {
687
-		$privateKey = $this->keyManager->getKey($user)->getPrivate();
688
-		openssl_sign(json_encode($message), $signature, $privateKey, OPENSSL_ALGO_SHA512);
689
-		$signatureBase64 = base64_encode($signature);
690
-
691
-		return $signatureBase64;
692
-	}
693
-
694
-	/**
695
-	 * @NoAdminRequired
696
-	 * @NoSubadminRequired
697
-	 * @PasswordConfirmationRequired
698
-	 *
699
-	 * @param string $avatarScope
700
-	 * @param string $displayname
701
-	 * @param string $displaynameScope
702
-	 * @param string $phone
703
-	 * @param string $phoneScope
704
-	 * @param string $email
705
-	 * @param string $emailScope
706
-	 * @param string $website
707
-	 * @param string $websiteScope
708
-	 * @param string $address
709
-	 * @param string $addressScope
710
-	 * @param string $twitter
711
-	 * @param string $twitterScope
712
-	 * @return DataResponse
713
-	 */
714
-	public function setUserSettings($avatarScope,
715
-									$displayname,
716
-									$displaynameScope,
717
-									$phone,
718
-									$phoneScope,
719
-									$email,
720
-									$emailScope,
721
-									$website,
722
-									$websiteScope,
723
-									$address,
724
-									$addressScope,
725
-									$twitter,
726
-									$twitterScope
727
-	) {
728
-
729
-		if (!empty($email) && !$this->mailer->validateMailAddress($email)) {
730
-			return new DataResponse(
731
-				[
732
-					'status' => 'error',
733
-					'data' => [
734
-						'message' => (string)$this->l10n->t('Invalid mail address')
735
-					]
736
-				],
737
-				Http::STATUS_UNPROCESSABLE_ENTITY
738
-			);
739
-		}
740
-
741
-		$user = $this->userSession->getUser();
742
-
743
-		$data = $this->accountManager->getUser($user);
744
-
745
-		$data[AccountManager::PROPERTY_AVATAR] = ['scope' => $avatarScope];
746
-		if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
747
-			$data[AccountManager::PROPERTY_DISPLAYNAME] = ['value' => $displayname, 'scope' => $displaynameScope];
748
-			$data[AccountManager::PROPERTY_EMAIL] = ['value' => $email, 'scope' => $emailScope];
749
-		}
750
-
751
-		if ($this->appManager->isEnabledForUser('federatedfilesharing')) {
752
-			$federatedFileSharing = new \OCA\FederatedFileSharing\AppInfo\Application();
753
-			$shareProvider = $federatedFileSharing->getFederatedShareProvider();
754
-			if ($shareProvider->isLookupServerUploadEnabled()) {
755
-				$data[AccountManager::PROPERTY_WEBSITE] = ['value' => $website, 'scope' => $websiteScope];
756
-				$data[AccountManager::PROPERTY_ADDRESS] = ['value' => $address, 'scope' => $addressScope];
757
-				$data[AccountManager::PROPERTY_PHONE] = ['value' => $phone, 'scope' => $phoneScope];
758
-				$data[AccountManager::PROPERTY_TWITTER] = ['value' => $twitter, 'scope' => $twitterScope];
759
-			}
760
-		}
761
-
762
-		try {
763
-			$this->saveUserSettings($user, $data);
764
-			return new DataResponse(
765
-				[
766
-					'status' => 'success',
767
-					'data' => [
768
-						'userId' => $user->getUID(),
769
-						'avatarScope' => $data[AccountManager::PROPERTY_AVATAR]['scope'],
770
-						'displayname' => $data[AccountManager::PROPERTY_DISPLAYNAME]['value'],
771
-						'displaynameScope' => $data[AccountManager::PROPERTY_DISPLAYNAME]['scope'],
772
-						'email' => $data[AccountManager::PROPERTY_EMAIL]['value'],
773
-						'emailScope' => $data[AccountManager::PROPERTY_EMAIL]['scope'],
774
-						'website' => $data[AccountManager::PROPERTY_WEBSITE]['value'],
775
-						'websiteScope' => $data[AccountManager::PROPERTY_WEBSITE]['scope'],
776
-						'address' => $data[AccountManager::PROPERTY_ADDRESS]['value'],
777
-						'addressScope' => $data[AccountManager::PROPERTY_ADDRESS]['scope'],
778
-						'message' => (string)$this->l10n->t('Settings saved')
779
-					]
780
-				],
781
-				Http::STATUS_OK
782
-			);
783
-		} catch (ForbiddenException $e) {
784
-			return new DataResponse([
785
-				'status' => 'error',
786
-				'data' => [
787
-					'message' => $e->getMessage()
788
-				],
789
-			]);
790
-		}
791
-
792
-	}
793
-
794
-
795
-	/**
796
-	 * update account manager with new user data
797
-	 *
798
-	 * @param IUser $user
799
-	 * @param array $data
800
-	 * @throws ForbiddenException
801
-	 */
802
-	protected function saveUserSettings(IUser $user, $data) {
803
-
804
-		// keep the user back-end up-to-date with the latest display name and email
805
-		// address
806
-		$oldDisplayName = $user->getDisplayName();
807
-		$oldDisplayName = is_null($oldDisplayName) ? '' : $oldDisplayName;
808
-		if (isset($data[AccountManager::PROPERTY_DISPLAYNAME]['value'])
809
-			&& $oldDisplayName !== $data[AccountManager::PROPERTY_DISPLAYNAME]['value']
810
-		) {
811
-			$result = $user->setDisplayName($data[AccountManager::PROPERTY_DISPLAYNAME]['value']);
812
-			if ($result === false) {
813
-				throw new ForbiddenException($this->l10n->t('Unable to change full name'));
814
-			}
815
-		}
816
-
817
-		$oldEmailAddress = $user->getEMailAddress();
818
-		$oldEmailAddress = is_null($oldEmailAddress) ? '' : $oldEmailAddress;
819
-		if (isset($data[AccountManager::PROPERTY_EMAIL]['value'])
820
-			&& $oldEmailAddress !== $data[AccountManager::PROPERTY_EMAIL]['value']
821
-		) {
822
-			// this is the only permission a backend provides and is also used
823
-			// for the permission of setting a email address
824
-			if (!$user->canChangeDisplayName()) {
825
-				throw new ForbiddenException($this->l10n->t('Unable to change email address'));
826
-			}
827
-			$user->setEMailAddress($data[AccountManager::PROPERTY_EMAIL]['value']);
828
-		}
829
-
830
-		$this->accountManager->updateUser($user, $data);
831
-	}
832
-
833
-	/**
834
-	 * Count all unique users visible for the current admin/subadmin.
835
-	 *
836
-	 * @NoAdminRequired
837
-	 *
838
-	 * @return DataResponse
839
-	 */
840
-	public function stats() {
841
-		$userCount = 0;
842
-		if ($this->isAdmin) {
843
-			$countByBackend = $this->userManager->countUsers();
844
-
845
-			if (!empty($countByBackend)) {
846
-				foreach ($countByBackend as $count) {
847
-					$userCount += $count;
848
-				}
849
-			}
850
-		} else {
851
-			$groups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
852
-
853
-			$uniqueUsers = [];
854
-			foreach ($groups as $group) {
855
-				foreach ($group->getUsers() as $uid => $displayName) {
856
-					$uniqueUsers[$uid] = true;
857
-				}
858
-			}
859
-
860
-			$userCount = count($uniqueUsers);
861
-		}
862
-
863
-		return new DataResponse(
864
-			[
865
-				'totalUsers' => $userCount
866
-			]
867
-		);
868
-	}
869
-
870
-
871
-	/**
872
-	 * Set the displayName of a user
873
-	 *
874
-	 * @NoAdminRequired
875
-	 * @NoSubadminRequired
876
-	 * @PasswordConfirmationRequired
877
-	 * @todo merge into saveUserSettings
878
-	 *
879
-	 * @param string $username
880
-	 * @param string $displayName
881
-	 * @return DataResponse
882
-	 */
883
-	public function setDisplayName($username, $displayName) {
884
-		$currentUser = $this->userSession->getUser();
885
-		$user = $this->userManager->get($username);
886
-
887
-		if ($user === null ||
888
-			!$user->canChangeDisplayName() ||
889
-			(
890
-				!$this->groupManager->isAdmin($currentUser->getUID()) &&
891
-				!$this->groupManager->getSubAdmin()->isUserAccessible($currentUser, $user) &&
892
-				$currentUser->getUID() !== $username
893
-
894
-			)
895
-		) {
896
-			return new DataResponse([
897
-				'status' => 'error',
898
-				'data' => [
899
-					'message' => $this->l10n->t('Authentication error'),
900
-				],
901
-			]);
902
-		}
903
-
904
-		$userData = $this->accountManager->getUser($user);
905
-		$userData[AccountManager::PROPERTY_DISPLAYNAME]['value'] = $displayName;
906
-
907
-
908
-		try {
909
-			$this->saveUserSettings($user, $userData);
910
-			return new DataResponse([
911
-				'status' => 'success',
912
-				'data' => [
913
-					'message' => $this->l10n->t('Your full name has been changed.'),
914
-					'username' => $username,
915
-					'displayName' => $displayName,
916
-				],
917
-			]);
918
-		} catch (ForbiddenException $e) {
919
-			return new DataResponse([
920
-				'status' => 'error',
921
-				'data' => [
922
-					'message' => $e->getMessage(),
923
-					'displayName' => $user->getDisplayName(),
924
-				],
925
-			]);
926
-		}
927
-	}
928
-
929
-	/**
930
-	 * Set the mail address of a user
931
-	 *
932
-	 * @NoAdminRequired
933
-	 * @NoSubadminRequired
934
-	 * @PasswordConfirmationRequired
935
-	 *
936
-	 * @param string $id
937
-	 * @param string $mailAddress
938
-	 * @return DataResponse
939
-	 */
940
-	public function setEMailAddress($id, $mailAddress) {
941
-		$user = $this->userManager->get($id);
942
-		if (!$this->isAdmin
943
-			&& !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)
944
-		) {
945
-			return new DataResponse(
946
-				[
947
-					'status' => 'error',
948
-					'data' => [
949
-						'message' => (string)$this->l10n->t('Forbidden')
950
-					]
951
-				],
952
-				Http::STATUS_FORBIDDEN
953
-			);
954
-		}
955
-
956
-		if ($mailAddress !== '' && !$this->mailer->validateMailAddress($mailAddress)) {
957
-			return new DataResponse(
958
-				[
959
-					'status' => 'error',
960
-					'data' => [
961
-						'message' => (string)$this->l10n->t('Invalid mail address')
962
-					]
963
-				],
964
-				Http::STATUS_UNPROCESSABLE_ENTITY
965
-			);
966
-		}
967
-
968
-		if (!$user) {
969
-			return new DataResponse(
970
-				[
971
-					'status' => 'error',
972
-					'data' => [
973
-						'message' => (string)$this->l10n->t('Invalid user')
974
-					]
975
-				],
976
-				Http::STATUS_UNPROCESSABLE_ENTITY
977
-			);
978
-		}
979
-		// this is the only permission a backend provides and is also used
980
-		// for the permission of setting a email address
981
-		if (!$user->canChangeDisplayName()) {
982
-			return new DataResponse(
983
-				[
984
-					'status' => 'error',
985
-					'data' => [
986
-						'message' => (string)$this->l10n->t('Unable to change mail address')
987
-					]
988
-				],
989
-				Http::STATUS_FORBIDDEN
990
-			);
991
-		}
992
-
993
-		$userData = $this->accountManager->getUser($user);
994
-		$userData[AccountManager::PROPERTY_EMAIL]['value'] = $mailAddress;
995
-
996
-		try {
997
-			$this->saveUserSettings($user, $userData);
998
-			return new DataResponse(
999
-				[
1000
-					'status' => 'success',
1001
-					'data' => [
1002
-						'username' => $id,
1003
-						'mailAddress' => $mailAddress,
1004
-						'message' => (string)$this->l10n->t('Email saved')
1005
-					]
1006
-				],
1007
-				Http::STATUS_OK
1008
-			);
1009
-		} catch (ForbiddenException $e) {
1010
-			return new DataResponse([
1011
-				'status' => 'error',
1012
-				'data' => [
1013
-					'message' => $e->getMessage()
1014
-				],
1015
-			]);
1016
-		}
1017
-	}
63
+    /** @var IL10N */
64
+    private $l10n;
65
+    /** @var IUserSession */
66
+    private $userSession;
67
+    /** @var bool */
68
+    private $isAdmin;
69
+    /** @var IUserManager */
70
+    private $userManager;
71
+    /** @var IGroupManager */
72
+    private $groupManager;
73
+    /** @var IConfig */
74
+    private $config;
75
+    /** @var ILogger */
76
+    private $log;
77
+    /** @var IMailer */
78
+    private $mailer;
79
+    /** @var bool contains the state of the encryption app */
80
+    private $isEncryptionAppEnabled;
81
+    /** @var bool contains the state of the admin recovery setting */
82
+    private $isRestoreEnabled = false;
83
+    /** @var IAppManager */
84
+    private $appManager;
85
+    /** @var IAvatarManager */
86
+    private $avatarManager;
87
+    /** @var AccountManager */
88
+    private $accountManager;
89
+    /** @var ISecureRandom */
90
+    private $secureRandom;
91
+    /** @var NewUserMailHelper */
92
+    private $newUserMailHelper;
93
+    /** @var ITimeFactory */
94
+    private $timeFactory;
95
+    /** @var ICrypto */
96
+    private $crypto;
97
+    /** @var Manager */
98
+    private $keyManager;
99
+    /** @var IJobList */
100
+    private $jobList;
101
+    /** @var IUserMountCache */
102
+    private $userMountCache;
103
+
104
+    /**
105
+     * @param string $appName
106
+     * @param IRequest $request
107
+     * @param IUserManager $userManager
108
+     * @param IGroupManager $groupManager
109
+     * @param IUserSession $userSession
110
+     * @param IConfig $config
111
+     * @param bool $isAdmin
112
+     * @param IL10N $l10n
113
+     * @param ILogger $log
114
+     * @param IMailer $mailer
115
+     * @param IURLGenerator $urlGenerator
116
+     * @param IAppManager $appManager
117
+     * @param IAvatarManager $avatarManager
118
+     * @param AccountManager $accountManager
119
+     * @param ISecureRandom $secureRandom
120
+     * @param NewUserMailHelper $newUserMailHelper
121
+     * @param ITimeFactory $timeFactory
122
+     * @param ICrypto $crypto
123
+     * @param Manager $keyManager
124
+     * @param IJobList $jobList
125
+     * @param IUserMountCache $userMountCache
126
+     */
127
+    public function __construct($appName,
128
+                                IRequest $request,
129
+                                IUserManager $userManager,
130
+                                IGroupManager $groupManager,
131
+                                IUserSession $userSession,
132
+                                IConfig $config,
133
+                                $isAdmin,
134
+                                IL10N $l10n,
135
+                                ILogger $log,
136
+                                IMailer $mailer,
137
+                                IURLGenerator $urlGenerator,
138
+                                IAppManager $appManager,
139
+                                IAvatarManager $avatarManager,
140
+                                AccountManager $accountManager,
141
+                                ISecureRandom $secureRandom,
142
+                                NewUserMailHelper $newUserMailHelper,
143
+                                ITimeFactory $timeFactory,
144
+                                ICrypto $crypto,
145
+                                Manager $keyManager,
146
+                                IJobList $jobList,
147
+                                IUserMountCache $userMountCache) {
148
+        parent::__construct($appName, $request);
149
+        $this->userManager = $userManager;
150
+        $this->groupManager = $groupManager;
151
+        $this->userSession = $userSession;
152
+        $this->config = $config;
153
+        $this->isAdmin = $isAdmin;
154
+        $this->l10n = $l10n;
155
+        $this->log = $log;
156
+        $this->mailer = $mailer;
157
+        $this->appManager = $appManager;
158
+        $this->avatarManager = $avatarManager;
159
+        $this->accountManager = $accountManager;
160
+        $this->secureRandom = $secureRandom;
161
+        $this->newUserMailHelper = $newUserMailHelper;
162
+        $this->timeFactory = $timeFactory;
163
+        $this->crypto = $crypto;
164
+        $this->keyManager = $keyManager;
165
+        $this->jobList = $jobList;
166
+        $this->userMountCache = $userMountCache;
167
+
168
+        // check for encryption state - TODO see formatUserForIndex
169
+        $this->isEncryptionAppEnabled = $appManager->isEnabledForUser('encryption');
170
+        if ($this->isEncryptionAppEnabled) {
171
+            // putting this directly in empty is possible in PHP 5.5+
172
+            $result = $config->getAppValue('encryption', 'recoveryAdminEnabled', 0);
173
+            $this->isRestoreEnabled = !empty($result);
174
+        }
175
+    }
176
+
177
+    /**
178
+     * @param IUser $user
179
+     * @param array $userGroups
180
+     * @return array
181
+     */
182
+    private function formatUserForIndex(IUser $user, array $userGroups = null) {
183
+
184
+        // TODO: eliminate this encryption specific code below and somehow
185
+        // hook in additional user info from other apps
186
+
187
+        // recovery isn't possible if admin or user has it disabled and encryption
188
+        // is enabled - so we eliminate the else paths in the conditional tree
189
+        // below
190
+        $restorePossible = false;
191
+
192
+        if ($this->isEncryptionAppEnabled) {
193
+            if ($this->isRestoreEnabled) {
194
+                // check for the users recovery setting
195
+                $recoveryMode = $this->config->getUserValue($user->getUID(), 'encryption', 'recoveryEnabled', '0');
196
+                // method call inside empty is possible with PHP 5.5+
197
+                $recoveryModeEnabled = !empty($recoveryMode);
198
+                if ($recoveryModeEnabled) {
199
+                    // user also has recovery mode enabled
200
+                    $restorePossible = true;
201
+                }
202
+            }
203
+        } else {
204
+            // recovery is possible if encryption is disabled (plain files are
205
+            // available)
206
+            $restorePossible = true;
207
+        }
208
+
209
+        $subAdminGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($user);
210
+        foreach ($subAdminGroups as $key => $subAdminGroup) {
211
+            $subAdminGroups[$key] = $subAdminGroup->getGID();
212
+        }
213
+
214
+        $displayName = $user->getEMailAddress();
215
+        if (is_null($displayName)) {
216
+            $displayName = '';
217
+        }
218
+
219
+        $avatarAvailable = false;
220
+        try {
221
+            $avatarAvailable = $this->avatarManager->getAvatar($user->getUID())->exists();
222
+        } catch (\Exception $e) {
223
+            //No avatar yet
224
+        }
225
+
226
+        return [
227
+            'name' => $user->getUID(),
228
+            'displayname' => $user->getDisplayName(),
229
+            'groups' => (empty($userGroups)) ? $this->groupManager->getUserGroupIds($user) : $userGroups,
230
+            'subadmin' => $subAdminGroups,
231
+            'quota' => $user->getQuota(),
232
+            'quota_bytes' => Util::computerFileSize($user->getQuota()),
233
+            'storageLocation' => $user->getHome(),
234
+            'lastLogin' => $user->getLastLogin() * 1000,
235
+            'backend' => $user->getBackendClassName(),
236
+            'email' => $displayName,
237
+            'isRestoreDisabled' => !$restorePossible,
238
+            'isAvatarAvailable' => $avatarAvailable,
239
+            'isEnabled' => $user->isEnabled(),
240
+        ];
241
+    }
242
+
243
+    /**
244
+     * @param array $userIDs Array with schema [$uid => $displayName]
245
+     * @return IUser[]
246
+     */
247
+    private function getUsersForUID(array $userIDs) {
248
+        $users = [];
249
+        foreach ($userIDs as $uid => $displayName) {
250
+            $users[$uid] = $this->userManager->get($uid);
251
+        }
252
+        return $users;
253
+    }
254
+
255
+    /**
256
+     * @NoAdminRequired
257
+     *
258
+     * @param int $offset
259
+     * @param int $limit
260
+     * @param string $gid GID to filter for
261
+     * @param string $pattern Pattern to search for in the username
262
+     * @param string $backend Backend to filter for (class-name)
263
+     * @return DataResponse
264
+     *
265
+     * TODO: Tidy up and write unit tests - code is mainly static method calls
266
+     */
267
+    public function index($offset = 0, $limit = 10, $gid = '', $pattern = '', $backend = '') {
268
+        // Remove backends
269
+        if (!empty($backend)) {
270
+            $activeBackends = $this->userManager->getBackends();
271
+            $this->userManager->clearBackends();
272
+            foreach ($activeBackends as $singleActiveBackend) {
273
+                if ($backend === get_class($singleActiveBackend)) {
274
+                    $this->userManager->registerBackend($singleActiveBackend);
275
+                    break;
276
+                }
277
+            }
278
+        }
279
+
280
+        $userObjects = [];
281
+        $users = [];
282
+        if ($this->isAdmin) {
283
+            if ($gid !== '' && $gid !== '_disabledUsers') {
284
+                $batch = $this->getUsersForUID($this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset));
285
+            } else {
286
+                $batch = $this->userManager->search($pattern, $limit, $offset);
287
+            }
288
+
289
+            foreach ($batch as $user) {
290
+                if (($gid !== '_disabledUsers' && $user->isEnabled()) ||
291
+                    ($gid === '_disabledUsers' && !$user->isEnabled())
292
+                ) {
293
+                    $userObjects[] = $user;
294
+                    $users[] = $this->formatUserForIndex($user);
295
+                }
296
+            }
297
+
298
+        } else {
299
+            $subAdminOfGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
300
+            // New class returns IGroup[] so convert back
301
+            $gids = [];
302
+            foreach ($subAdminOfGroups as $group) {
303
+                $gids[] = $group->getGID();
304
+            }
305
+            $subAdminOfGroups = $gids;
306
+
307
+            // Set the $gid parameter to an empty value if the subadmin has no rights to access a specific group
308
+            if ($gid !== '' && $gid !== '_disabledUsers' && !in_array($gid, $subAdminOfGroups)) {
309
+                $gid = '';
310
+            }
311
+
312
+            // Batch all groups the user is subadmin of when a group is specified
313
+            $batch = [];
314
+            if ($gid === '') {
315
+                foreach ($subAdminOfGroups as $group) {
316
+                    $groupUsers = $this->groupManager->displayNamesInGroup($group, $pattern, $limit, $offset);
317
+
318
+                    foreach ($groupUsers as $uid => $displayName) {
319
+                        $batch[$uid] = $displayName;
320
+                    }
321
+                }
322
+            } else {
323
+                $batch = $this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset);
324
+            }
325
+            $batch = $this->getUsersForUID($batch);
326
+
327
+            foreach ($batch as $user) {
328
+                // Only add the groups, this user is a subadmin of
329
+                $userGroups = array_values(array_intersect(
330
+                    $this->groupManager->getUserGroupIds($user),
331
+                    $subAdminOfGroups
332
+                ));
333
+                if (($gid !== '_disabledUsers' && $user->isEnabled()) ||
334
+                    ($gid === '_disabledUsers' && !$user->isEnabled())
335
+                ) {
336
+                    $userObjects[] = $user;
337
+                    $users[] = $this->formatUserForIndex($user, $userGroups);
338
+                }
339
+            }
340
+        }
341
+
342
+        $usedSpace = $this->userMountCache->getUsedSpaceForUsers($userObjects);
343
+
344
+        foreach ($users as &$userData) {
345
+            $userData['size'] = isset($usedSpace[$userData['name']]) ? $usedSpace[$userData['name']] : 0;
346
+        }
347
+
348
+        return new DataResponse($users);
349
+    }
350
+
351
+    /**
352
+     * @NoAdminRequired
353
+     * @PasswordConfirmationRequired
354
+     *
355
+     * @param string $username
356
+     * @param string $password
357
+     * @param array $groups
358
+     * @param string $email
359
+     * @return DataResponse
360
+     */
361
+    public function create($username, $password, array $groups = [], $email = '') {
362
+        if ($email !== '' && !$this->mailer->validateMailAddress($email)) {
363
+            return new DataResponse(
364
+                [
365
+                    'message' => (string)$this->l10n->t('Invalid mail address')
366
+                ],
367
+                Http::STATUS_UNPROCESSABLE_ENTITY
368
+            );
369
+        }
370
+
371
+        $currentUser = $this->userSession->getUser();
372
+
373
+        if (!$this->isAdmin) {
374
+            if (!empty($groups)) {
375
+                foreach ($groups as $key => $group) {
376
+                    $groupObject = $this->groupManager->get($group);
377
+                    if ($groupObject === null) {
378
+                        unset($groups[$key]);
379
+                        continue;
380
+                    }
381
+
382
+                    if (!$this->groupManager->getSubAdmin()->isSubAdminofGroup($currentUser, $groupObject)) {
383
+                        unset($groups[$key]);
384
+                    }
385
+                }
386
+            }
387
+
388
+            if (empty($groups)) {
389
+                return new DataResponse(
390
+                    [
391
+                        'message' => $this->l10n->t('No valid group selected'),
392
+                    ],
393
+                    Http::STATUS_FORBIDDEN
394
+                );
395
+            }
396
+        }
397
+
398
+        if ($this->userManager->userExists($username)) {
399
+            return new DataResponse(
400
+                [
401
+                    'message' => (string)$this->l10n->t('A user with that name already exists.')
402
+                ],
403
+                Http::STATUS_CONFLICT
404
+            );
405
+        }
406
+
407
+        $generatePasswordResetToken = false;
408
+        if ($password === '') {
409
+            if ($email === '') {
410
+                return new DataResponse(
411
+                    [
412
+                        'message' => (string)$this->l10n->t('To send a password link to the user an email address is required.')
413
+                    ],
414
+                    Http::STATUS_UNPROCESSABLE_ENTITY
415
+                );
416
+            }
417
+
418
+            $password = $this->secureRandom->generate(32);
419
+            $generatePasswordResetToken = true;
420
+        }
421
+
422
+        try {
423
+            $user = $this->userManager->createUser($username, $password);
424
+        } catch (\Exception $exception) {
425
+            $message = $exception->getMessage();
426
+            if (!$message) {
427
+                $message = $this->l10n->t('Unable to create user.');
428
+            }
429
+            return new DataResponse(
430
+                [
431
+                    'message' => (string)$message,
432
+                ],
433
+                Http::STATUS_FORBIDDEN
434
+            );
435
+        }
436
+
437
+        if ($user instanceof IUser) {
438
+            if ($groups !== null) {
439
+                foreach ($groups as $groupName) {
440
+                    $group = $this->groupManager->get($groupName);
441
+
442
+                    if (empty($group)) {
443
+                        $group = $this->groupManager->createGroup($groupName);
444
+                    }
445
+                    $group->addUser($user);
446
+                }
447
+            }
448
+            /**
449
+             * Send new user mail only if a mail is set
450
+             */
451
+            if ($email !== '') {
452
+                $user->setEMailAddress($email);
453
+                try {
454
+                    $emailTemplate = $this->newUserMailHelper->generateTemplate($user, $generatePasswordResetToken);
455
+                    $this->newUserMailHelper->sendMail($user, $emailTemplate);
456
+                } catch (\Exception $e) {
457
+                    $this->log->error("Can't send new user mail to $email: " . $e->getMessage(), ['app' => 'settings']);
458
+                }
459
+            }
460
+            // fetch users groups
461
+            $userGroups = $this->groupManager->getUserGroupIds($user);
462
+
463
+            return new DataResponse(
464
+                $this->formatUserForIndex($user, $userGroups),
465
+                Http::STATUS_CREATED
466
+            );
467
+        }
468
+
469
+        return new DataResponse(
470
+            [
471
+                'message' => (string)$this->l10n->t('Unable to create user.')
472
+            ],
473
+            Http::STATUS_FORBIDDEN
474
+        );
475
+
476
+    }
477
+
478
+    /**
479
+     * @NoAdminRequired
480
+     * @PasswordConfirmationRequired
481
+     *
482
+     * @param string $id
483
+     * @return DataResponse
484
+     */
485
+    public function destroy($id) {
486
+        $userId = $this->userSession->getUser()->getUID();
487
+        $user = $this->userManager->get($id);
488
+
489
+        if ($userId === $id) {
490
+            return new DataResponse(
491
+                [
492
+                    'status' => 'error',
493
+                    'data' => [
494
+                        'message' => (string)$this->l10n->t('Unable to delete user.')
495
+                    ]
496
+                ],
497
+                Http::STATUS_FORBIDDEN
498
+            );
499
+        }
500
+
501
+        if (!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
502
+            return new DataResponse(
503
+                [
504
+                    'status' => 'error',
505
+                    'data' => [
506
+                        'message' => (string)$this->l10n->t('Authentication error')
507
+                    ]
508
+                ],
509
+                Http::STATUS_FORBIDDEN
510
+            );
511
+        }
512
+
513
+        if ($user) {
514
+            if ($user->delete()) {
515
+                return new DataResponse(
516
+                    [
517
+                        'status' => 'success',
518
+                        'data' => [
519
+                            'username' => $id
520
+                        ]
521
+                    ],
522
+                    Http::STATUS_NO_CONTENT
523
+                );
524
+            }
525
+        }
526
+
527
+        return new DataResponse(
528
+            [
529
+                'status' => 'error',
530
+                'data' => [
531
+                    'message' => (string)$this->l10n->t('Unable to delete user.')
532
+                ]
533
+            ],
534
+            Http::STATUS_FORBIDDEN
535
+        );
536
+    }
537
+
538
+    /**
539
+     * @NoAdminRequired
540
+     *
541
+     * @param string $id
542
+     * @param int $enabled
543
+     * @return DataResponse
544
+     */
545
+    public function setEnabled($id, $enabled) {
546
+        $enabled = (bool)$enabled;
547
+        if ($enabled) {
548
+            $errorMsgGeneral = (string)$this->l10n->t('Error while enabling user.');
549
+        } else {
550
+            $errorMsgGeneral = (string)$this->l10n->t('Error while disabling user.');
551
+        }
552
+
553
+        $userId = $this->userSession->getUser()->getUID();
554
+        $user = $this->userManager->get($id);
555
+
556
+        if ($userId === $id) {
557
+            return new DataResponse(
558
+                [
559
+                    'status' => 'error',
560
+                    'data' => [
561
+                        'message' => $errorMsgGeneral
562
+                    ]
563
+                ], Http::STATUS_FORBIDDEN
564
+            );
565
+        }
566
+
567
+        if ($user) {
568
+            if (!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
569
+                return new DataResponse(
570
+                    [
571
+                        'status' => 'error',
572
+                        'data' => [
573
+                            'message' => (string)$this->l10n->t('Authentication error')
574
+                        ]
575
+                    ],
576
+                    Http::STATUS_FORBIDDEN
577
+                );
578
+            }
579
+
580
+            $user->setEnabled($enabled);
581
+            return new DataResponse(
582
+                [
583
+                    'status' => 'success',
584
+                    'data' => [
585
+                        'username' => $id,
586
+                        'enabled' => $enabled
587
+                    ]
588
+                ]
589
+            );
590
+        } else {
591
+            return new DataResponse(
592
+                [
593
+                    'status' => 'error',
594
+                    'data' => [
595
+                        'message' => $errorMsgGeneral
596
+                    ]
597
+                ],
598
+                Http::STATUS_FORBIDDEN
599
+            );
600
+        }
601
+
602
+    }
603
+
604
+    /**
605
+     * Set the mail address of a user
606
+     *
607
+     * @NoAdminRequired
608
+     * @NoSubadminRequired
609
+     * @PasswordConfirmationRequired
610
+     *
611
+     * @param string $account
612
+     * @param bool $onlyVerificationCode only return verification code without updating the data
613
+     * @return DataResponse
614
+     */
615
+    public function getVerificationCode($account, $onlyVerificationCode) {
616
+
617
+        $user = $this->userSession->getUser();
618
+
619
+        if ($user === null) {
620
+            return new DataResponse([], Http::STATUS_BAD_REQUEST);
621
+        }
622
+
623
+        $accountData = $this->accountManager->getUser($user);
624
+        $cloudId = $user->getCloudId();
625
+        $message = "Use my Federated Cloud ID to share with me: " . $cloudId;
626
+        $signature = $this->signMessage($user, $message);
627
+
628
+        $code = $message . ' ' . $signature;
629
+        $codeMd5 = $message . ' ' . md5($signature);
630
+
631
+        switch ($account) {
632
+            case 'verify-twitter':
633
+                $accountData[AccountManager::PROPERTY_TWITTER]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
634
+                $msg = $this->l10n->t('In order to verify your Twitter account, post the following tweet on Twitter (please make sure to post it without any line breaks):');
635
+                $code = $codeMd5;
636
+                $type = AccountManager::PROPERTY_TWITTER;
637
+                $data = $accountData[AccountManager::PROPERTY_TWITTER]['value'];
638
+                $accountData[AccountManager::PROPERTY_TWITTER]['signature'] = $signature;
639
+                break;
640
+            case 'verify-website':
641
+                $accountData[AccountManager::PROPERTY_WEBSITE]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
642
+                $msg = $this->l10n->t('In order to verify your Website, store the following content in your web-root at \'.well-known/CloudIdVerificationCode.txt\' (please make sure that the complete text is in one line):');
643
+                $type = AccountManager::PROPERTY_WEBSITE;
644
+                $data = $accountData[AccountManager::PROPERTY_WEBSITE]['value'];
645
+                $accountData[AccountManager::PROPERTY_WEBSITE]['signature'] = $signature;
646
+                break;
647
+            default:
648
+                return new DataResponse([], Http::STATUS_BAD_REQUEST);
649
+        }
650
+
651
+        if ($onlyVerificationCode === false) {
652
+            $this->accountManager->updateUser($user, $accountData);
653
+
654
+            $this->jobList->add('OC\Settings\BackgroundJobs\VerifyUserData',
655
+                [
656
+                    'verificationCode' => $code,
657
+                    'data' => $data,
658
+                    'type' => $type,
659
+                    'uid' => $user->getUID(),
660
+                    'try' => 0,
661
+                    'lastRun' => $this->getCurrentTime()
662
+                ]
663
+            );
664
+        }
665
+
666
+        return new DataResponse(['msg' => $msg, 'code' => $code]);
667
+    }
668
+
669
+    /**
670
+     * get current timestamp
671
+     *
672
+     * @return int
673
+     */
674
+    protected function getCurrentTime() {
675
+        return time();
676
+    }
677
+
678
+    /**
679
+     * sign message with users private key
680
+     *
681
+     * @param IUser $user
682
+     * @param string $message
683
+     *
684
+     * @return string base64 encoded signature
685
+     */
686
+    protected function signMessage(IUser $user, $message) {
687
+        $privateKey = $this->keyManager->getKey($user)->getPrivate();
688
+        openssl_sign(json_encode($message), $signature, $privateKey, OPENSSL_ALGO_SHA512);
689
+        $signatureBase64 = base64_encode($signature);
690
+
691
+        return $signatureBase64;
692
+    }
693
+
694
+    /**
695
+     * @NoAdminRequired
696
+     * @NoSubadminRequired
697
+     * @PasswordConfirmationRequired
698
+     *
699
+     * @param string $avatarScope
700
+     * @param string $displayname
701
+     * @param string $displaynameScope
702
+     * @param string $phone
703
+     * @param string $phoneScope
704
+     * @param string $email
705
+     * @param string $emailScope
706
+     * @param string $website
707
+     * @param string $websiteScope
708
+     * @param string $address
709
+     * @param string $addressScope
710
+     * @param string $twitter
711
+     * @param string $twitterScope
712
+     * @return DataResponse
713
+     */
714
+    public function setUserSettings($avatarScope,
715
+                                    $displayname,
716
+                                    $displaynameScope,
717
+                                    $phone,
718
+                                    $phoneScope,
719
+                                    $email,
720
+                                    $emailScope,
721
+                                    $website,
722
+                                    $websiteScope,
723
+                                    $address,
724
+                                    $addressScope,
725
+                                    $twitter,
726
+                                    $twitterScope
727
+    ) {
728
+
729
+        if (!empty($email) && !$this->mailer->validateMailAddress($email)) {
730
+            return new DataResponse(
731
+                [
732
+                    'status' => 'error',
733
+                    'data' => [
734
+                        'message' => (string)$this->l10n->t('Invalid mail address')
735
+                    ]
736
+                ],
737
+                Http::STATUS_UNPROCESSABLE_ENTITY
738
+            );
739
+        }
740
+
741
+        $user = $this->userSession->getUser();
742
+
743
+        $data = $this->accountManager->getUser($user);
744
+
745
+        $data[AccountManager::PROPERTY_AVATAR] = ['scope' => $avatarScope];
746
+        if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
747
+            $data[AccountManager::PROPERTY_DISPLAYNAME] = ['value' => $displayname, 'scope' => $displaynameScope];
748
+            $data[AccountManager::PROPERTY_EMAIL] = ['value' => $email, 'scope' => $emailScope];
749
+        }
750
+
751
+        if ($this->appManager->isEnabledForUser('federatedfilesharing')) {
752
+            $federatedFileSharing = new \OCA\FederatedFileSharing\AppInfo\Application();
753
+            $shareProvider = $federatedFileSharing->getFederatedShareProvider();
754
+            if ($shareProvider->isLookupServerUploadEnabled()) {
755
+                $data[AccountManager::PROPERTY_WEBSITE] = ['value' => $website, 'scope' => $websiteScope];
756
+                $data[AccountManager::PROPERTY_ADDRESS] = ['value' => $address, 'scope' => $addressScope];
757
+                $data[AccountManager::PROPERTY_PHONE] = ['value' => $phone, 'scope' => $phoneScope];
758
+                $data[AccountManager::PROPERTY_TWITTER] = ['value' => $twitter, 'scope' => $twitterScope];
759
+            }
760
+        }
761
+
762
+        try {
763
+            $this->saveUserSettings($user, $data);
764
+            return new DataResponse(
765
+                [
766
+                    'status' => 'success',
767
+                    'data' => [
768
+                        'userId' => $user->getUID(),
769
+                        'avatarScope' => $data[AccountManager::PROPERTY_AVATAR]['scope'],
770
+                        'displayname' => $data[AccountManager::PROPERTY_DISPLAYNAME]['value'],
771
+                        'displaynameScope' => $data[AccountManager::PROPERTY_DISPLAYNAME]['scope'],
772
+                        'email' => $data[AccountManager::PROPERTY_EMAIL]['value'],
773
+                        'emailScope' => $data[AccountManager::PROPERTY_EMAIL]['scope'],
774
+                        'website' => $data[AccountManager::PROPERTY_WEBSITE]['value'],
775
+                        'websiteScope' => $data[AccountManager::PROPERTY_WEBSITE]['scope'],
776
+                        'address' => $data[AccountManager::PROPERTY_ADDRESS]['value'],
777
+                        'addressScope' => $data[AccountManager::PROPERTY_ADDRESS]['scope'],
778
+                        'message' => (string)$this->l10n->t('Settings saved')
779
+                    ]
780
+                ],
781
+                Http::STATUS_OK
782
+            );
783
+        } catch (ForbiddenException $e) {
784
+            return new DataResponse([
785
+                'status' => 'error',
786
+                'data' => [
787
+                    'message' => $e->getMessage()
788
+                ],
789
+            ]);
790
+        }
791
+
792
+    }
793
+
794
+
795
+    /**
796
+     * update account manager with new user data
797
+     *
798
+     * @param IUser $user
799
+     * @param array $data
800
+     * @throws ForbiddenException
801
+     */
802
+    protected function saveUserSettings(IUser $user, $data) {
803
+
804
+        // keep the user back-end up-to-date with the latest display name and email
805
+        // address
806
+        $oldDisplayName = $user->getDisplayName();
807
+        $oldDisplayName = is_null($oldDisplayName) ? '' : $oldDisplayName;
808
+        if (isset($data[AccountManager::PROPERTY_DISPLAYNAME]['value'])
809
+            && $oldDisplayName !== $data[AccountManager::PROPERTY_DISPLAYNAME]['value']
810
+        ) {
811
+            $result = $user->setDisplayName($data[AccountManager::PROPERTY_DISPLAYNAME]['value']);
812
+            if ($result === false) {
813
+                throw new ForbiddenException($this->l10n->t('Unable to change full name'));
814
+            }
815
+        }
816
+
817
+        $oldEmailAddress = $user->getEMailAddress();
818
+        $oldEmailAddress = is_null($oldEmailAddress) ? '' : $oldEmailAddress;
819
+        if (isset($data[AccountManager::PROPERTY_EMAIL]['value'])
820
+            && $oldEmailAddress !== $data[AccountManager::PROPERTY_EMAIL]['value']
821
+        ) {
822
+            // this is the only permission a backend provides and is also used
823
+            // for the permission of setting a email address
824
+            if (!$user->canChangeDisplayName()) {
825
+                throw new ForbiddenException($this->l10n->t('Unable to change email address'));
826
+            }
827
+            $user->setEMailAddress($data[AccountManager::PROPERTY_EMAIL]['value']);
828
+        }
829
+
830
+        $this->accountManager->updateUser($user, $data);
831
+    }
832
+
833
+    /**
834
+     * Count all unique users visible for the current admin/subadmin.
835
+     *
836
+     * @NoAdminRequired
837
+     *
838
+     * @return DataResponse
839
+     */
840
+    public function stats() {
841
+        $userCount = 0;
842
+        if ($this->isAdmin) {
843
+            $countByBackend = $this->userManager->countUsers();
844
+
845
+            if (!empty($countByBackend)) {
846
+                foreach ($countByBackend as $count) {
847
+                    $userCount += $count;
848
+                }
849
+            }
850
+        } else {
851
+            $groups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
852
+
853
+            $uniqueUsers = [];
854
+            foreach ($groups as $group) {
855
+                foreach ($group->getUsers() as $uid => $displayName) {
856
+                    $uniqueUsers[$uid] = true;
857
+                }
858
+            }
859
+
860
+            $userCount = count($uniqueUsers);
861
+        }
862
+
863
+        return new DataResponse(
864
+            [
865
+                'totalUsers' => $userCount
866
+            ]
867
+        );
868
+    }
869
+
870
+
871
+    /**
872
+     * Set the displayName of a user
873
+     *
874
+     * @NoAdminRequired
875
+     * @NoSubadminRequired
876
+     * @PasswordConfirmationRequired
877
+     * @todo merge into saveUserSettings
878
+     *
879
+     * @param string $username
880
+     * @param string $displayName
881
+     * @return DataResponse
882
+     */
883
+    public function setDisplayName($username, $displayName) {
884
+        $currentUser = $this->userSession->getUser();
885
+        $user = $this->userManager->get($username);
886
+
887
+        if ($user === null ||
888
+            !$user->canChangeDisplayName() ||
889
+            (
890
+                !$this->groupManager->isAdmin($currentUser->getUID()) &&
891
+                !$this->groupManager->getSubAdmin()->isUserAccessible($currentUser, $user) &&
892
+                $currentUser->getUID() !== $username
893
+
894
+            )
895
+        ) {
896
+            return new DataResponse([
897
+                'status' => 'error',
898
+                'data' => [
899
+                    'message' => $this->l10n->t('Authentication error'),
900
+                ],
901
+            ]);
902
+        }
903
+
904
+        $userData = $this->accountManager->getUser($user);
905
+        $userData[AccountManager::PROPERTY_DISPLAYNAME]['value'] = $displayName;
906
+
907
+
908
+        try {
909
+            $this->saveUserSettings($user, $userData);
910
+            return new DataResponse([
911
+                'status' => 'success',
912
+                'data' => [
913
+                    'message' => $this->l10n->t('Your full name has been changed.'),
914
+                    'username' => $username,
915
+                    'displayName' => $displayName,
916
+                ],
917
+            ]);
918
+        } catch (ForbiddenException $e) {
919
+            return new DataResponse([
920
+                'status' => 'error',
921
+                'data' => [
922
+                    'message' => $e->getMessage(),
923
+                    'displayName' => $user->getDisplayName(),
924
+                ],
925
+            ]);
926
+        }
927
+    }
928
+
929
+    /**
930
+     * Set the mail address of a user
931
+     *
932
+     * @NoAdminRequired
933
+     * @NoSubadminRequired
934
+     * @PasswordConfirmationRequired
935
+     *
936
+     * @param string $id
937
+     * @param string $mailAddress
938
+     * @return DataResponse
939
+     */
940
+    public function setEMailAddress($id, $mailAddress) {
941
+        $user = $this->userManager->get($id);
942
+        if (!$this->isAdmin
943
+            && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)
944
+        ) {
945
+            return new DataResponse(
946
+                [
947
+                    'status' => 'error',
948
+                    'data' => [
949
+                        'message' => (string)$this->l10n->t('Forbidden')
950
+                    ]
951
+                ],
952
+                Http::STATUS_FORBIDDEN
953
+            );
954
+        }
955
+
956
+        if ($mailAddress !== '' && !$this->mailer->validateMailAddress($mailAddress)) {
957
+            return new DataResponse(
958
+                [
959
+                    'status' => 'error',
960
+                    'data' => [
961
+                        'message' => (string)$this->l10n->t('Invalid mail address')
962
+                    ]
963
+                ],
964
+                Http::STATUS_UNPROCESSABLE_ENTITY
965
+            );
966
+        }
967
+
968
+        if (!$user) {
969
+            return new DataResponse(
970
+                [
971
+                    'status' => 'error',
972
+                    'data' => [
973
+                        'message' => (string)$this->l10n->t('Invalid user')
974
+                    ]
975
+                ],
976
+                Http::STATUS_UNPROCESSABLE_ENTITY
977
+            );
978
+        }
979
+        // this is the only permission a backend provides and is also used
980
+        // for the permission of setting a email address
981
+        if (!$user->canChangeDisplayName()) {
982
+            return new DataResponse(
983
+                [
984
+                    'status' => 'error',
985
+                    'data' => [
986
+                        'message' => (string)$this->l10n->t('Unable to change mail address')
987
+                    ]
988
+                ],
989
+                Http::STATUS_FORBIDDEN
990
+            );
991
+        }
992
+
993
+        $userData = $this->accountManager->getUser($user);
994
+        $userData[AccountManager::PROPERTY_EMAIL]['value'] = $mailAddress;
995
+
996
+        try {
997
+            $this->saveUserSettings($user, $userData);
998
+            return new DataResponse(
999
+                [
1000
+                    'status' => 'success',
1001
+                    'data' => [
1002
+                        'username' => $id,
1003
+                        'mailAddress' => $mailAddress,
1004
+                        'message' => (string)$this->l10n->t('Email saved')
1005
+                    ]
1006
+                ],
1007
+                Http::STATUS_OK
1008
+            );
1009
+        } catch (ForbiddenException $e) {
1010
+            return new DataResponse([
1011
+                'status' => 'error',
1012
+                'data' => [
1013
+                    'message' => $e->getMessage()
1014
+                ],
1015
+            ]);
1016
+        }
1017
+    }
1018 1018
 
1019 1019
 }
Please login to merge, or discard this patch.
Spacing   +23 added lines, -23 removed lines patch added patch discarded remove patch
@@ -362,7 +362,7 @@  discard block
 block discarded – undo
362 362
 		if ($email !== '' && !$this->mailer->validateMailAddress($email)) {
363 363
 			return new DataResponse(
364 364
 				[
365
-					'message' => (string)$this->l10n->t('Invalid mail address')
365
+					'message' => (string) $this->l10n->t('Invalid mail address')
366 366
 				],
367 367
 				Http::STATUS_UNPROCESSABLE_ENTITY
368 368
 			);
@@ -398,7 +398,7 @@  discard block
 block discarded – undo
398 398
 		if ($this->userManager->userExists($username)) {
399 399
 			return new DataResponse(
400 400
 				[
401
-					'message' => (string)$this->l10n->t('A user with that name already exists.')
401
+					'message' => (string) $this->l10n->t('A user with that name already exists.')
402 402
 				],
403 403
 				Http::STATUS_CONFLICT
404 404
 			);
@@ -409,7 +409,7 @@  discard block
 block discarded – undo
409 409
 			if ($email === '') {
410 410
 				return new DataResponse(
411 411
 					[
412
-						'message' => (string)$this->l10n->t('To send a password link to the user an email address is required.')
412
+						'message' => (string) $this->l10n->t('To send a password link to the user an email address is required.')
413 413
 					],
414 414
 					Http::STATUS_UNPROCESSABLE_ENTITY
415 415
 				);
@@ -428,7 +428,7 @@  discard block
 block discarded – undo
428 428
 			}
429 429
 			return new DataResponse(
430 430
 				[
431
-					'message' => (string)$message,
431
+					'message' => (string) $message,
432 432
 				],
433 433
 				Http::STATUS_FORBIDDEN
434 434
 			);
@@ -454,7 +454,7 @@  discard block
 block discarded – undo
454 454
 					$emailTemplate = $this->newUserMailHelper->generateTemplate($user, $generatePasswordResetToken);
455 455
 					$this->newUserMailHelper->sendMail($user, $emailTemplate);
456 456
 				} catch (\Exception $e) {
457
-					$this->log->error("Can't send new user mail to $email: " . $e->getMessage(), ['app' => 'settings']);
457
+					$this->log->error("Can't send new user mail to $email: ".$e->getMessage(), ['app' => 'settings']);
458 458
 				}
459 459
 			}
460 460
 			// fetch users groups
@@ -468,7 +468,7 @@  discard block
 block discarded – undo
468 468
 
469 469
 		return new DataResponse(
470 470
 			[
471
-				'message' => (string)$this->l10n->t('Unable to create user.')
471
+				'message' => (string) $this->l10n->t('Unable to create user.')
472 472
 			],
473 473
 			Http::STATUS_FORBIDDEN
474 474
 		);
@@ -491,7 +491,7 @@  discard block
 block discarded – undo
491 491
 				[
492 492
 					'status' => 'error',
493 493
 					'data' => [
494
-						'message' => (string)$this->l10n->t('Unable to delete user.')
494
+						'message' => (string) $this->l10n->t('Unable to delete user.')
495 495
 					]
496 496
 				],
497 497
 				Http::STATUS_FORBIDDEN
@@ -503,7 +503,7 @@  discard block
 block discarded – undo
503 503
 				[
504 504
 					'status' => 'error',
505 505
 					'data' => [
506
-						'message' => (string)$this->l10n->t('Authentication error')
506
+						'message' => (string) $this->l10n->t('Authentication error')
507 507
 					]
508 508
 				],
509 509
 				Http::STATUS_FORBIDDEN
@@ -528,7 +528,7 @@  discard block
 block discarded – undo
528 528
 			[
529 529
 				'status' => 'error',
530 530
 				'data' => [
531
-					'message' => (string)$this->l10n->t('Unable to delete user.')
531
+					'message' => (string) $this->l10n->t('Unable to delete user.')
532 532
 				]
533 533
 			],
534 534
 			Http::STATUS_FORBIDDEN
@@ -543,11 +543,11 @@  discard block
 block discarded – undo
543 543
 	 * @return DataResponse
544 544
 	 */
545 545
 	public function setEnabled($id, $enabled) {
546
-		$enabled = (bool)$enabled;
546
+		$enabled = (bool) $enabled;
547 547
 		if ($enabled) {
548
-			$errorMsgGeneral = (string)$this->l10n->t('Error while enabling user.');
548
+			$errorMsgGeneral = (string) $this->l10n->t('Error while enabling user.');
549 549
 		} else {
550
-			$errorMsgGeneral = (string)$this->l10n->t('Error while disabling user.');
550
+			$errorMsgGeneral = (string) $this->l10n->t('Error while disabling user.');
551 551
 		}
552 552
 
553 553
 		$userId = $this->userSession->getUser()->getUID();
@@ -570,7 +570,7 @@  discard block
 block discarded – undo
570 570
 					[
571 571
 						'status' => 'error',
572 572
 						'data' => [
573
-							'message' => (string)$this->l10n->t('Authentication error')
573
+							'message' => (string) $this->l10n->t('Authentication error')
574 574
 						]
575 575
 					],
576 576
 					Http::STATUS_FORBIDDEN
@@ -622,11 +622,11 @@  discard block
 block discarded – undo
622 622
 
623 623
 		$accountData = $this->accountManager->getUser($user);
624 624
 		$cloudId = $user->getCloudId();
625
-		$message = "Use my Federated Cloud ID to share with me: " . $cloudId;
625
+		$message = "Use my Federated Cloud ID to share with me: ".$cloudId;
626 626
 		$signature = $this->signMessage($user, $message);
627 627
 
628
-		$code = $message . ' ' . $signature;
629
-		$codeMd5 = $message . ' ' . md5($signature);
628
+		$code = $message.' '.$signature;
629
+		$codeMd5 = $message.' '.md5($signature);
630 630
 
631 631
 		switch ($account) {
632 632
 			case 'verify-twitter':
@@ -731,7 +731,7 @@  discard block
 block discarded – undo
731 731
 				[
732 732
 					'status' => 'error',
733 733
 					'data' => [
734
-						'message' => (string)$this->l10n->t('Invalid mail address')
734
+						'message' => (string) $this->l10n->t('Invalid mail address')
735 735
 					]
736 736
 				],
737 737
 				Http::STATUS_UNPROCESSABLE_ENTITY
@@ -775,7 +775,7 @@  discard block
 block discarded – undo
775 775
 						'websiteScope' => $data[AccountManager::PROPERTY_WEBSITE]['scope'],
776 776
 						'address' => $data[AccountManager::PROPERTY_ADDRESS]['value'],
777 777
 						'addressScope' => $data[AccountManager::PROPERTY_ADDRESS]['scope'],
778
-						'message' => (string)$this->l10n->t('Settings saved')
778
+						'message' => (string) $this->l10n->t('Settings saved')
779 779
 					]
780 780
 				],
781 781
 				Http::STATUS_OK
@@ -946,7 +946,7 @@  discard block
 block discarded – undo
946 946
 				[
947 947
 					'status' => 'error',
948 948
 					'data' => [
949
-						'message' => (string)$this->l10n->t('Forbidden')
949
+						'message' => (string) $this->l10n->t('Forbidden')
950 950
 					]
951 951
 				],
952 952
 				Http::STATUS_FORBIDDEN
@@ -958,7 +958,7 @@  discard block
 block discarded – undo
958 958
 				[
959 959
 					'status' => 'error',
960 960
 					'data' => [
961
-						'message' => (string)$this->l10n->t('Invalid mail address')
961
+						'message' => (string) $this->l10n->t('Invalid mail address')
962 962
 					]
963 963
 				],
964 964
 				Http::STATUS_UNPROCESSABLE_ENTITY
@@ -970,7 +970,7 @@  discard block
 block discarded – undo
970 970
 				[
971 971
 					'status' => 'error',
972 972
 					'data' => [
973
-						'message' => (string)$this->l10n->t('Invalid user')
973
+						'message' => (string) $this->l10n->t('Invalid user')
974 974
 					]
975 975
 				],
976 976
 				Http::STATUS_UNPROCESSABLE_ENTITY
@@ -983,7 +983,7 @@  discard block
 block discarded – undo
983 983
 				[
984 984
 					'status' => 'error',
985 985
 					'data' => [
986
-						'message' => (string)$this->l10n->t('Unable to change mail address')
986
+						'message' => (string) $this->l10n->t('Unable to change mail address')
987 987
 					]
988 988
 				],
989 989
 				Http::STATUS_FORBIDDEN
@@ -1001,7 +1001,7 @@  discard block
 block discarded – undo
1001 1001
 					'data' => [
1002 1002
 						'username' => $id,
1003 1003
 						'mailAddress' => $mailAddress,
1004
-						'message' => (string)$this->l10n->t('Email saved')
1004
+						'message' => (string) $this->l10n->t('Email saved')
1005 1005
 					]
1006 1006
 				],
1007 1007
 				Http::STATUS_OK
Please login to merge, or discard this patch.
lib/public/Files/Config/IUserMountCache.php 1 patch
Indentation   +77 added lines, -77 removed lines patch added patch discarded remove patch
@@ -31,89 +31,89 @@
 block discarded – undo
31 31
  * @since 9.0.0
32 32
  */
33 33
 interface IUserMountCache {
34
-	/**
35
-	 * Register mounts for a user to the cache
36
-	 *
37
-	 * @param IUser $user
38
-	 * @param IMountPoint[] $mounts
39
-	 * @since 9.0.0
40
-	 */
41
-	public function registerMounts(IUser $user, array $mounts);
34
+    /**
35
+     * Register mounts for a user to the cache
36
+     *
37
+     * @param IUser $user
38
+     * @param IMountPoint[] $mounts
39
+     * @since 9.0.0
40
+     */
41
+    public function registerMounts(IUser $user, array $mounts);
42 42
 
43
-	/**
44
-	 * Get all cached mounts for a user
45
-	 *
46
-	 * @param IUser $user
47
-	 * @return ICachedMountInfo[]
48
-	 * @since 9.0.0
49
-	 */
50
-	public function getMountsForUser(IUser $user);
43
+    /**
44
+     * Get all cached mounts for a user
45
+     *
46
+     * @param IUser $user
47
+     * @return ICachedMountInfo[]
48
+     * @since 9.0.0
49
+     */
50
+    public function getMountsForUser(IUser $user);
51 51
 
52
-	/**
53
-	 * Get all cached mounts by storage
54
-	 *
55
-	 * @param int $numericStorageId
56
-	 * @param string|null $user limit the results to a single user @since 12.0.0
57
-	 * @return ICachedMountInfo[]
58
-	 * @since 9.0.0
59
-	 */
60
-	public function getMountsForStorageId($numericStorageId, $user = null);
52
+    /**
53
+     * Get all cached mounts by storage
54
+     *
55
+     * @param int $numericStorageId
56
+     * @param string|null $user limit the results to a single user @since 12.0.0
57
+     * @return ICachedMountInfo[]
58
+     * @since 9.0.0
59
+     */
60
+    public function getMountsForStorageId($numericStorageId, $user = null);
61 61
 
62
-	/**
63
-	 * Get all cached mounts by root
64
-	 *
65
-	 * @param int $rootFileId
66
-	 * @return ICachedMountInfo[]
67
-	 * @since 9.0.0
68
-	 */
69
-	public function getMountsForRootId($rootFileId);
62
+    /**
63
+     * Get all cached mounts by root
64
+     *
65
+     * @param int $rootFileId
66
+     * @return ICachedMountInfo[]
67
+     * @since 9.0.0
68
+     */
69
+    public function getMountsForRootId($rootFileId);
70 70
 
71
-	/**
72
-	 * Get all cached mounts that contain a file
73
-	 *
74
-	 * @param int $fileId
75
-	 * @param string|null $user optionally restrict the results to a single user @since 12.0.0
76
-	 * @return ICachedMountInfo[]
77
-	 * @since 9.0.0
78
-	 */
79
-	public function getMountsForFileId($fileId, $user = null);
71
+    /**
72
+     * Get all cached mounts that contain a file
73
+     *
74
+     * @param int $fileId
75
+     * @param string|null $user optionally restrict the results to a single user @since 12.0.0
76
+     * @return ICachedMountInfo[]
77
+     * @since 9.0.0
78
+     */
79
+    public function getMountsForFileId($fileId, $user = null);
80 80
 
81
-	/**
82
-	 * Remove all cached mounts for a user
83
-	 *
84
-	 * @param IUser $user
85
-	 * @since 9.0.0
86
-	 */
87
-	public function removeUserMounts(IUser $user);
81
+    /**
82
+     * Remove all cached mounts for a user
83
+     *
84
+     * @param IUser $user
85
+     * @since 9.0.0
86
+     */
87
+    public function removeUserMounts(IUser $user);
88 88
 
89
-	/**
90
-	 * Remove all mounts for a user and storage
91
-	 *
92
-	 * @param $storageId
93
-	 * @param string $userId
94
-	 * @return mixed
95
-	 * @since 9.0.0
96
-	 */
97
-	public function removeUserStorageMount($storageId, $userId);
89
+    /**
90
+     * Remove all mounts for a user and storage
91
+     *
92
+     * @param $storageId
93
+     * @param string $userId
94
+     * @return mixed
95
+     * @since 9.0.0
96
+     */
97
+    public function removeUserStorageMount($storageId, $userId);
98 98
 
99
-	/**
100
-	 * Remove all cached mounts for a storage
101
-	 *
102
-	 * @param $storageId
103
-	 * @return mixed
104
-	 * @since 9.0.0
105
-	 */
106
-	public function remoteStorageMounts($storageId);
99
+    /**
100
+     * Remove all cached mounts for a storage
101
+     *
102
+     * @param $storageId
103
+     * @return mixed
104
+     * @since 9.0.0
105
+     */
106
+    public function remoteStorageMounts($storageId);
107 107
 
108
-	/**
109
-	 * Get the used space for users
110
-	 *
111
-	 * Note that this only includes the space in their home directory,
112
-	 * not any incoming shares or external storages.
113
-	 *
114
-	 * @param IUser[] $users
115
-	 * @return int[] [$userId => $userSpace]
116
-	 * @since 13.0.0
117
-	 */
118
-	public function getUsedSpaceForUsers(array $users);
108
+    /**
109
+     * Get the used space for users
110
+     *
111
+     * Note that this only includes the space in their home directory,
112
+     * not any incoming shares or external storages.
113
+     *
114
+     * @param IUser[] $users
115
+     * @return int[] [$userId => $userSpace]
116
+     * @since 13.0.0
117
+     */
118
+    public function getUsedSpaceForUsers(array $users);
119 119
 }
Please login to merge, or discard this patch.