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