Passed
Push — master ( 62403d...0c3e2f )
by Joas
14:50 queued 14s
created
apps/user_ldap/lib/Jobs/Sync.php 2 patches
Indentation   +338 added lines, -338 removed lines patch added patch discarded remove patch
@@ -42,343 +42,343 @@
 block discarded – undo
42 42
 use OCP\Notification\IManager;
43 43
 
44 44
 class Sync extends TimedJob {
45
-	const MAX_INTERVAL = 12 * 60 * 60; // 12h
46
-	const MIN_INTERVAL = 30 * 60; // 30min
47
-	/** @var  Helper */
48
-	protected $ldapHelper;
49
-	/** @var  LDAP */
50
-	protected $ldap;
51
-	/** @var  Manager */
52
-	protected $userManager;
53
-	/** @var UserMapping */
54
-	protected $mapper;
55
-	/** @var  IConfig */
56
-	protected $config;
57
-	/** @var  IAvatarManager */
58
-	protected $avatarManager;
59
-	/** @var  IDBConnection */
60
-	protected $dbc;
61
-	/** @var  IUserManager */
62
-	protected $ncUserManager;
63
-	/** @var  IManager */
64
-	protected $notificationManager;
65
-	/** @var ConnectionFactory */
66
-	protected $connectionFactory;
67
-	/** @var AccessFactory */
68
-	protected $accessFactory;
69
-
70
-	public function __construct() {
71
-		$this->setInterval(
72
-			\OC::$server->getConfig()->getAppValue(
73
-				'user_ldap',
74
-				'background_sync_interval',
75
-				self::MIN_INTERVAL
76
-			)
77
-		);
78
-	}
79
-
80
-	/**
81
-	 * updates the interval
82
-	 *
83
-	 * the idea is to adjust the interval depending on the amount of known users
84
-	 * and the attempt to update each user one day. At most it would run every
85
-	 * 30 minutes, and at least every 12 hours.
86
-	 */
87
-	public function updateInterval() {
88
-		$minPagingSize = $this->getMinPagingSize();
89
-		$mappedUsers = $this->mapper->count();
90
-
91
-		$runsPerDay = ($minPagingSize === 0 || $mappedUsers === 0) ? self::MAX_INTERVAL
92
-			: $mappedUsers / $minPagingSize;
93
-		$interval = floor(24 * 60 * 60 / $runsPerDay);
94
-		$interval = min(max($interval, self::MIN_INTERVAL), self::MAX_INTERVAL);
95
-
96
-		$this->config->setAppValue('user_ldap', 'background_sync_interval', $interval);
97
-	}
98
-
99
-	/**
100
-	 * returns the smallest configured paging size
101
-	 * @return int
102
-	 */
103
-	protected function getMinPagingSize() {
104
-		$configKeys = $this->config->getAppKeys('user_ldap');
105
-		$configKeys = array_filter($configKeys, function($key) {
106
-			return strpos($key, 'ldap_paging_size') !== false;
107
-		});
108
-		$minPagingSize = null;
109
-		foreach ($configKeys as $configKey) {
110
-			$pagingSize = $this->config->getAppValue('user_ldap', $configKey, $minPagingSize);
111
-			$minPagingSize = $minPagingSize === null ? $pagingSize : min($minPagingSize, $pagingSize);
112
-		}
113
-		return (int)$minPagingSize;
114
-	}
115
-
116
-	/**
117
-	 * @param array $argument
118
-	 */
119
-	public function run($argument) {
120
-		$this->setArgument($argument);
121
-
122
-		$isBackgroundJobModeAjax = $this->config
123
-				->getAppValue('core', 'backgroundjobs_mode', 'ajax') === 'ajax';
124
-		if($isBackgroundJobModeAjax) {
125
-			return;
126
-		}
127
-
128
-		$cycleData = $this->getCycle();
129
-		if($cycleData === null) {
130
-			$cycleData = $this->determineNextCycle();
131
-			if($cycleData === null) {
132
-				$this->updateInterval();
133
-				return;
134
-			}
135
-		}
136
-
137
-		if(!$this->qualifiesToRun($cycleData)) {
138
-			$this->updateInterval();
139
-			return;
140
-		}
141
-
142
-		try {
143
-			$expectMoreResults = $this->runCycle($cycleData);
144
-			if ($expectMoreResults) {
145
-				$this->increaseOffset($cycleData);
146
-			} else {
147
-				$this->determineNextCycle($cycleData);
148
-			}
149
-			$this->updateInterval();
150
-		} catch (ServerNotAvailableException $e) {
151
-			$this->determineNextCycle($cycleData);
152
-		}
153
-	}
154
-
155
-	/**
156
-	 * @param array $cycleData
157
-	 * @return bool whether more results are expected from the same configuration
158
-	 */
159
-	public function runCycle($cycleData) {
160
-		$connection = $this->connectionFactory->get($cycleData['prefix']);
161
-		$access = $this->accessFactory->get($connection);
162
-		$access->setUserMapper($this->mapper);
163
-
164
-		$filter = $access->combineFilterWithAnd([
165
-			$access->connection->ldapUserFilter,
166
-			$access->connection->ldapUserDisplayName . '=*',
167
-			$access->getFilterPartForUserSearch('')
168
-		]);
169
-		$results = $access->fetchListOfUsers(
170
-			$filter,
171
-			$access->userManager->getAttributes(),
172
-			$connection->ldapPagingSize,
173
-			$cycleData['offset'],
174
-			true
175
-		);
176
-
177
-		if((int)$connection->ldapPagingSize === 0) {
178
-			return false;
179
-		}
180
-		return count($results) >= (int)$connection->ldapPagingSize;
181
-	}
182
-
183
-	/**
184
-	 * returns the info about the current cycle that should be run, if any,
185
-	 * otherwise null
186
-	 *
187
-	 * @return array|null
188
-	 */
189
-	public function getCycle() {
190
-		$prefixes = $this->ldapHelper->getServerConfigurationPrefixes(true);
191
-		if(count($prefixes) === 0) {
192
-			return null;
193
-		}
194
-
195
-		$cycleData = [
196
-			'prefix' => $this->config->getAppValue('user_ldap', 'background_sync_prefix', null),
197
-			'offset' => (int)$this->config->getAppValue('user_ldap', 'background_sync_offset', 0),
198
-		];
199
-
200
-		if(
201
-			$cycleData['prefix'] !== null
202
-			&& in_array($cycleData['prefix'], $prefixes)
203
-		) {
204
-			return $cycleData;
205
-		}
206
-
207
-		return null;
208
-	}
209
-
210
-	/**
211
-	 * Save the provided cycle information in the DB
212
-	 *
213
-	 * @param array $cycleData
214
-	 */
215
-	public function setCycle(array $cycleData) {
216
-		$this->config->setAppValue('user_ldap', 'background_sync_prefix', $cycleData['prefix']);
217
-		$this->config->setAppValue('user_ldap', 'background_sync_offset', $cycleData['offset']);
218
-	}
219
-
220
-	/**
221
-	 * returns data about the next cycle that should run, if any, otherwise
222
-	 * null. It also always goes for the next LDAP configuration!
223
-	 *
224
-	 * @param array|null $cycleData the old cycle
225
-	 * @return array|null
226
-	 */
227
-	public function determineNextCycle(array $cycleData = null) {
228
-		$prefixes = $this->ldapHelper->getServerConfigurationPrefixes(true);
229
-		if(count($prefixes) === 0) {
230
-			return null;
231
-		}
232
-
233
-		// get the next prefix in line and remember it
234
-		$oldPrefix = $cycleData === null ? null : $cycleData['prefix'];
235
-		$prefix = $this->getNextPrefix($oldPrefix);
236
-		if($prefix === null) {
237
-			return null;
238
-		}
239
-		$cycleData['prefix'] = $prefix;
240
-		$cycleData['offset'] = 0;
241
-		$this->setCycle(['prefix' => $prefix, 'offset' => 0]);
242
-
243
-		return $cycleData;
244
-	}
245
-
246
-	/**
247
-	 * Checks whether the provided cycle should be run. Currently only the
248
-	 * last configuration change goes into account (at least one hour).
249
-	 *
250
-	 * @param $cycleData
251
-	 * @return bool
252
-	 */
253
-	public function qualifiesToRun($cycleData) {
254
-		$lastChange = $this->config->getAppValue('user_ldap', $cycleData['prefix'] . '_lastChange', 0);
255
-		if((time() - $lastChange) > 60 * 30) {
256
-			return true;
257
-		}
258
-		return false;
259
-	}
260
-
261
-	/**
262
-	 * increases the offset of the current cycle for the next run
263
-	 *
264
-	 * @param $cycleData
265
-	 */
266
-	protected function increaseOffset($cycleData) {
267
-		$ldapConfig = new Configuration($cycleData['prefix']);
268
-		$cycleData['offset'] += (int)$ldapConfig->ldapPagingSize;
269
-		$this->setCycle($cycleData);
270
-	}
271
-
272
-	/**
273
-	 * determines the next configuration prefix based on the last one (if any)
274
-	 *
275
-	 * @param string|null $lastPrefix
276
-	 * @return string|null
277
-	 */
278
-	protected function getNextPrefix($lastPrefix) {
279
-		$prefixes = $this->ldapHelper->getServerConfigurationPrefixes(true);
280
-		$noOfPrefixes = count($prefixes);
281
-		if($noOfPrefixes === 0) {
282
-			return null;
283
-		}
284
-		$i = $lastPrefix === null ? false : array_search($lastPrefix, $prefixes, true);
285
-		if($i === false) {
286
-			$i = -1;
287
-		} else {
288
-			$i++;
289
-		}
290
-
291
-		if(!isset($prefixes[$i])) {
292
-			$i = 0;
293
-		}
294
-		return $prefixes[$i];
295
-	}
296
-
297
-	/**
298
-	 * "fixes" DI
299
-	 *
300
-	 * @param array $argument
301
-	 */
302
-	public function setArgument($argument) {
303
-		if(isset($argument['config'])) {
304
-			$this->config = $argument['config'];
305
-		} else {
306
-			$this->config = \OC::$server->getConfig();
307
-		}
308
-
309
-		if(isset($argument['helper'])) {
310
-			$this->ldapHelper = $argument['helper'];
311
-		} else {
312
-			$this->ldapHelper = new Helper($this->config);
313
-		}
314
-
315
-		if(isset($argument['ldapWrapper'])) {
316
-			$this->ldap = $argument['ldapWrapper'];
317
-		} else {
318
-			$this->ldap = new LDAP();
319
-		}
320
-
321
-		if(isset($argument['avatarManager'])) {
322
-			$this->avatarManager = $argument['avatarManager'];
323
-		} else {
324
-			$this->avatarManager = \OC::$server->getAvatarManager();
325
-		}
326
-
327
-		if(isset($argument['dbc'])) {
328
-			$this->dbc = $argument['dbc'];
329
-		} else {
330
-			$this->dbc = \OC::$server->getDatabaseConnection();
331
-		}
332
-
333
-		if(isset($argument['ncUserManager'])) {
334
-			$this->ncUserManager = $argument['ncUserManager'];
335
-		} else {
336
-			$this->ncUserManager = \OC::$server->getUserManager();
337
-		}
338
-
339
-		if(isset($argument['notificationManager'])) {
340
-			$this->notificationManager = $argument['notificationManager'];
341
-		} else {
342
-			$this->notificationManager = \OC::$server->getNotificationManager();
343
-		}
344
-
345
-		if(isset($argument['userManager'])) {
346
-			$this->userManager = $argument['userManager'];
347
-		} else {
348
-			$this->userManager = new Manager(
349
-				$this->config,
350
-				new FilesystemHelper(),
351
-				new LogWrapper(),
352
-				$this->avatarManager,
353
-				new Image(),
354
-				$this->dbc,
355
-				$this->ncUserManager,
356
-				$this->notificationManager
357
-			);
358
-		}
359
-
360
-		if(isset($argument['mapper'])) {
361
-			$this->mapper = $argument['mapper'];
362
-		} else {
363
-			$this->mapper = new UserMapping($this->dbc);
364
-		}
45
+    const MAX_INTERVAL = 12 * 60 * 60; // 12h
46
+    const MIN_INTERVAL = 30 * 60; // 30min
47
+    /** @var  Helper */
48
+    protected $ldapHelper;
49
+    /** @var  LDAP */
50
+    protected $ldap;
51
+    /** @var  Manager */
52
+    protected $userManager;
53
+    /** @var UserMapping */
54
+    protected $mapper;
55
+    /** @var  IConfig */
56
+    protected $config;
57
+    /** @var  IAvatarManager */
58
+    protected $avatarManager;
59
+    /** @var  IDBConnection */
60
+    protected $dbc;
61
+    /** @var  IUserManager */
62
+    protected $ncUserManager;
63
+    /** @var  IManager */
64
+    protected $notificationManager;
65
+    /** @var ConnectionFactory */
66
+    protected $connectionFactory;
67
+    /** @var AccessFactory */
68
+    protected $accessFactory;
69
+
70
+    public function __construct() {
71
+        $this->setInterval(
72
+            \OC::$server->getConfig()->getAppValue(
73
+                'user_ldap',
74
+                'background_sync_interval',
75
+                self::MIN_INTERVAL
76
+            )
77
+        );
78
+    }
79
+
80
+    /**
81
+     * updates the interval
82
+     *
83
+     * the idea is to adjust the interval depending on the amount of known users
84
+     * and the attempt to update each user one day. At most it would run every
85
+     * 30 minutes, and at least every 12 hours.
86
+     */
87
+    public function updateInterval() {
88
+        $minPagingSize = $this->getMinPagingSize();
89
+        $mappedUsers = $this->mapper->count();
90
+
91
+        $runsPerDay = ($minPagingSize === 0 || $mappedUsers === 0) ? self::MAX_INTERVAL
92
+            : $mappedUsers / $minPagingSize;
93
+        $interval = floor(24 * 60 * 60 / $runsPerDay);
94
+        $interval = min(max($interval, self::MIN_INTERVAL), self::MAX_INTERVAL);
95
+
96
+        $this->config->setAppValue('user_ldap', 'background_sync_interval', $interval);
97
+    }
98
+
99
+    /**
100
+     * returns the smallest configured paging size
101
+     * @return int
102
+     */
103
+    protected function getMinPagingSize() {
104
+        $configKeys = $this->config->getAppKeys('user_ldap');
105
+        $configKeys = array_filter($configKeys, function($key) {
106
+            return strpos($key, 'ldap_paging_size') !== false;
107
+        });
108
+        $minPagingSize = null;
109
+        foreach ($configKeys as $configKey) {
110
+            $pagingSize = $this->config->getAppValue('user_ldap', $configKey, $minPagingSize);
111
+            $minPagingSize = $minPagingSize === null ? $pagingSize : min($minPagingSize, $pagingSize);
112
+        }
113
+        return (int)$minPagingSize;
114
+    }
115
+
116
+    /**
117
+     * @param array $argument
118
+     */
119
+    public function run($argument) {
120
+        $this->setArgument($argument);
121
+
122
+        $isBackgroundJobModeAjax = $this->config
123
+                ->getAppValue('core', 'backgroundjobs_mode', 'ajax') === 'ajax';
124
+        if($isBackgroundJobModeAjax) {
125
+            return;
126
+        }
127
+
128
+        $cycleData = $this->getCycle();
129
+        if($cycleData === null) {
130
+            $cycleData = $this->determineNextCycle();
131
+            if($cycleData === null) {
132
+                $this->updateInterval();
133
+                return;
134
+            }
135
+        }
136
+
137
+        if(!$this->qualifiesToRun($cycleData)) {
138
+            $this->updateInterval();
139
+            return;
140
+        }
141
+
142
+        try {
143
+            $expectMoreResults = $this->runCycle($cycleData);
144
+            if ($expectMoreResults) {
145
+                $this->increaseOffset($cycleData);
146
+            } else {
147
+                $this->determineNextCycle($cycleData);
148
+            }
149
+            $this->updateInterval();
150
+        } catch (ServerNotAvailableException $e) {
151
+            $this->determineNextCycle($cycleData);
152
+        }
153
+    }
154
+
155
+    /**
156
+     * @param array $cycleData
157
+     * @return bool whether more results are expected from the same configuration
158
+     */
159
+    public function runCycle($cycleData) {
160
+        $connection = $this->connectionFactory->get($cycleData['prefix']);
161
+        $access = $this->accessFactory->get($connection);
162
+        $access->setUserMapper($this->mapper);
163
+
164
+        $filter = $access->combineFilterWithAnd([
165
+            $access->connection->ldapUserFilter,
166
+            $access->connection->ldapUserDisplayName . '=*',
167
+            $access->getFilterPartForUserSearch('')
168
+        ]);
169
+        $results = $access->fetchListOfUsers(
170
+            $filter,
171
+            $access->userManager->getAttributes(),
172
+            $connection->ldapPagingSize,
173
+            $cycleData['offset'],
174
+            true
175
+        );
176
+
177
+        if((int)$connection->ldapPagingSize === 0) {
178
+            return false;
179
+        }
180
+        return count($results) >= (int)$connection->ldapPagingSize;
181
+    }
182
+
183
+    /**
184
+     * returns the info about the current cycle that should be run, if any,
185
+     * otherwise null
186
+     *
187
+     * @return array|null
188
+     */
189
+    public function getCycle() {
190
+        $prefixes = $this->ldapHelper->getServerConfigurationPrefixes(true);
191
+        if(count($prefixes) === 0) {
192
+            return null;
193
+        }
194
+
195
+        $cycleData = [
196
+            'prefix' => $this->config->getAppValue('user_ldap', 'background_sync_prefix', null),
197
+            'offset' => (int)$this->config->getAppValue('user_ldap', 'background_sync_offset', 0),
198
+        ];
199
+
200
+        if(
201
+            $cycleData['prefix'] !== null
202
+            && in_array($cycleData['prefix'], $prefixes)
203
+        ) {
204
+            return $cycleData;
205
+        }
206
+
207
+        return null;
208
+    }
209
+
210
+    /**
211
+     * Save the provided cycle information in the DB
212
+     *
213
+     * @param array $cycleData
214
+     */
215
+    public function setCycle(array $cycleData) {
216
+        $this->config->setAppValue('user_ldap', 'background_sync_prefix', $cycleData['prefix']);
217
+        $this->config->setAppValue('user_ldap', 'background_sync_offset', $cycleData['offset']);
218
+    }
219
+
220
+    /**
221
+     * returns data about the next cycle that should run, if any, otherwise
222
+     * null. It also always goes for the next LDAP configuration!
223
+     *
224
+     * @param array|null $cycleData the old cycle
225
+     * @return array|null
226
+     */
227
+    public function determineNextCycle(array $cycleData = null) {
228
+        $prefixes = $this->ldapHelper->getServerConfigurationPrefixes(true);
229
+        if(count($prefixes) === 0) {
230
+            return null;
231
+        }
232
+
233
+        // get the next prefix in line and remember it
234
+        $oldPrefix = $cycleData === null ? null : $cycleData['prefix'];
235
+        $prefix = $this->getNextPrefix($oldPrefix);
236
+        if($prefix === null) {
237
+            return null;
238
+        }
239
+        $cycleData['prefix'] = $prefix;
240
+        $cycleData['offset'] = 0;
241
+        $this->setCycle(['prefix' => $prefix, 'offset' => 0]);
242
+
243
+        return $cycleData;
244
+    }
245
+
246
+    /**
247
+     * Checks whether the provided cycle should be run. Currently only the
248
+     * last configuration change goes into account (at least one hour).
249
+     *
250
+     * @param $cycleData
251
+     * @return bool
252
+     */
253
+    public function qualifiesToRun($cycleData) {
254
+        $lastChange = $this->config->getAppValue('user_ldap', $cycleData['prefix'] . '_lastChange', 0);
255
+        if((time() - $lastChange) > 60 * 30) {
256
+            return true;
257
+        }
258
+        return false;
259
+    }
260
+
261
+    /**
262
+     * increases the offset of the current cycle for the next run
263
+     *
264
+     * @param $cycleData
265
+     */
266
+    protected function increaseOffset($cycleData) {
267
+        $ldapConfig = new Configuration($cycleData['prefix']);
268
+        $cycleData['offset'] += (int)$ldapConfig->ldapPagingSize;
269
+        $this->setCycle($cycleData);
270
+    }
271
+
272
+    /**
273
+     * determines the next configuration prefix based on the last one (if any)
274
+     *
275
+     * @param string|null $lastPrefix
276
+     * @return string|null
277
+     */
278
+    protected function getNextPrefix($lastPrefix) {
279
+        $prefixes = $this->ldapHelper->getServerConfigurationPrefixes(true);
280
+        $noOfPrefixes = count($prefixes);
281
+        if($noOfPrefixes === 0) {
282
+            return null;
283
+        }
284
+        $i = $lastPrefix === null ? false : array_search($lastPrefix, $prefixes, true);
285
+        if($i === false) {
286
+            $i = -1;
287
+        } else {
288
+            $i++;
289
+        }
290
+
291
+        if(!isset($prefixes[$i])) {
292
+            $i = 0;
293
+        }
294
+        return $prefixes[$i];
295
+    }
296
+
297
+    /**
298
+     * "fixes" DI
299
+     *
300
+     * @param array $argument
301
+     */
302
+    public function setArgument($argument) {
303
+        if(isset($argument['config'])) {
304
+            $this->config = $argument['config'];
305
+        } else {
306
+            $this->config = \OC::$server->getConfig();
307
+        }
308
+
309
+        if(isset($argument['helper'])) {
310
+            $this->ldapHelper = $argument['helper'];
311
+        } else {
312
+            $this->ldapHelper = new Helper($this->config);
313
+        }
314
+
315
+        if(isset($argument['ldapWrapper'])) {
316
+            $this->ldap = $argument['ldapWrapper'];
317
+        } else {
318
+            $this->ldap = new LDAP();
319
+        }
320
+
321
+        if(isset($argument['avatarManager'])) {
322
+            $this->avatarManager = $argument['avatarManager'];
323
+        } else {
324
+            $this->avatarManager = \OC::$server->getAvatarManager();
325
+        }
326
+
327
+        if(isset($argument['dbc'])) {
328
+            $this->dbc = $argument['dbc'];
329
+        } else {
330
+            $this->dbc = \OC::$server->getDatabaseConnection();
331
+        }
332
+
333
+        if(isset($argument['ncUserManager'])) {
334
+            $this->ncUserManager = $argument['ncUserManager'];
335
+        } else {
336
+            $this->ncUserManager = \OC::$server->getUserManager();
337
+        }
338
+
339
+        if(isset($argument['notificationManager'])) {
340
+            $this->notificationManager = $argument['notificationManager'];
341
+        } else {
342
+            $this->notificationManager = \OC::$server->getNotificationManager();
343
+        }
344
+
345
+        if(isset($argument['userManager'])) {
346
+            $this->userManager = $argument['userManager'];
347
+        } else {
348
+            $this->userManager = new Manager(
349
+                $this->config,
350
+                new FilesystemHelper(),
351
+                new LogWrapper(),
352
+                $this->avatarManager,
353
+                new Image(),
354
+                $this->dbc,
355
+                $this->ncUserManager,
356
+                $this->notificationManager
357
+            );
358
+        }
359
+
360
+        if(isset($argument['mapper'])) {
361
+            $this->mapper = $argument['mapper'];
362
+        } else {
363
+            $this->mapper = new UserMapping($this->dbc);
364
+        }
365 365
 		
366
-		if(isset($argument['connectionFactory'])) {
367
-			$this->connectionFactory = $argument['connectionFactory'];
368
-		} else {
369
-			$this->connectionFactory = new ConnectionFactory($this->ldap);
370
-		}
371
-
372
-		if(isset($argument['accessFactory'])) {
373
-			$this->accessFactory = $argument['accessFactory'];
374
-		} else {
375
-			$this->accessFactory = new AccessFactory(
376
-				$this->ldap,
377
-				$this->userManager,
378
-				$this->ldapHelper,
379
-				$this->config,
380
-				$this->ncUserManager
381
-			);
382
-		}
383
-	}
366
+        if(isset($argument['connectionFactory'])) {
367
+            $this->connectionFactory = $argument['connectionFactory'];
368
+        } else {
369
+            $this->connectionFactory = new ConnectionFactory($this->ldap);
370
+        }
371
+
372
+        if(isset($argument['accessFactory'])) {
373
+            $this->accessFactory = $argument['accessFactory'];
374
+        } else {
375
+            $this->accessFactory = new AccessFactory(
376
+                $this->ldap,
377
+                $this->userManager,
378
+                $this->ldapHelper,
379
+                $this->config,
380
+                $this->ncUserManager
381
+            );
382
+        }
383
+    }
384 384
 }
Please login to merge, or discard this patch.
Spacing   +30 added lines, -30 removed lines patch added patch discarded remove patch
@@ -110,7 +110,7 @@  discard block
 block discarded – undo
110 110
 			$pagingSize = $this->config->getAppValue('user_ldap', $configKey, $minPagingSize);
111 111
 			$minPagingSize = $minPagingSize === null ? $pagingSize : min($minPagingSize, $pagingSize);
112 112
 		}
113
-		return (int)$minPagingSize;
113
+		return (int) $minPagingSize;
114 114
 	}
115 115
 
116 116
 	/**
@@ -121,20 +121,20 @@  discard block
 block discarded – undo
121 121
 
122 122
 		$isBackgroundJobModeAjax = $this->config
123 123
 				->getAppValue('core', 'backgroundjobs_mode', 'ajax') === 'ajax';
124
-		if($isBackgroundJobModeAjax) {
124
+		if ($isBackgroundJobModeAjax) {
125 125
 			return;
126 126
 		}
127 127
 
128 128
 		$cycleData = $this->getCycle();
129
-		if($cycleData === null) {
129
+		if ($cycleData === null) {
130 130
 			$cycleData = $this->determineNextCycle();
131
-			if($cycleData === null) {
131
+			if ($cycleData === null) {
132 132
 				$this->updateInterval();
133 133
 				return;
134 134
 			}
135 135
 		}
136 136
 
137
-		if(!$this->qualifiesToRun($cycleData)) {
137
+		if (!$this->qualifiesToRun($cycleData)) {
138 138
 			$this->updateInterval();
139 139
 			return;
140 140
 		}
@@ -163,7 +163,7 @@  discard block
 block discarded – undo
163 163
 
164 164
 		$filter = $access->combineFilterWithAnd([
165 165
 			$access->connection->ldapUserFilter,
166
-			$access->connection->ldapUserDisplayName . '=*',
166
+			$access->connection->ldapUserDisplayName.'=*',
167 167
 			$access->getFilterPartForUserSearch('')
168 168
 		]);
169 169
 		$results = $access->fetchListOfUsers(
@@ -174,10 +174,10 @@  discard block
 block discarded – undo
174 174
 			true
175 175
 		);
176 176
 
177
-		if((int)$connection->ldapPagingSize === 0) {
177
+		if ((int) $connection->ldapPagingSize === 0) {
178 178
 			return false;
179 179
 		}
180
-		return count($results) >= (int)$connection->ldapPagingSize;
180
+		return count($results) >= (int) $connection->ldapPagingSize;
181 181
 	}
182 182
 
183 183
 	/**
@@ -188,16 +188,16 @@  discard block
 block discarded – undo
188 188
 	 */
189 189
 	public function getCycle() {
190 190
 		$prefixes = $this->ldapHelper->getServerConfigurationPrefixes(true);
191
-		if(count($prefixes) === 0) {
191
+		if (count($prefixes) === 0) {
192 192
 			return null;
193 193
 		}
194 194
 
195 195
 		$cycleData = [
196 196
 			'prefix' => $this->config->getAppValue('user_ldap', 'background_sync_prefix', null),
197
-			'offset' => (int)$this->config->getAppValue('user_ldap', 'background_sync_offset', 0),
197
+			'offset' => (int) $this->config->getAppValue('user_ldap', 'background_sync_offset', 0),
198 198
 		];
199 199
 
200
-		if(
200
+		if (
201 201
 			$cycleData['prefix'] !== null
202 202
 			&& in_array($cycleData['prefix'], $prefixes)
203 203
 		) {
@@ -226,14 +226,14 @@  discard block
 block discarded – undo
226 226
 	 */
227 227
 	public function determineNextCycle(array $cycleData = null) {
228 228
 		$prefixes = $this->ldapHelper->getServerConfigurationPrefixes(true);
229
-		if(count($prefixes) === 0) {
229
+		if (count($prefixes) === 0) {
230 230
 			return null;
231 231
 		}
232 232
 
233 233
 		// get the next prefix in line and remember it
234 234
 		$oldPrefix = $cycleData === null ? null : $cycleData['prefix'];
235 235
 		$prefix = $this->getNextPrefix($oldPrefix);
236
-		if($prefix === null) {
236
+		if ($prefix === null) {
237 237
 			return null;
238 238
 		}
239 239
 		$cycleData['prefix'] = $prefix;
@@ -251,8 +251,8 @@  discard block
 block discarded – undo
251 251
 	 * @return bool
252 252
 	 */
253 253
 	public function qualifiesToRun($cycleData) {
254
-		$lastChange = $this->config->getAppValue('user_ldap', $cycleData['prefix'] . '_lastChange', 0);
255
-		if((time() - $lastChange) > 60 * 30) {
254
+		$lastChange = $this->config->getAppValue('user_ldap', $cycleData['prefix'].'_lastChange', 0);
255
+		if ((time() - $lastChange) > 60 * 30) {
256 256
 			return true;
257 257
 		}
258 258
 		return false;
@@ -265,7 +265,7 @@  discard block
 block discarded – undo
265 265
 	 */
266 266
 	protected function increaseOffset($cycleData) {
267 267
 		$ldapConfig = new Configuration($cycleData['prefix']);
268
-		$cycleData['offset'] += (int)$ldapConfig->ldapPagingSize;
268
+		$cycleData['offset'] += (int) $ldapConfig->ldapPagingSize;
269 269
 		$this->setCycle($cycleData);
270 270
 	}
271 271
 
@@ -278,17 +278,17 @@  discard block
 block discarded – undo
278 278
 	protected function getNextPrefix($lastPrefix) {
279 279
 		$prefixes = $this->ldapHelper->getServerConfigurationPrefixes(true);
280 280
 		$noOfPrefixes = count($prefixes);
281
-		if($noOfPrefixes === 0) {
281
+		if ($noOfPrefixes === 0) {
282 282
 			return null;
283 283
 		}
284 284
 		$i = $lastPrefix === null ? false : array_search($lastPrefix, $prefixes, true);
285
-		if($i === false) {
285
+		if ($i === false) {
286 286
 			$i = -1;
287 287
 		} else {
288 288
 			$i++;
289 289
 		}
290 290
 
291
-		if(!isset($prefixes[$i])) {
291
+		if (!isset($prefixes[$i])) {
292 292
 			$i = 0;
293 293
 		}
294 294
 		return $prefixes[$i];
@@ -300,49 +300,49 @@  discard block
 block discarded – undo
300 300
 	 * @param array $argument
301 301
 	 */
302 302
 	public function setArgument($argument) {
303
-		if(isset($argument['config'])) {
303
+		if (isset($argument['config'])) {
304 304
 			$this->config = $argument['config'];
305 305
 		} else {
306 306
 			$this->config = \OC::$server->getConfig();
307 307
 		}
308 308
 
309
-		if(isset($argument['helper'])) {
309
+		if (isset($argument['helper'])) {
310 310
 			$this->ldapHelper = $argument['helper'];
311 311
 		} else {
312 312
 			$this->ldapHelper = new Helper($this->config);
313 313
 		}
314 314
 
315
-		if(isset($argument['ldapWrapper'])) {
315
+		if (isset($argument['ldapWrapper'])) {
316 316
 			$this->ldap = $argument['ldapWrapper'];
317 317
 		} else {
318 318
 			$this->ldap = new LDAP();
319 319
 		}
320 320
 
321
-		if(isset($argument['avatarManager'])) {
321
+		if (isset($argument['avatarManager'])) {
322 322
 			$this->avatarManager = $argument['avatarManager'];
323 323
 		} else {
324 324
 			$this->avatarManager = \OC::$server->getAvatarManager();
325 325
 		}
326 326
 
327
-		if(isset($argument['dbc'])) {
327
+		if (isset($argument['dbc'])) {
328 328
 			$this->dbc = $argument['dbc'];
329 329
 		} else {
330 330
 			$this->dbc = \OC::$server->getDatabaseConnection();
331 331
 		}
332 332
 
333
-		if(isset($argument['ncUserManager'])) {
333
+		if (isset($argument['ncUserManager'])) {
334 334
 			$this->ncUserManager = $argument['ncUserManager'];
335 335
 		} else {
336 336
 			$this->ncUserManager = \OC::$server->getUserManager();
337 337
 		}
338 338
 
339
-		if(isset($argument['notificationManager'])) {
339
+		if (isset($argument['notificationManager'])) {
340 340
 			$this->notificationManager = $argument['notificationManager'];
341 341
 		} else {
342 342
 			$this->notificationManager = \OC::$server->getNotificationManager();
343 343
 		}
344 344
 
345
-		if(isset($argument['userManager'])) {
345
+		if (isset($argument['userManager'])) {
346 346
 			$this->userManager = $argument['userManager'];
347 347
 		} else {
348 348
 			$this->userManager = new Manager(
@@ -357,19 +357,19 @@  discard block
 block discarded – undo
357 357
 			);
358 358
 		}
359 359
 
360
-		if(isset($argument['mapper'])) {
360
+		if (isset($argument['mapper'])) {
361 361
 			$this->mapper = $argument['mapper'];
362 362
 		} else {
363 363
 			$this->mapper = new UserMapping($this->dbc);
364 364
 		}
365 365
 		
366
-		if(isset($argument['connectionFactory'])) {
366
+		if (isset($argument['connectionFactory'])) {
367 367
 			$this->connectionFactory = $argument['connectionFactory'];
368 368
 		} else {
369 369
 			$this->connectionFactory = new ConnectionFactory($this->ldap);
370 370
 		}
371 371
 
372
-		if(isset($argument['accessFactory'])) {
372
+		if (isset($argument['accessFactory'])) {
373 373
 			$this->accessFactory = $argument['accessFactory'];
374 374
 		} else {
375 375
 			$this->accessFactory = new AccessFactory(
Please login to merge, or discard this patch.
apps/user_ldap/lib/Jobs/UpdateGroups.php 2 patches
Indentation   +164 added lines, -164 removed lines patch added patch discarded remove patch
@@ -45,183 +45,183 @@
 block discarded – undo
45 45
 use OCP\ILogger;
46 46
 
47 47
 class UpdateGroups extends \OC\BackgroundJob\TimedJob {
48
-	static private $groupsFromDB;
49
-
50
-	static private $groupBE;
51
-
52
-	public function __construct(){
53
-		$this->interval = self::getRefreshInterval();
54
-	}
55
-
56
-	/**
57
-	 * @param mixed $argument
58
-	 */
59
-	public function run($argument){
60
-		self::updateGroups();
61
-	}
62
-
63
-	static public function updateGroups() {
64
-		\OCP\Util::writeLog('user_ldap', 'Run background job "updateGroups"', ILogger::DEBUG);
65
-
66
-		$knownGroups = array_keys(self::getKnownGroups());
67
-		$actualGroups = self::getGroupBE()->getGroups();
68
-
69
-		if(empty($actualGroups) && empty($knownGroups)) {
70
-			\OCP\Util::writeLog('user_ldap',
71
-				'bgJ "updateGroups" – groups do not seem to be configured properly, aborting.',
72
-				ILogger::INFO);
73
-			return;
74
-		}
75
-
76
-		self::handleKnownGroups(array_intersect($actualGroups, $knownGroups));
77
-		self::handleCreatedGroups(array_diff($actualGroups, $knownGroups));
78
-		self::handleRemovedGroups(array_diff($knownGroups, $actualGroups));
79
-
80
-		\OCP\Util::writeLog('user_ldap', 'bgJ "updateGroups" – Finished.', ILogger::DEBUG);
81
-	}
82
-
83
-	/**
84
-	 * @return int
85
-	 */
86
-	static private function getRefreshInterval() {
87
-		//defaults to every hour
88
-		return \OC::$server->getConfig()->getAppValue('user_ldap', 'bgjRefreshInterval', 3600);
89
-	}
90
-
91
-	/**
92
-	 * @param string[] $groups
93
-	 */
94
-	static private function handleKnownGroups($groups) {
95
-		\OCP\Util::writeLog('user_ldap', 'bgJ "updateGroups" – Dealing with known Groups.', ILogger::DEBUG);
96
-		$query = \OC_DB::prepare('
48
+    static private $groupsFromDB;
49
+
50
+    static private $groupBE;
51
+
52
+    public function __construct(){
53
+        $this->interval = self::getRefreshInterval();
54
+    }
55
+
56
+    /**
57
+     * @param mixed $argument
58
+     */
59
+    public function run($argument){
60
+        self::updateGroups();
61
+    }
62
+
63
+    static public function updateGroups() {
64
+        \OCP\Util::writeLog('user_ldap', 'Run background job "updateGroups"', ILogger::DEBUG);
65
+
66
+        $knownGroups = array_keys(self::getKnownGroups());
67
+        $actualGroups = self::getGroupBE()->getGroups();
68
+
69
+        if(empty($actualGroups) && empty($knownGroups)) {
70
+            \OCP\Util::writeLog('user_ldap',
71
+                'bgJ "updateGroups" – groups do not seem to be configured properly, aborting.',
72
+                ILogger::INFO);
73
+            return;
74
+        }
75
+
76
+        self::handleKnownGroups(array_intersect($actualGroups, $knownGroups));
77
+        self::handleCreatedGroups(array_diff($actualGroups, $knownGroups));
78
+        self::handleRemovedGroups(array_diff($knownGroups, $actualGroups));
79
+
80
+        \OCP\Util::writeLog('user_ldap', 'bgJ "updateGroups" – Finished.', ILogger::DEBUG);
81
+    }
82
+
83
+    /**
84
+     * @return int
85
+     */
86
+    static private function getRefreshInterval() {
87
+        //defaults to every hour
88
+        return \OC::$server->getConfig()->getAppValue('user_ldap', 'bgjRefreshInterval', 3600);
89
+    }
90
+
91
+    /**
92
+     * @param string[] $groups
93
+     */
94
+    static private function handleKnownGroups($groups) {
95
+        \OCP\Util::writeLog('user_ldap', 'bgJ "updateGroups" – Dealing with known Groups.', ILogger::DEBUG);
96
+        $query = \OC_DB::prepare('
97 97
 			UPDATE `*PREFIX*ldap_group_members`
98 98
 			SET `owncloudusers` = ?
99 99
 			WHERE `owncloudname` = ?
100 100
 		');
101
-		foreach($groups as $group) {
102
-			//we assume, that self::$groupsFromDB has been retrieved already
103
-			$knownUsers = unserialize(self::$groupsFromDB[$group]['owncloudusers']);
104
-			$actualUsers = self::getGroupBE()->usersInGroup($group);
105
-			$hasChanged = false;
106
-			foreach(array_diff($knownUsers, $actualUsers) as $removedUser) {
107
-				\OCP\Util::emitHook('OC_User', 'post_removeFromGroup', ['uid' => $removedUser, 'gid' => $group]);
108
-				\OCP\Util::writeLog('user_ldap',
109
-				'bgJ "updateGroups" – "'.$removedUser.'" removed from "'.$group.'".',
110
-					ILogger::INFO);
111
-				$hasChanged = true;
112
-			}
113
-			foreach(array_diff($actualUsers, $knownUsers) as $addedUser) {
114
-				\OCP\Util::emitHook('OC_User', 'post_addToGroup', ['uid' => $addedUser, 'gid' => $group]);
115
-				\OCP\Util::writeLog('user_ldap',
116
-				'bgJ "updateGroups" – "'.$addedUser.'" added to "'.$group.'".',
117
-					ILogger::INFO);
118
-				$hasChanged = true;
119
-			}
120
-			if($hasChanged) {
121
-				$query->execute([serialize($actualUsers), $group]);
122
-			}
123
-		}
124
-		\OCP\Util::writeLog('user_ldap',
125
-			'bgJ "updateGroups" – FINISHED dealing with known Groups.',
126
-			ILogger::DEBUG);
127
-	}
128
-
129
-	/**
130
-	 * @param string[] $createdGroups
131
-	 */
132
-	static private function handleCreatedGroups($createdGroups) {
133
-		\OCP\Util::writeLog('user_ldap', 'bgJ "updateGroups" – dealing with created Groups.', ILogger::DEBUG);
134
-		$query = \OC_DB::prepare('
101
+        foreach($groups as $group) {
102
+            //we assume, that self::$groupsFromDB has been retrieved already
103
+            $knownUsers = unserialize(self::$groupsFromDB[$group]['owncloudusers']);
104
+            $actualUsers = self::getGroupBE()->usersInGroup($group);
105
+            $hasChanged = false;
106
+            foreach(array_diff($knownUsers, $actualUsers) as $removedUser) {
107
+                \OCP\Util::emitHook('OC_User', 'post_removeFromGroup', ['uid' => $removedUser, 'gid' => $group]);
108
+                \OCP\Util::writeLog('user_ldap',
109
+                'bgJ "updateGroups" – "'.$removedUser.'" removed from "'.$group.'".',
110
+                    ILogger::INFO);
111
+                $hasChanged = true;
112
+            }
113
+            foreach(array_diff($actualUsers, $knownUsers) as $addedUser) {
114
+                \OCP\Util::emitHook('OC_User', 'post_addToGroup', ['uid' => $addedUser, 'gid' => $group]);
115
+                \OCP\Util::writeLog('user_ldap',
116
+                'bgJ "updateGroups" – "'.$addedUser.'" added to "'.$group.'".',
117
+                    ILogger::INFO);
118
+                $hasChanged = true;
119
+            }
120
+            if($hasChanged) {
121
+                $query->execute([serialize($actualUsers), $group]);
122
+            }
123
+        }
124
+        \OCP\Util::writeLog('user_ldap',
125
+            'bgJ "updateGroups" – FINISHED dealing with known Groups.',
126
+            ILogger::DEBUG);
127
+    }
128
+
129
+    /**
130
+     * @param string[] $createdGroups
131
+     */
132
+    static private function handleCreatedGroups($createdGroups) {
133
+        \OCP\Util::writeLog('user_ldap', 'bgJ "updateGroups" – dealing with created Groups.', ILogger::DEBUG);
134
+        $query = \OC_DB::prepare('
135 135
 			INSERT
136 136
 			INTO `*PREFIX*ldap_group_members` (`owncloudname`, `owncloudusers`)
137 137
 			VALUES (?, ?)
138 138
 		');
139
-		foreach($createdGroups as $createdGroup) {
140
-			\OCP\Util::writeLog('user_ldap',
141
-				'bgJ "updateGroups" – new group "'.$createdGroup.'" found.',
142
-				ILogger::INFO);
143
-			$users = serialize(self::getGroupBE()->usersInGroup($createdGroup));
144
-			$query->execute([$createdGroup, $users]);
145
-		}
146
-		\OCP\Util::writeLog('user_ldap',
147
-			'bgJ "updateGroups" – FINISHED dealing with created Groups.',
148
-			ILogger::DEBUG);
149
-	}
150
-
151
-	/**
152
-	 * @param string[] $removedGroups
153
-	 */
154
-	static private function handleRemovedGroups($removedGroups) {
155
-		\OCP\Util::writeLog('user_ldap', 'bgJ "updateGroups" – dealing with removed groups.', ILogger::DEBUG);
156
-		$query = \OC_DB::prepare('
139
+        foreach($createdGroups as $createdGroup) {
140
+            \OCP\Util::writeLog('user_ldap',
141
+                'bgJ "updateGroups" – new group "'.$createdGroup.'" found.',
142
+                ILogger::INFO);
143
+            $users = serialize(self::getGroupBE()->usersInGroup($createdGroup));
144
+            $query->execute([$createdGroup, $users]);
145
+        }
146
+        \OCP\Util::writeLog('user_ldap',
147
+            'bgJ "updateGroups" – FINISHED dealing with created Groups.',
148
+            ILogger::DEBUG);
149
+    }
150
+
151
+    /**
152
+     * @param string[] $removedGroups
153
+     */
154
+    static private function handleRemovedGroups($removedGroups) {
155
+        \OCP\Util::writeLog('user_ldap', 'bgJ "updateGroups" – dealing with removed groups.', ILogger::DEBUG);
156
+        $query = \OC_DB::prepare('
157 157
 			DELETE
158 158
 			FROM `*PREFIX*ldap_group_members`
159 159
 			WHERE `owncloudname` = ?
160 160
 		');
161
-		foreach($removedGroups as $removedGroup) {
162
-			\OCP\Util::writeLog('user_ldap',
163
-				'bgJ "updateGroups" – group "'.$removedGroup.'" was removed.',
164
-				ILogger::INFO);
165
-			$query->execute([$removedGroup]);
166
-		}
167
-		\OCP\Util::writeLog('user_ldap',
168
-			'bgJ "updateGroups" – FINISHED dealing with removed groups.',
169
-			ILogger::DEBUG);
170
-	}
171
-
172
-	/**
173
-	 * @return \OCA\User_LDAP\Group_LDAP|\OCA\User_LDAP\Group_Proxy
174
-	 */
175
-	static private function getGroupBE() {
176
-		if(!is_null(self::$groupBE)) {
177
-			return self::$groupBE;
178
-		}
179
-		$helper = new Helper(\OC::$server->getConfig());
180
-		$configPrefixes = $helper->getServerConfigurationPrefixes(true);
181
-		$ldapWrapper = new LDAP();
182
-		if(count($configPrefixes) === 1) {
183
-			//avoid the proxy when there is only one LDAP server configured
184
-			$dbc = \OC::$server->getDatabaseConnection();
185
-			$userManager = new Manager(
186
-				\OC::$server->getConfig(),
187
-				new FilesystemHelper(),
188
-				new LogWrapper(),
189
-				\OC::$server->getAvatarManager(),
190
-				new \OCP\Image(),
191
-				$dbc,
192
-				\OC::$server->getUserManager(),
193
-				\OC::$server->getNotificationManager());
194
-			$connector = new Connection($ldapWrapper, $configPrefixes[0]);
195
-			$ldapAccess = new Access($connector, $ldapWrapper, $userManager, $helper, \OC::$server->getConfig(), \OC::$server->getUserManager());
196
-			$groupMapper = new GroupMapping($dbc);
197
-			$userMapper  = new UserMapping($dbc);
198
-			$ldapAccess->setGroupMapper($groupMapper);
199
-			$ldapAccess->setUserMapper($userMapper);
200
-			self::$groupBE = new \OCA\User_LDAP\Group_LDAP($ldapAccess, \OC::$server->query('LDAPGroupPluginManager'));
201
-		} else {
202
-			self::$groupBE = new \OCA\User_LDAP\Group_Proxy($configPrefixes, $ldapWrapper, \OC::$server->query('LDAPGroupPluginManager'));
203
-		}
204
-
205
-		return self::$groupBE;
206
-	}
207
-
208
-	/**
209
-	 * @return array
210
-	 */
211
-	static private function getKnownGroups() {
212
-		if(is_array(self::$groupsFromDB)) {
213
-			return self::$groupsFromDB;
214
-		}
215
-		$query = \OC_DB::prepare('
161
+        foreach($removedGroups as $removedGroup) {
162
+            \OCP\Util::writeLog('user_ldap',
163
+                'bgJ "updateGroups" – group "'.$removedGroup.'" was removed.',
164
+                ILogger::INFO);
165
+            $query->execute([$removedGroup]);
166
+        }
167
+        \OCP\Util::writeLog('user_ldap',
168
+            'bgJ "updateGroups" – FINISHED dealing with removed groups.',
169
+            ILogger::DEBUG);
170
+    }
171
+
172
+    /**
173
+     * @return \OCA\User_LDAP\Group_LDAP|\OCA\User_LDAP\Group_Proxy
174
+     */
175
+    static private function getGroupBE() {
176
+        if(!is_null(self::$groupBE)) {
177
+            return self::$groupBE;
178
+        }
179
+        $helper = new Helper(\OC::$server->getConfig());
180
+        $configPrefixes = $helper->getServerConfigurationPrefixes(true);
181
+        $ldapWrapper = new LDAP();
182
+        if(count($configPrefixes) === 1) {
183
+            //avoid the proxy when there is only one LDAP server configured
184
+            $dbc = \OC::$server->getDatabaseConnection();
185
+            $userManager = new Manager(
186
+                \OC::$server->getConfig(),
187
+                new FilesystemHelper(),
188
+                new LogWrapper(),
189
+                \OC::$server->getAvatarManager(),
190
+                new \OCP\Image(),
191
+                $dbc,
192
+                \OC::$server->getUserManager(),
193
+                \OC::$server->getNotificationManager());
194
+            $connector = new Connection($ldapWrapper, $configPrefixes[0]);
195
+            $ldapAccess = new Access($connector, $ldapWrapper, $userManager, $helper, \OC::$server->getConfig(), \OC::$server->getUserManager());
196
+            $groupMapper = new GroupMapping($dbc);
197
+            $userMapper  = new UserMapping($dbc);
198
+            $ldapAccess->setGroupMapper($groupMapper);
199
+            $ldapAccess->setUserMapper($userMapper);
200
+            self::$groupBE = new \OCA\User_LDAP\Group_LDAP($ldapAccess, \OC::$server->query('LDAPGroupPluginManager'));
201
+        } else {
202
+            self::$groupBE = new \OCA\User_LDAP\Group_Proxy($configPrefixes, $ldapWrapper, \OC::$server->query('LDAPGroupPluginManager'));
203
+        }
204
+
205
+        return self::$groupBE;
206
+    }
207
+
208
+    /**
209
+     * @return array
210
+     */
211
+    static private function getKnownGroups() {
212
+        if(is_array(self::$groupsFromDB)) {
213
+            return self::$groupsFromDB;
214
+        }
215
+        $query = \OC_DB::prepare('
216 216
 			SELECT `owncloudname`, `owncloudusers`
217 217
 			FROM `*PREFIX*ldap_group_members`
218 218
 		');
219
-		$result = $query->execute()->fetchAll();
220
-		self::$groupsFromDB = [];
221
-		foreach($result as $dataset) {
222
-			self::$groupsFromDB[$dataset['owncloudname']] = $dataset;
223
-		}
224
-
225
-		return self::$groupsFromDB;
226
-	}
219
+        $result = $query->execute()->fetchAll();
220
+        self::$groupsFromDB = [];
221
+        foreach($result as $dataset) {
222
+            self::$groupsFromDB[$dataset['owncloudname']] = $dataset;
223
+        }
224
+
225
+        return self::$groupsFromDB;
226
+    }
227 227
 }
Please login to merge, or discard this patch.
Spacing   +13 added lines, -13 removed lines patch added patch discarded remove patch
@@ -49,14 +49,14 @@  discard block
 block discarded – undo
49 49
 
50 50
 	static private $groupBE;
51 51
 
52
-	public function __construct(){
52
+	public function __construct() {
53 53
 		$this->interval = self::getRefreshInterval();
54 54
 	}
55 55
 
56 56
 	/**
57 57
 	 * @param mixed $argument
58 58
 	 */
59
-	public function run($argument){
59
+	public function run($argument) {
60 60
 		self::updateGroups();
61 61
 	}
62 62
 
@@ -66,7 +66,7 @@  discard block
 block discarded – undo
66 66
 		$knownGroups = array_keys(self::getKnownGroups());
67 67
 		$actualGroups = self::getGroupBE()->getGroups();
68 68
 
69
-		if(empty($actualGroups) && empty($knownGroups)) {
69
+		if (empty($actualGroups) && empty($knownGroups)) {
70 70
 			\OCP\Util::writeLog('user_ldap',
71 71
 				'bgJ "updateGroups" – groups do not seem to be configured properly, aborting.',
72 72
 				ILogger::INFO);
@@ -98,26 +98,26 @@  discard block
 block discarded – undo
98 98
 			SET `owncloudusers` = ?
99 99
 			WHERE `owncloudname` = ?
100 100
 		');
101
-		foreach($groups as $group) {
101
+		foreach ($groups as $group) {
102 102
 			//we assume, that self::$groupsFromDB has been retrieved already
103 103
 			$knownUsers = unserialize(self::$groupsFromDB[$group]['owncloudusers']);
104 104
 			$actualUsers = self::getGroupBE()->usersInGroup($group);
105 105
 			$hasChanged = false;
106
-			foreach(array_diff($knownUsers, $actualUsers) as $removedUser) {
106
+			foreach (array_diff($knownUsers, $actualUsers) as $removedUser) {
107 107
 				\OCP\Util::emitHook('OC_User', 'post_removeFromGroup', ['uid' => $removedUser, 'gid' => $group]);
108 108
 				\OCP\Util::writeLog('user_ldap',
109 109
 				'bgJ "updateGroups" – "'.$removedUser.'" removed from "'.$group.'".',
110 110
 					ILogger::INFO);
111 111
 				$hasChanged = true;
112 112
 			}
113
-			foreach(array_diff($actualUsers, $knownUsers) as $addedUser) {
113
+			foreach (array_diff($actualUsers, $knownUsers) as $addedUser) {
114 114
 				\OCP\Util::emitHook('OC_User', 'post_addToGroup', ['uid' => $addedUser, 'gid' => $group]);
115 115
 				\OCP\Util::writeLog('user_ldap',
116 116
 				'bgJ "updateGroups" – "'.$addedUser.'" added to "'.$group.'".',
117 117
 					ILogger::INFO);
118 118
 				$hasChanged = true;
119 119
 			}
120
-			if($hasChanged) {
120
+			if ($hasChanged) {
121 121
 				$query->execute([serialize($actualUsers), $group]);
122 122
 			}
123 123
 		}
@@ -136,7 +136,7 @@  discard block
 block discarded – undo
136 136
 			INTO `*PREFIX*ldap_group_members` (`owncloudname`, `owncloudusers`)
137 137
 			VALUES (?, ?)
138 138
 		');
139
-		foreach($createdGroups as $createdGroup) {
139
+		foreach ($createdGroups as $createdGroup) {
140 140
 			\OCP\Util::writeLog('user_ldap',
141 141
 				'bgJ "updateGroups" – new group "'.$createdGroup.'" found.',
142 142
 				ILogger::INFO);
@@ -158,7 +158,7 @@  discard block
 block discarded – undo
158 158
 			FROM `*PREFIX*ldap_group_members`
159 159
 			WHERE `owncloudname` = ?
160 160
 		');
161
-		foreach($removedGroups as $removedGroup) {
161
+		foreach ($removedGroups as $removedGroup) {
162 162
 			\OCP\Util::writeLog('user_ldap',
163 163
 				'bgJ "updateGroups" – group "'.$removedGroup.'" was removed.',
164 164
 				ILogger::INFO);
@@ -173,13 +173,13 @@  discard block
 block discarded – undo
173 173
 	 * @return \OCA\User_LDAP\Group_LDAP|\OCA\User_LDAP\Group_Proxy
174 174
 	 */
175 175
 	static private function getGroupBE() {
176
-		if(!is_null(self::$groupBE)) {
176
+		if (!is_null(self::$groupBE)) {
177 177
 			return self::$groupBE;
178 178
 		}
179 179
 		$helper = new Helper(\OC::$server->getConfig());
180 180
 		$configPrefixes = $helper->getServerConfigurationPrefixes(true);
181 181
 		$ldapWrapper = new LDAP();
182
-		if(count($configPrefixes) === 1) {
182
+		if (count($configPrefixes) === 1) {
183 183
 			//avoid the proxy when there is only one LDAP server configured
184 184
 			$dbc = \OC::$server->getDatabaseConnection();
185 185
 			$userManager = new Manager(
@@ -209,7 +209,7 @@  discard block
 block discarded – undo
209 209
 	 * @return array
210 210
 	 */
211 211
 	static private function getKnownGroups() {
212
-		if(is_array(self::$groupsFromDB)) {
212
+		if (is_array(self::$groupsFromDB)) {
213 213
 			return self::$groupsFromDB;
214 214
 		}
215 215
 		$query = \OC_DB::prepare('
@@ -218,7 +218,7 @@  discard block
 block discarded – undo
218 218
 		');
219 219
 		$result = $query->execute()->fetchAll();
220 220
 		self::$groupsFromDB = [];
221
-		foreach($result as $dataset) {
221
+		foreach ($result as $dataset) {
222 222
 			self::$groupsFromDB[$dataset['owncloudname']] = $dataset;
223 223
 		}
224 224
 
Please login to merge, or discard this patch.
apps/user_ldap/lib/User_LDAP.php 2 patches
Indentation   +579 added lines, -579 removed lines patch added patch discarded remove patch
@@ -52,587 +52,587 @@
 block discarded – undo
52 52
 use OCP\Util;
53 53
 
54 54
 class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserInterface, IUserLDAP {
55
-	/** @var \OCP\IConfig */
56
-	protected $ocConfig;
57
-
58
-	/** @var INotificationManager */
59
-	protected $notificationManager;
60
-
61
-	/** @var UserPluginManager */
62
-	protected $userPluginManager;
63
-
64
-	/**
65
-	 * @param Access $access
66
-	 * @param \OCP\IConfig $ocConfig
67
-	 * @param \OCP\Notification\IManager $notificationManager
68
-	 * @param IUserSession $userSession
69
-	 */
70
-	public function __construct(Access $access, IConfig $ocConfig, INotificationManager $notificationManager, IUserSession $userSession, UserPluginManager $userPluginManager) {
71
-		parent::__construct($access);
72
-		$this->ocConfig = $ocConfig;
73
-		$this->notificationManager = $notificationManager;
74
-		$this->userPluginManager = $userPluginManager;
75
-	}
76
-
77
-	/**
78
-	 * checks whether the user is allowed to change his avatar in Nextcloud
79
-	 *
80
-	 * @param string $uid the Nextcloud user name
81
-	 * @return boolean either the user can or cannot
82
-	 * @throws \Exception
83
-	 */
84
-	public function canChangeAvatar($uid) {
85
-		if ($this->userPluginManager->implementsActions(Backend::PROVIDE_AVATAR)) {
86
-			return $this->userPluginManager->canChangeAvatar($uid);
87
-		}
88
-
89
-		if(!$this->implementsActions(Backend::PROVIDE_AVATAR)) {
90
-			return true;
91
-		}
92
-
93
-		$user = $this->access->userManager->get($uid);
94
-		if(!$user instanceof User) {
95
-			return false;
96
-		}
97
-		$imageData = $user->getAvatarImage();
98
-		if($imageData === false) {
99
-			return true;
100
-		}
101
-		return !$user->updateAvatar(true);
102
-	}
103
-
104
-	/**
105
-	 * Return the username for the given login name, if available
106
-	 *
107
-	 * @param string $loginName
108
-	 * @return string|false
109
-	 * @throws \Exception
110
-	 */
111
-	public function loginName2UserName($loginName) {
112
-		$cacheKey = 'loginName2UserName-' . $loginName;
113
-		$username = $this->access->connection->getFromCache($cacheKey);
114
-
115
-		if ($username !== null) {
116
-			return $username;
117
-		}
118
-
119
-		try {
120
-			$ldapRecord = $this->getLDAPUserByLoginName($loginName);
121
-			$user = $this->access->userManager->get($ldapRecord['dn'][0]);
122
-			if ($user === null || $user instanceof OfflineUser) {
123
-				// this path is not really possible, however get() is documented
124
-				// to return User, OfflineUser or null so we are very defensive here.
125
-				$this->access->connection->writeToCache($cacheKey, false);
126
-				return false;
127
-			}
128
-			$username = $user->getUsername();
129
-			$this->access->connection->writeToCache($cacheKey, $username);
130
-			return $username;
131
-		} catch (NotOnLDAP $e) {
132
-			$this->access->connection->writeToCache($cacheKey, false);
133
-			return false;
134
-		}
135
-	}
55
+    /** @var \OCP\IConfig */
56
+    protected $ocConfig;
57
+
58
+    /** @var INotificationManager */
59
+    protected $notificationManager;
60
+
61
+    /** @var UserPluginManager */
62
+    protected $userPluginManager;
63
+
64
+    /**
65
+     * @param Access $access
66
+     * @param \OCP\IConfig $ocConfig
67
+     * @param \OCP\Notification\IManager $notificationManager
68
+     * @param IUserSession $userSession
69
+     */
70
+    public function __construct(Access $access, IConfig $ocConfig, INotificationManager $notificationManager, IUserSession $userSession, UserPluginManager $userPluginManager) {
71
+        parent::__construct($access);
72
+        $this->ocConfig = $ocConfig;
73
+        $this->notificationManager = $notificationManager;
74
+        $this->userPluginManager = $userPluginManager;
75
+    }
76
+
77
+    /**
78
+     * checks whether the user is allowed to change his avatar in Nextcloud
79
+     *
80
+     * @param string $uid the Nextcloud user name
81
+     * @return boolean either the user can or cannot
82
+     * @throws \Exception
83
+     */
84
+    public function canChangeAvatar($uid) {
85
+        if ($this->userPluginManager->implementsActions(Backend::PROVIDE_AVATAR)) {
86
+            return $this->userPluginManager->canChangeAvatar($uid);
87
+        }
88
+
89
+        if(!$this->implementsActions(Backend::PROVIDE_AVATAR)) {
90
+            return true;
91
+        }
92
+
93
+        $user = $this->access->userManager->get($uid);
94
+        if(!$user instanceof User) {
95
+            return false;
96
+        }
97
+        $imageData = $user->getAvatarImage();
98
+        if($imageData === false) {
99
+            return true;
100
+        }
101
+        return !$user->updateAvatar(true);
102
+    }
103
+
104
+    /**
105
+     * Return the username for the given login name, if available
106
+     *
107
+     * @param string $loginName
108
+     * @return string|false
109
+     * @throws \Exception
110
+     */
111
+    public function loginName2UserName($loginName) {
112
+        $cacheKey = 'loginName2UserName-' . $loginName;
113
+        $username = $this->access->connection->getFromCache($cacheKey);
114
+
115
+        if ($username !== null) {
116
+            return $username;
117
+        }
118
+
119
+        try {
120
+            $ldapRecord = $this->getLDAPUserByLoginName($loginName);
121
+            $user = $this->access->userManager->get($ldapRecord['dn'][0]);
122
+            if ($user === null || $user instanceof OfflineUser) {
123
+                // this path is not really possible, however get() is documented
124
+                // to return User, OfflineUser or null so we are very defensive here.
125
+                $this->access->connection->writeToCache($cacheKey, false);
126
+                return false;
127
+            }
128
+            $username = $user->getUsername();
129
+            $this->access->connection->writeToCache($cacheKey, $username);
130
+            return $username;
131
+        } catch (NotOnLDAP $e) {
132
+            $this->access->connection->writeToCache($cacheKey, false);
133
+            return false;
134
+        }
135
+    }
136 136
 	
137
-	/**
138
-	 * returns the username for the given LDAP DN, if available
139
-	 *
140
-	 * @param string $dn
141
-	 * @return string|false with the username
142
-	 */
143
-	public function dn2UserName($dn) {
144
-		return $this->access->dn2username($dn);
145
-	}
146
-
147
-	/**
148
-	 * returns an LDAP record based on a given login name
149
-	 *
150
-	 * @param string $loginName
151
-	 * @return array
152
-	 * @throws NotOnLDAP
153
-	 */
154
-	public function getLDAPUserByLoginName($loginName) {
155
-		//find out dn of the user name
156
-		$attrs = $this->access->userManager->getAttributes();
157
-		$users = $this->access->fetchUsersByLoginName($loginName, $attrs);
158
-		if(count($users) < 1) {
159
-			throw new NotOnLDAP('No user available for the given login name on ' .
160
-				$this->access->connection->ldapHost . ':' . $this->access->connection->ldapPort);
161
-		}
162
-		return $users[0];
163
-	}
164
-
165
-	/**
166
-	 * Check if the password is correct without logging in the user
167
-	 *
168
-	 * @param string $uid The username
169
-	 * @param string $password The password
170
-	 * @return false|string
171
-	 */
172
-	public function checkPassword($uid, $password) {
173
-		try {
174
-			$ldapRecord = $this->getLDAPUserByLoginName($uid);
175
-		} catch(NotOnLDAP $e) {
176
-			\OC::$server->getLogger()->logException($e, ['app' => 'user_ldap', 'level' => ILogger::DEBUG]);
177
-			return false;
178
-		}
179
-		$dn = $ldapRecord['dn'][0];
180
-		$user = $this->access->userManager->get($dn);
181
-
182
-		if(!$user instanceof User) {
183
-			Util::writeLog('user_ldap',
184
-				'LDAP Login: Could not get user object for DN ' . $dn .
185
-				'. Maybe the LDAP entry has no set display name attribute?',
186
-				ILogger::WARN);
187
-			return false;
188
-		}
189
-		if($user->getUsername() !== false) {
190
-			//are the credentials OK?
191
-			if(!$this->access->areCredentialsValid($dn, $password)) {
192
-				return false;
193
-			}
194
-
195
-			$this->access->cacheUserExists($user->getUsername());
196
-			$user->processAttributes($ldapRecord);
197
-			$user->markLogin();
198
-
199
-			return $user->getUsername();
200
-		}
201
-
202
-		return false;
203
-	}
204
-
205
-	/**
206
-	 * Set password
207
-	 * @param string $uid The username
208
-	 * @param string $password The new password
209
-	 * @return bool
210
-	 */
211
-	public function setPassword($uid, $password) {
212
-		if ($this->userPluginManager->implementsActions(Backend::SET_PASSWORD)) {
213
-			return $this->userPluginManager->setPassword($uid, $password);
214
-		}
215
-
216
-		$user = $this->access->userManager->get($uid);
217
-
218
-		if(!$user instanceof User) {
219
-			throw new \Exception('LDAP setPassword: Could not get user object for uid ' . $uid .
220
-				'. Maybe the LDAP entry has no set display name attribute?');
221
-		}
222
-		if($user->getUsername() !== false && $this->access->setPassword($user->getDN(), $password)) {
223
-			$ldapDefaultPPolicyDN = $this->access->connection->ldapDefaultPPolicyDN;
224
-			$turnOnPasswordChange = $this->access->connection->turnOnPasswordChange;
225
-			if (!empty($ldapDefaultPPolicyDN) && ((int)$turnOnPasswordChange === 1)) {
226
-				//remove last password expiry warning if any
227
-				$notification = $this->notificationManager->createNotification();
228
-				$notification->setApp('user_ldap')
229
-					->setUser($uid)
230
-					->setObject('pwd_exp_warn', $uid)
231
-				;
232
-				$this->notificationManager->markProcessed($notification);
233
-			}
234
-			return true;
235
-		}
236
-
237
-		return false;
238
-	}
239
-
240
-	/**
241
-	 * Get a list of all users
242
-	 *
243
-	 * @param string $search
244
-	 * @param integer $limit
245
-	 * @param integer $offset
246
-	 * @return string[] an array of all uids
247
-	 */
248
-	public function getUsers($search = '', $limit = 10, $offset = 0) {
249
-		$search = $this->access->escapeFilterPart($search, true);
250
-		$cachekey = 'getUsers-'.$search.'-'.$limit.'-'.$offset;
251
-
252
-		//check if users are cached, if so return
253
-		$ldap_users = $this->access->connection->getFromCache($cachekey);
254
-		if(!is_null($ldap_users)) {
255
-			return $ldap_users;
256
-		}
257
-
258
-		// if we'd pass -1 to LDAP search, we'd end up in a Protocol
259
-		// error. With a limit of 0, we get 0 results. So we pass null.
260
-		if($limit <= 0) {
261
-			$limit = null;
262
-		}
263
-		$filter = $this->access->combineFilterWithAnd([
264
-			$this->access->connection->ldapUserFilter,
265
-			$this->access->connection->ldapUserDisplayName . '=*',
266
-			$this->access->getFilterPartForUserSearch($search)
267
-		]);
268
-
269
-		Util::writeLog('user_ldap',
270
-			'getUsers: Options: search '.$search.' limit '.$limit.' offset '.$offset.' Filter: '.$filter,
271
-			ILogger::DEBUG);
272
-		//do the search and translate results to Nextcloud names
273
-		$ldap_users = $this->access->fetchListOfUsers(
274
-			$filter,
275
-			$this->access->userManager->getAttributes(true),
276
-			$limit, $offset);
277
-		$ldap_users = $this->access->nextcloudUserNames($ldap_users);
278
-		Util::writeLog('user_ldap', 'getUsers: '.count($ldap_users). ' Users found', ILogger::DEBUG);
279
-
280
-		$this->access->connection->writeToCache($cachekey, $ldap_users);
281
-		return $ldap_users;
282
-	}
283
-
284
-	/**
285
-	 * checks whether a user is still available on LDAP
286
-	 *
287
-	 * @param string|\OCA\User_LDAP\User\User $user either the Nextcloud user
288
-	 * name or an instance of that user
289
-	 * @return bool
290
-	 * @throws \Exception
291
-	 * @throws \OC\ServerNotAvailableException
292
-	 */
293
-	public function userExistsOnLDAP($user) {
294
-		if(is_string($user)) {
295
-			$user = $this->access->userManager->get($user);
296
-		}
297
-		if(is_null($user)) {
298
-			return false;
299
-		}
300
-		$uid = $user instanceof User ? $user->getUsername() : $user->getOCName();
301
-		$cacheKey = 'userExistsOnLDAP' . $uid;
302
-		$userExists = $this->access->connection->getFromCache($cacheKey);
303
-		if(!is_null($userExists)) {
304
-			return (bool)$userExists;
305
-		}
306
-
307
-		$dn = $user->getDN();
308
-		//check if user really still exists by reading its entry
309
-		if(!is_array($this->access->readAttribute($dn, '', $this->access->connection->ldapUserFilter))) {
310
-			try {
311
-				$uuid = $this->access->getUserMapper()->getUUIDByDN($dn);
312
-				if (!$uuid) {
313
-					$this->access->connection->writeToCache($cacheKey, false);
314
-					return false;
315
-				}
316
-				$newDn = $this->access->getUserDnByUuid($uuid);
317
-				//check if renamed user is still valid by reapplying the ldap filter
318
-				if ($newDn === $dn || !is_array($this->access->readAttribute($newDn, '', $this->access->connection->ldapUserFilter))) {
319
-					$this->access->connection->writeToCache($cacheKey, false);
320
-					return false;
321
-				}
322
-				$this->access->getUserMapper()->setDNbyUUID($newDn, $uuid);
323
-				$this->access->connection->writeToCache($cacheKey, true);
324
-				return true;
325
-			} catch (ServerNotAvailableException $e) {
326
-				throw $e;
327
-			} catch (\Exception $e) {
328
-				$this->access->connection->writeToCache($cacheKey, false);
329
-				return false;
330
-			}
331
-		}
332
-
333
-		if($user instanceof OfflineUser) {
334
-			$user->unmark();
335
-		}
336
-
337
-		$this->access->connection->writeToCache($cacheKey, true);
338
-		return true;
339
-	}
340
-
341
-	/**
342
-	 * check if a user exists
343
-	 * @param string $uid the username
344
-	 * @return boolean
345
-	 * @throws \Exception when connection could not be established
346
-	 */
347
-	public function userExists($uid) {
348
-		$userExists = $this->access->connection->getFromCache('userExists'.$uid);
349
-		if(!is_null($userExists)) {
350
-			return (bool)$userExists;
351
-		}
352
-		//getting dn, if false the user does not exist. If dn, he may be mapped only, requires more checking.
353
-		$user = $this->access->userManager->get($uid);
354
-
355
-		if(is_null($user)) {
356
-			Util::writeLog('user_ldap', 'No DN found for '.$uid.' on '.
357
-				$this->access->connection->ldapHost, ILogger::DEBUG);
358
-			$this->access->connection->writeToCache('userExists'.$uid, false);
359
-			return false;
360
-		}
361
-
362
-		$this->access->connection->writeToCache('userExists'.$uid, true);
363
-		return true;
364
-	}
365
-
366
-	/**
367
-	* returns whether a user was deleted in LDAP
368
-	*
369
-	* @param string $uid The username of the user to delete
370
-	* @return bool
371
-	*/
372
-	public function deleteUser($uid) {
373
-		if ($this->userPluginManager->canDeleteUser()) {
374
-			$status = $this->userPluginManager->deleteUser($uid);
375
-			if($status === false) {
376
-				return false;
377
-			}
378
-		}
379
-
380
-		$marked = $this->ocConfig->getUserValue($uid, 'user_ldap', 'isDeleted', 0);
381
-		if((int)$marked === 0) {
382
-			\OC::$server->getLogger()->notice(
383
-				'User '.$uid . ' is not marked as deleted, not cleaning up.',
384
-				['app' => 'user_ldap']);
385
-			return false;
386
-		}
387
-		\OC::$server->getLogger()->info('Cleaning up after user ' . $uid,
388
-			['app' => 'user_ldap']);
389
-
390
-		$this->access->getUserMapper()->unmap($uid); // we don't emit unassign signals here, since it is implicit to delete signals fired from core
391
-		$this->access->userManager->invalidate($uid);
392
-		return true;
393
-	}
394
-
395
-	/**
396
-	 * get the user's home directory
397
-	 *
398
-	 * @param string $uid the username
399
-	 * @return bool|string
400
-	 * @throws NoUserException
401
-	 * @throws \Exception
402
-	 */
403
-	public function getHome($uid) {
404
-		// user Exists check required as it is not done in user proxy!
405
-		if(!$this->userExists($uid)) {
406
-			return false;
407
-		}
408
-
409
-		if ($this->userPluginManager->implementsActions(Backend::GET_HOME)) {
410
-			return $this->userPluginManager->getHome($uid);
411
-		}
412
-
413
-		$cacheKey = 'getHome'.$uid;
414
-		$path = $this->access->connection->getFromCache($cacheKey);
415
-		if(!is_null($path)) {
416
-			return $path;
417
-		}
418
-
419
-		// early return path if it is a deleted user
420
-		$user = $this->access->userManager->get($uid);
421
-		if($user instanceof User || $user instanceof OfflineUser) {
422
-			$path = $user->getHomePath() ?: false;
423
-		} else {
424
-			throw new NoUserException($uid . ' is not a valid user anymore');
425
-		}
426
-
427
-		$this->access->cacheUserHome($uid, $path);
428
-		return $path;
429
-	}
430
-
431
-	/**
432
-	 * get display name of the user
433
-	 * @param string $uid user ID of the user
434
-	 * @return string|false display name
435
-	 */
436
-	public function getDisplayName($uid) {
437
-		if ($this->userPluginManager->implementsActions(Backend::GET_DISPLAYNAME)) {
438
-			return $this->userPluginManager->getDisplayName($uid);
439
-		}
440
-
441
-		if(!$this->userExists($uid)) {
442
-			return false;
443
-		}
444
-
445
-		$cacheKey = 'getDisplayName'.$uid;
446
-		if(!is_null($displayName = $this->access->connection->getFromCache($cacheKey))) {
447
-			return $displayName;
448
-		}
449
-
450
-		//Check whether the display name is configured to have a 2nd feature
451
-		$additionalAttribute = $this->access->connection->ldapUserDisplayName2;
452
-		$displayName2 = '';
453
-		if ($additionalAttribute !== '') {
454
-			$displayName2 = $this->access->readAttribute(
455
-				$this->access->username2dn($uid),
456
-				$additionalAttribute);
457
-		}
458
-
459
-		$displayName = $this->access->readAttribute(
460
-			$this->access->username2dn($uid),
461
-			$this->access->connection->ldapUserDisplayName);
462
-
463
-		if($displayName && (count($displayName) > 0)) {
464
-			$displayName = $displayName[0];
465
-
466
-			if (is_array($displayName2)){
467
-				$displayName2 = count($displayName2) > 0 ? $displayName2[0] : '';
468
-			}
469
-
470
-			$user = $this->access->userManager->get($uid);
471
-			if ($user instanceof User) {
472
-				$displayName = $user->composeAndStoreDisplayName($displayName, $displayName2);
473
-				$this->access->connection->writeToCache($cacheKey, $displayName);
474
-			}
475
-			if ($user instanceof OfflineUser) {
476
-				/** @var OfflineUser $user*/
477
-				$displayName = $user->getDisplayName();
478
-			}
479
-			return $displayName;
480
-		}
481
-
482
-		return null;
483
-	}
484
-
485
-	/**
486
-	 * set display name of the user
487
-	 * @param string $uid user ID of the user
488
-	 * @param string $displayName new display name of the user
489
-	 * @return string|false display name
490
-	 */
491
-	public function setDisplayName($uid, $displayName) {
492
-		if ($this->userPluginManager->implementsActions(Backend::SET_DISPLAYNAME)) {
493
-			$this->userPluginManager->setDisplayName($uid, $displayName);
494
-			$this->access->cacheUserDisplayName($uid, $displayName);
495
-			return $displayName;
496
-		}
497
-		return false;
498
-	}
499
-
500
-	/**
501
-	 * Get a list of all display names
502
-	 *
503
-	 * @param string $search
504
-	 * @param string|null $limit
505
-	 * @param string|null $offset
506
-	 * @return array an array of all displayNames (value) and the corresponding uids (key)
507
-	 */
508
-	public function getDisplayNames($search = '', $limit = null, $offset = null) {
509
-		$cacheKey = 'getDisplayNames-'.$search.'-'.$limit.'-'.$offset;
510
-		if(!is_null($displayNames = $this->access->connection->getFromCache($cacheKey))) {
511
-			return $displayNames;
512
-		}
513
-
514
-		$displayNames = [];
515
-		$users = $this->getUsers($search, $limit, $offset);
516
-		foreach ($users as $user) {
517
-			$displayNames[$user] = $this->getDisplayName($user);
518
-		}
519
-		$this->access->connection->writeToCache($cacheKey, $displayNames);
520
-		return $displayNames;
521
-	}
522
-
523
-	/**
524
-	* Check if backend implements actions
525
-	* @param int $actions bitwise-or'ed actions
526
-	* @return boolean
527
-	*
528
-	* Returns the supported actions as int to be
529
-	* compared with \OC\User\Backend::CREATE_USER etc.
530
-	*/
531
-	public function implementsActions($actions) {
532
-		return (bool)((Backend::CHECK_PASSWORD
533
-			| Backend::GET_HOME
534
-			| Backend::GET_DISPLAYNAME
535
-			| (($this->access->connection->ldapUserAvatarRule !== 'none') ? Backend::PROVIDE_AVATAR : 0)
536
-			| Backend::COUNT_USERS
537
-			| (((int)$this->access->connection->turnOnPasswordChange === 1)? Backend::SET_PASSWORD :0)
538
-			| $this->userPluginManager->getImplementedActions())
539
-			& $actions);
540
-	}
541
-
542
-	/**
543
-	 * @return bool
544
-	 */
545
-	public function hasUserListings() {
546
-		return true;
547
-	}
548
-
549
-	/**
550
-	 * counts the users in LDAP
551
-	 *
552
-	 * @return int|bool
553
-	 */
554
-	public function countUsers() {
555
-		if ($this->userPluginManager->implementsActions(Backend::COUNT_USERS)) {
556
-			return $this->userPluginManager->countUsers();
557
-		}
558
-
559
-		$filter = $this->access->getFilterForUserCount();
560
-		$cacheKey = 'countUsers-'.$filter;
561
-		if(!is_null($entries = $this->access->connection->getFromCache($cacheKey))) {
562
-			return $entries;
563
-		}
564
-		$entries = $this->access->countUsers($filter);
565
-		$this->access->connection->writeToCache($cacheKey, $entries);
566
-		return $entries;
567
-	}
568
-
569
-	/**
570
-	 * Backend name to be shown in user management
571
-	 * @return string the name of the backend to be shown
572
-	 */
573
-	public function getBackendName(){
574
-		return 'LDAP';
575
-	}
137
+    /**
138
+     * returns the username for the given LDAP DN, if available
139
+     *
140
+     * @param string $dn
141
+     * @return string|false with the username
142
+     */
143
+    public function dn2UserName($dn) {
144
+        return $this->access->dn2username($dn);
145
+    }
146
+
147
+    /**
148
+     * returns an LDAP record based on a given login name
149
+     *
150
+     * @param string $loginName
151
+     * @return array
152
+     * @throws NotOnLDAP
153
+     */
154
+    public function getLDAPUserByLoginName($loginName) {
155
+        //find out dn of the user name
156
+        $attrs = $this->access->userManager->getAttributes();
157
+        $users = $this->access->fetchUsersByLoginName($loginName, $attrs);
158
+        if(count($users) < 1) {
159
+            throw new NotOnLDAP('No user available for the given login name on ' .
160
+                $this->access->connection->ldapHost . ':' . $this->access->connection->ldapPort);
161
+        }
162
+        return $users[0];
163
+    }
164
+
165
+    /**
166
+     * Check if the password is correct without logging in the user
167
+     *
168
+     * @param string $uid The username
169
+     * @param string $password The password
170
+     * @return false|string
171
+     */
172
+    public function checkPassword($uid, $password) {
173
+        try {
174
+            $ldapRecord = $this->getLDAPUserByLoginName($uid);
175
+        } catch(NotOnLDAP $e) {
176
+            \OC::$server->getLogger()->logException($e, ['app' => 'user_ldap', 'level' => ILogger::DEBUG]);
177
+            return false;
178
+        }
179
+        $dn = $ldapRecord['dn'][0];
180
+        $user = $this->access->userManager->get($dn);
181
+
182
+        if(!$user instanceof User) {
183
+            Util::writeLog('user_ldap',
184
+                'LDAP Login: Could not get user object for DN ' . $dn .
185
+                '. Maybe the LDAP entry has no set display name attribute?',
186
+                ILogger::WARN);
187
+            return false;
188
+        }
189
+        if($user->getUsername() !== false) {
190
+            //are the credentials OK?
191
+            if(!$this->access->areCredentialsValid($dn, $password)) {
192
+                return false;
193
+            }
194
+
195
+            $this->access->cacheUserExists($user->getUsername());
196
+            $user->processAttributes($ldapRecord);
197
+            $user->markLogin();
198
+
199
+            return $user->getUsername();
200
+        }
201
+
202
+        return false;
203
+    }
204
+
205
+    /**
206
+     * Set password
207
+     * @param string $uid The username
208
+     * @param string $password The new password
209
+     * @return bool
210
+     */
211
+    public function setPassword($uid, $password) {
212
+        if ($this->userPluginManager->implementsActions(Backend::SET_PASSWORD)) {
213
+            return $this->userPluginManager->setPassword($uid, $password);
214
+        }
215
+
216
+        $user = $this->access->userManager->get($uid);
217
+
218
+        if(!$user instanceof User) {
219
+            throw new \Exception('LDAP setPassword: Could not get user object for uid ' . $uid .
220
+                '. Maybe the LDAP entry has no set display name attribute?');
221
+        }
222
+        if($user->getUsername() !== false && $this->access->setPassword($user->getDN(), $password)) {
223
+            $ldapDefaultPPolicyDN = $this->access->connection->ldapDefaultPPolicyDN;
224
+            $turnOnPasswordChange = $this->access->connection->turnOnPasswordChange;
225
+            if (!empty($ldapDefaultPPolicyDN) && ((int)$turnOnPasswordChange === 1)) {
226
+                //remove last password expiry warning if any
227
+                $notification = $this->notificationManager->createNotification();
228
+                $notification->setApp('user_ldap')
229
+                    ->setUser($uid)
230
+                    ->setObject('pwd_exp_warn', $uid)
231
+                ;
232
+                $this->notificationManager->markProcessed($notification);
233
+            }
234
+            return true;
235
+        }
236
+
237
+        return false;
238
+    }
239
+
240
+    /**
241
+     * Get a list of all users
242
+     *
243
+     * @param string $search
244
+     * @param integer $limit
245
+     * @param integer $offset
246
+     * @return string[] an array of all uids
247
+     */
248
+    public function getUsers($search = '', $limit = 10, $offset = 0) {
249
+        $search = $this->access->escapeFilterPart($search, true);
250
+        $cachekey = 'getUsers-'.$search.'-'.$limit.'-'.$offset;
251
+
252
+        //check if users are cached, if so return
253
+        $ldap_users = $this->access->connection->getFromCache($cachekey);
254
+        if(!is_null($ldap_users)) {
255
+            return $ldap_users;
256
+        }
257
+
258
+        // if we'd pass -1 to LDAP search, we'd end up in a Protocol
259
+        // error. With a limit of 0, we get 0 results. So we pass null.
260
+        if($limit <= 0) {
261
+            $limit = null;
262
+        }
263
+        $filter = $this->access->combineFilterWithAnd([
264
+            $this->access->connection->ldapUserFilter,
265
+            $this->access->connection->ldapUserDisplayName . '=*',
266
+            $this->access->getFilterPartForUserSearch($search)
267
+        ]);
268
+
269
+        Util::writeLog('user_ldap',
270
+            'getUsers: Options: search '.$search.' limit '.$limit.' offset '.$offset.' Filter: '.$filter,
271
+            ILogger::DEBUG);
272
+        //do the search and translate results to Nextcloud names
273
+        $ldap_users = $this->access->fetchListOfUsers(
274
+            $filter,
275
+            $this->access->userManager->getAttributes(true),
276
+            $limit, $offset);
277
+        $ldap_users = $this->access->nextcloudUserNames($ldap_users);
278
+        Util::writeLog('user_ldap', 'getUsers: '.count($ldap_users). ' Users found', ILogger::DEBUG);
279
+
280
+        $this->access->connection->writeToCache($cachekey, $ldap_users);
281
+        return $ldap_users;
282
+    }
283
+
284
+    /**
285
+     * checks whether a user is still available on LDAP
286
+     *
287
+     * @param string|\OCA\User_LDAP\User\User $user either the Nextcloud user
288
+     * name or an instance of that user
289
+     * @return bool
290
+     * @throws \Exception
291
+     * @throws \OC\ServerNotAvailableException
292
+     */
293
+    public function userExistsOnLDAP($user) {
294
+        if(is_string($user)) {
295
+            $user = $this->access->userManager->get($user);
296
+        }
297
+        if(is_null($user)) {
298
+            return false;
299
+        }
300
+        $uid = $user instanceof User ? $user->getUsername() : $user->getOCName();
301
+        $cacheKey = 'userExistsOnLDAP' . $uid;
302
+        $userExists = $this->access->connection->getFromCache($cacheKey);
303
+        if(!is_null($userExists)) {
304
+            return (bool)$userExists;
305
+        }
306
+
307
+        $dn = $user->getDN();
308
+        //check if user really still exists by reading its entry
309
+        if(!is_array($this->access->readAttribute($dn, '', $this->access->connection->ldapUserFilter))) {
310
+            try {
311
+                $uuid = $this->access->getUserMapper()->getUUIDByDN($dn);
312
+                if (!$uuid) {
313
+                    $this->access->connection->writeToCache($cacheKey, false);
314
+                    return false;
315
+                }
316
+                $newDn = $this->access->getUserDnByUuid($uuid);
317
+                //check if renamed user is still valid by reapplying the ldap filter
318
+                if ($newDn === $dn || !is_array($this->access->readAttribute($newDn, '', $this->access->connection->ldapUserFilter))) {
319
+                    $this->access->connection->writeToCache($cacheKey, false);
320
+                    return false;
321
+                }
322
+                $this->access->getUserMapper()->setDNbyUUID($newDn, $uuid);
323
+                $this->access->connection->writeToCache($cacheKey, true);
324
+                return true;
325
+            } catch (ServerNotAvailableException $e) {
326
+                throw $e;
327
+            } catch (\Exception $e) {
328
+                $this->access->connection->writeToCache($cacheKey, false);
329
+                return false;
330
+            }
331
+        }
332
+
333
+        if($user instanceof OfflineUser) {
334
+            $user->unmark();
335
+        }
336
+
337
+        $this->access->connection->writeToCache($cacheKey, true);
338
+        return true;
339
+    }
340
+
341
+    /**
342
+     * check if a user exists
343
+     * @param string $uid the username
344
+     * @return boolean
345
+     * @throws \Exception when connection could not be established
346
+     */
347
+    public function userExists($uid) {
348
+        $userExists = $this->access->connection->getFromCache('userExists'.$uid);
349
+        if(!is_null($userExists)) {
350
+            return (bool)$userExists;
351
+        }
352
+        //getting dn, if false the user does not exist. If dn, he may be mapped only, requires more checking.
353
+        $user = $this->access->userManager->get($uid);
354
+
355
+        if(is_null($user)) {
356
+            Util::writeLog('user_ldap', 'No DN found for '.$uid.' on '.
357
+                $this->access->connection->ldapHost, ILogger::DEBUG);
358
+            $this->access->connection->writeToCache('userExists'.$uid, false);
359
+            return false;
360
+        }
361
+
362
+        $this->access->connection->writeToCache('userExists'.$uid, true);
363
+        return true;
364
+    }
365
+
366
+    /**
367
+     * returns whether a user was deleted in LDAP
368
+     *
369
+     * @param string $uid The username of the user to delete
370
+     * @return bool
371
+     */
372
+    public function deleteUser($uid) {
373
+        if ($this->userPluginManager->canDeleteUser()) {
374
+            $status = $this->userPluginManager->deleteUser($uid);
375
+            if($status === false) {
376
+                return false;
377
+            }
378
+        }
379
+
380
+        $marked = $this->ocConfig->getUserValue($uid, 'user_ldap', 'isDeleted', 0);
381
+        if((int)$marked === 0) {
382
+            \OC::$server->getLogger()->notice(
383
+                'User '.$uid . ' is not marked as deleted, not cleaning up.',
384
+                ['app' => 'user_ldap']);
385
+            return false;
386
+        }
387
+        \OC::$server->getLogger()->info('Cleaning up after user ' . $uid,
388
+            ['app' => 'user_ldap']);
389
+
390
+        $this->access->getUserMapper()->unmap($uid); // we don't emit unassign signals here, since it is implicit to delete signals fired from core
391
+        $this->access->userManager->invalidate($uid);
392
+        return true;
393
+    }
394
+
395
+    /**
396
+     * get the user's home directory
397
+     *
398
+     * @param string $uid the username
399
+     * @return bool|string
400
+     * @throws NoUserException
401
+     * @throws \Exception
402
+     */
403
+    public function getHome($uid) {
404
+        // user Exists check required as it is not done in user proxy!
405
+        if(!$this->userExists($uid)) {
406
+            return false;
407
+        }
408
+
409
+        if ($this->userPluginManager->implementsActions(Backend::GET_HOME)) {
410
+            return $this->userPluginManager->getHome($uid);
411
+        }
412
+
413
+        $cacheKey = 'getHome'.$uid;
414
+        $path = $this->access->connection->getFromCache($cacheKey);
415
+        if(!is_null($path)) {
416
+            return $path;
417
+        }
418
+
419
+        // early return path if it is a deleted user
420
+        $user = $this->access->userManager->get($uid);
421
+        if($user instanceof User || $user instanceof OfflineUser) {
422
+            $path = $user->getHomePath() ?: false;
423
+        } else {
424
+            throw new NoUserException($uid . ' is not a valid user anymore');
425
+        }
426
+
427
+        $this->access->cacheUserHome($uid, $path);
428
+        return $path;
429
+    }
430
+
431
+    /**
432
+     * get display name of the user
433
+     * @param string $uid user ID of the user
434
+     * @return string|false display name
435
+     */
436
+    public function getDisplayName($uid) {
437
+        if ($this->userPluginManager->implementsActions(Backend::GET_DISPLAYNAME)) {
438
+            return $this->userPluginManager->getDisplayName($uid);
439
+        }
440
+
441
+        if(!$this->userExists($uid)) {
442
+            return false;
443
+        }
444
+
445
+        $cacheKey = 'getDisplayName'.$uid;
446
+        if(!is_null($displayName = $this->access->connection->getFromCache($cacheKey))) {
447
+            return $displayName;
448
+        }
449
+
450
+        //Check whether the display name is configured to have a 2nd feature
451
+        $additionalAttribute = $this->access->connection->ldapUserDisplayName2;
452
+        $displayName2 = '';
453
+        if ($additionalAttribute !== '') {
454
+            $displayName2 = $this->access->readAttribute(
455
+                $this->access->username2dn($uid),
456
+                $additionalAttribute);
457
+        }
458
+
459
+        $displayName = $this->access->readAttribute(
460
+            $this->access->username2dn($uid),
461
+            $this->access->connection->ldapUserDisplayName);
462
+
463
+        if($displayName && (count($displayName) > 0)) {
464
+            $displayName = $displayName[0];
465
+
466
+            if (is_array($displayName2)){
467
+                $displayName2 = count($displayName2) > 0 ? $displayName2[0] : '';
468
+            }
469
+
470
+            $user = $this->access->userManager->get($uid);
471
+            if ($user instanceof User) {
472
+                $displayName = $user->composeAndStoreDisplayName($displayName, $displayName2);
473
+                $this->access->connection->writeToCache($cacheKey, $displayName);
474
+            }
475
+            if ($user instanceof OfflineUser) {
476
+                /** @var OfflineUser $user*/
477
+                $displayName = $user->getDisplayName();
478
+            }
479
+            return $displayName;
480
+        }
481
+
482
+        return null;
483
+    }
484
+
485
+    /**
486
+     * set display name of the user
487
+     * @param string $uid user ID of the user
488
+     * @param string $displayName new display name of the user
489
+     * @return string|false display name
490
+     */
491
+    public function setDisplayName($uid, $displayName) {
492
+        if ($this->userPluginManager->implementsActions(Backend::SET_DISPLAYNAME)) {
493
+            $this->userPluginManager->setDisplayName($uid, $displayName);
494
+            $this->access->cacheUserDisplayName($uid, $displayName);
495
+            return $displayName;
496
+        }
497
+        return false;
498
+    }
499
+
500
+    /**
501
+     * Get a list of all display names
502
+     *
503
+     * @param string $search
504
+     * @param string|null $limit
505
+     * @param string|null $offset
506
+     * @return array an array of all displayNames (value) and the corresponding uids (key)
507
+     */
508
+    public function getDisplayNames($search = '', $limit = null, $offset = null) {
509
+        $cacheKey = 'getDisplayNames-'.$search.'-'.$limit.'-'.$offset;
510
+        if(!is_null($displayNames = $this->access->connection->getFromCache($cacheKey))) {
511
+            return $displayNames;
512
+        }
513
+
514
+        $displayNames = [];
515
+        $users = $this->getUsers($search, $limit, $offset);
516
+        foreach ($users as $user) {
517
+            $displayNames[$user] = $this->getDisplayName($user);
518
+        }
519
+        $this->access->connection->writeToCache($cacheKey, $displayNames);
520
+        return $displayNames;
521
+    }
522
+
523
+    /**
524
+     * Check if backend implements actions
525
+     * @param int $actions bitwise-or'ed actions
526
+     * @return boolean
527
+     *
528
+     * Returns the supported actions as int to be
529
+     * compared with \OC\User\Backend::CREATE_USER etc.
530
+     */
531
+    public function implementsActions($actions) {
532
+        return (bool)((Backend::CHECK_PASSWORD
533
+            | Backend::GET_HOME
534
+            | Backend::GET_DISPLAYNAME
535
+            | (($this->access->connection->ldapUserAvatarRule !== 'none') ? Backend::PROVIDE_AVATAR : 0)
536
+            | Backend::COUNT_USERS
537
+            | (((int)$this->access->connection->turnOnPasswordChange === 1)? Backend::SET_PASSWORD :0)
538
+            | $this->userPluginManager->getImplementedActions())
539
+            & $actions);
540
+    }
541
+
542
+    /**
543
+     * @return bool
544
+     */
545
+    public function hasUserListings() {
546
+        return true;
547
+    }
548
+
549
+    /**
550
+     * counts the users in LDAP
551
+     *
552
+     * @return int|bool
553
+     */
554
+    public function countUsers() {
555
+        if ($this->userPluginManager->implementsActions(Backend::COUNT_USERS)) {
556
+            return $this->userPluginManager->countUsers();
557
+        }
558
+
559
+        $filter = $this->access->getFilterForUserCount();
560
+        $cacheKey = 'countUsers-'.$filter;
561
+        if(!is_null($entries = $this->access->connection->getFromCache($cacheKey))) {
562
+            return $entries;
563
+        }
564
+        $entries = $this->access->countUsers($filter);
565
+        $this->access->connection->writeToCache($cacheKey, $entries);
566
+        return $entries;
567
+    }
568
+
569
+    /**
570
+     * Backend name to be shown in user management
571
+     * @return string the name of the backend to be shown
572
+     */
573
+    public function getBackendName(){
574
+        return 'LDAP';
575
+    }
576 576
 	
577
-	/**
578
-	 * Return access for LDAP interaction.
579
-	 * @param string $uid
580
-	 * @return Access instance of Access for LDAP interaction
581
-	 */
582
-	public function getLDAPAccess($uid) {
583
-		return $this->access;
584
-	}
577
+    /**
578
+     * Return access for LDAP interaction.
579
+     * @param string $uid
580
+     * @return Access instance of Access for LDAP interaction
581
+     */
582
+    public function getLDAPAccess($uid) {
583
+        return $this->access;
584
+    }
585 585
 	
586
-	/**
587
-	 * Return LDAP connection resource from a cloned connection.
588
-	 * The cloned connection needs to be closed manually.
589
-	 * of the current access.
590
-	 * @param string $uid
591
-	 * @return resource of the LDAP connection
592
-	 */
593
-	public function getNewLDAPConnection($uid) {
594
-		$connection = clone $this->access->getConnection();
595
-		return $connection->getConnectionResource();
596
-	}
597
-
598
-	/**
599
-	 * create new user
600
-	 * @param string $username username of the new user
601
-	 * @param string $password password of the new user
602
-	 * @throws \UnexpectedValueException
603
-	 * @return bool
604
-	 */
605
-	public function createUser($username, $password) {
606
-		if ($this->userPluginManager->implementsActions(Backend::CREATE_USER)) {
607
-			if ($dn = $this->userPluginManager->createUser($username, $password)) {
608
-				if (is_string($dn)) {
609
-					// the NC user creation work flow requires a know user id up front
610
-					$uuid = $this->access->getUUID($dn, true);
611
-					if(is_string($uuid)) {
612
-						$this->access->mapAndAnnounceIfApplicable(
613
-							$this->access->getUserMapper(),
614
-							$dn,
615
-							$username,
616
-							$uuid,
617
-							true
618
-						);
619
-						$this->access->cacheUserExists($username);
620
-					} else {
621
-						\OC::$server->getLogger()->warning(
622
-							'Failed to map created LDAP user with userid {userid}, because UUID could not be determined',
623
-							[
624
-								'app' => 'user_ldap',
625
-								'userid' => $username,
626
-							]
627
-						);
628
-					}
629
-				} else {
630
-					throw new \UnexpectedValueException("LDAP Plugin: Method createUser changed to return the user DN instead of boolean.");
631
-				}
632
-			}
633
-			return (bool) $dn;
634
-		}
635
-		return false;
636
-	}
586
+    /**
587
+     * Return LDAP connection resource from a cloned connection.
588
+     * The cloned connection needs to be closed manually.
589
+     * of the current access.
590
+     * @param string $uid
591
+     * @return resource of the LDAP connection
592
+     */
593
+    public function getNewLDAPConnection($uid) {
594
+        $connection = clone $this->access->getConnection();
595
+        return $connection->getConnectionResource();
596
+    }
597
+
598
+    /**
599
+     * create new user
600
+     * @param string $username username of the new user
601
+     * @param string $password password of the new user
602
+     * @throws \UnexpectedValueException
603
+     * @return bool
604
+     */
605
+    public function createUser($username, $password) {
606
+        if ($this->userPluginManager->implementsActions(Backend::CREATE_USER)) {
607
+            if ($dn = $this->userPluginManager->createUser($username, $password)) {
608
+                if (is_string($dn)) {
609
+                    // the NC user creation work flow requires a know user id up front
610
+                    $uuid = $this->access->getUUID($dn, true);
611
+                    if(is_string($uuid)) {
612
+                        $this->access->mapAndAnnounceIfApplicable(
613
+                            $this->access->getUserMapper(),
614
+                            $dn,
615
+                            $username,
616
+                            $uuid,
617
+                            true
618
+                        );
619
+                        $this->access->cacheUserExists($username);
620
+                    } else {
621
+                        \OC::$server->getLogger()->warning(
622
+                            'Failed to map created LDAP user with userid {userid}, because UUID could not be determined',
623
+                            [
624
+                                'app' => 'user_ldap',
625
+                                'userid' => $username,
626
+                            ]
627
+                        );
628
+                    }
629
+                } else {
630
+                    throw new \UnexpectedValueException("LDAP Plugin: Method createUser changed to return the user DN instead of boolean.");
631
+                }
632
+            }
633
+            return (bool) $dn;
634
+        }
635
+        return false;
636
+    }
637 637
 
638 638
 }
Please login to merge, or discard this patch.
Spacing   +48 added lines, -48 removed lines patch added patch discarded remove patch
@@ -86,16 +86,16 @@  discard block
 block discarded – undo
86 86
 			return $this->userPluginManager->canChangeAvatar($uid);
87 87
 		}
88 88
 
89
-		if(!$this->implementsActions(Backend::PROVIDE_AVATAR)) {
89
+		if (!$this->implementsActions(Backend::PROVIDE_AVATAR)) {
90 90
 			return true;
91 91
 		}
92 92
 
93 93
 		$user = $this->access->userManager->get($uid);
94
-		if(!$user instanceof User) {
94
+		if (!$user instanceof User) {
95 95
 			return false;
96 96
 		}
97 97
 		$imageData = $user->getAvatarImage();
98
-		if($imageData === false) {
98
+		if ($imageData === false) {
99 99
 			return true;
100 100
 		}
101 101
 		return !$user->updateAvatar(true);
@@ -109,7 +109,7 @@  discard block
 block discarded – undo
109 109
 	 * @throws \Exception
110 110
 	 */
111 111
 	public function loginName2UserName($loginName) {
112
-		$cacheKey = 'loginName2UserName-' . $loginName;
112
+		$cacheKey = 'loginName2UserName-'.$loginName;
113 113
 		$username = $this->access->connection->getFromCache($cacheKey);
114 114
 
115 115
 		if ($username !== null) {
@@ -155,9 +155,9 @@  discard block
 block discarded – undo
155 155
 		//find out dn of the user name
156 156
 		$attrs = $this->access->userManager->getAttributes();
157 157
 		$users = $this->access->fetchUsersByLoginName($loginName, $attrs);
158
-		if(count($users) < 1) {
159
-			throw new NotOnLDAP('No user available for the given login name on ' .
160
-				$this->access->connection->ldapHost . ':' . $this->access->connection->ldapPort);
158
+		if (count($users) < 1) {
159
+			throw new NotOnLDAP('No user available for the given login name on '.
160
+				$this->access->connection->ldapHost.':'.$this->access->connection->ldapPort);
161 161
 		}
162 162
 		return $users[0];
163 163
 	}
@@ -172,23 +172,23 @@  discard block
 block discarded – undo
172 172
 	public function checkPassword($uid, $password) {
173 173
 		try {
174 174
 			$ldapRecord = $this->getLDAPUserByLoginName($uid);
175
-		} catch(NotOnLDAP $e) {
175
+		} catch (NotOnLDAP $e) {
176 176
 			\OC::$server->getLogger()->logException($e, ['app' => 'user_ldap', 'level' => ILogger::DEBUG]);
177 177
 			return false;
178 178
 		}
179 179
 		$dn = $ldapRecord['dn'][0];
180 180
 		$user = $this->access->userManager->get($dn);
181 181
 
182
-		if(!$user instanceof User) {
182
+		if (!$user instanceof User) {
183 183
 			Util::writeLog('user_ldap',
184
-				'LDAP Login: Could not get user object for DN ' . $dn .
184
+				'LDAP Login: Could not get user object for DN '.$dn.
185 185
 				'. Maybe the LDAP entry has no set display name attribute?',
186 186
 				ILogger::WARN);
187 187
 			return false;
188 188
 		}
189
-		if($user->getUsername() !== false) {
189
+		if ($user->getUsername() !== false) {
190 190
 			//are the credentials OK?
191
-			if(!$this->access->areCredentialsValid($dn, $password)) {
191
+			if (!$this->access->areCredentialsValid($dn, $password)) {
192 192
 				return false;
193 193
 			}
194 194
 
@@ -215,14 +215,14 @@  discard block
 block discarded – undo
215 215
 
216 216
 		$user = $this->access->userManager->get($uid);
217 217
 
218
-		if(!$user instanceof User) {
219
-			throw new \Exception('LDAP setPassword: Could not get user object for uid ' . $uid .
218
+		if (!$user instanceof User) {
219
+			throw new \Exception('LDAP setPassword: Could not get user object for uid '.$uid.
220 220
 				'. Maybe the LDAP entry has no set display name attribute?');
221 221
 		}
222
-		if($user->getUsername() !== false && $this->access->setPassword($user->getDN(), $password)) {
222
+		if ($user->getUsername() !== false && $this->access->setPassword($user->getDN(), $password)) {
223 223
 			$ldapDefaultPPolicyDN = $this->access->connection->ldapDefaultPPolicyDN;
224 224
 			$turnOnPasswordChange = $this->access->connection->turnOnPasswordChange;
225
-			if (!empty($ldapDefaultPPolicyDN) && ((int)$turnOnPasswordChange === 1)) {
225
+			if (!empty($ldapDefaultPPolicyDN) && ((int) $turnOnPasswordChange === 1)) {
226 226
 				//remove last password expiry warning if any
227 227
 				$notification = $this->notificationManager->createNotification();
228 228
 				$notification->setApp('user_ldap')
@@ -251,18 +251,18 @@  discard block
 block discarded – undo
251 251
 
252 252
 		//check if users are cached, if so return
253 253
 		$ldap_users = $this->access->connection->getFromCache($cachekey);
254
-		if(!is_null($ldap_users)) {
254
+		if (!is_null($ldap_users)) {
255 255
 			return $ldap_users;
256 256
 		}
257 257
 
258 258
 		// if we'd pass -1 to LDAP search, we'd end up in a Protocol
259 259
 		// error. With a limit of 0, we get 0 results. So we pass null.
260
-		if($limit <= 0) {
260
+		if ($limit <= 0) {
261 261
 			$limit = null;
262 262
 		}
263 263
 		$filter = $this->access->combineFilterWithAnd([
264 264
 			$this->access->connection->ldapUserFilter,
265
-			$this->access->connection->ldapUserDisplayName . '=*',
265
+			$this->access->connection->ldapUserDisplayName.'=*',
266 266
 			$this->access->getFilterPartForUserSearch($search)
267 267
 		]);
268 268
 
@@ -275,7 +275,7 @@  discard block
 block discarded – undo
275 275
 			$this->access->userManager->getAttributes(true),
276 276
 			$limit, $offset);
277 277
 		$ldap_users = $this->access->nextcloudUserNames($ldap_users);
278
-		Util::writeLog('user_ldap', 'getUsers: '.count($ldap_users). ' Users found', ILogger::DEBUG);
278
+		Util::writeLog('user_ldap', 'getUsers: '.count($ldap_users).' Users found', ILogger::DEBUG);
279 279
 
280 280
 		$this->access->connection->writeToCache($cachekey, $ldap_users);
281 281
 		return $ldap_users;
@@ -291,22 +291,22 @@  discard block
 block discarded – undo
291 291
 	 * @throws \OC\ServerNotAvailableException
292 292
 	 */
293 293
 	public function userExistsOnLDAP($user) {
294
-		if(is_string($user)) {
294
+		if (is_string($user)) {
295 295
 			$user = $this->access->userManager->get($user);
296 296
 		}
297
-		if(is_null($user)) {
297
+		if (is_null($user)) {
298 298
 			return false;
299 299
 		}
300 300
 		$uid = $user instanceof User ? $user->getUsername() : $user->getOCName();
301
-		$cacheKey = 'userExistsOnLDAP' . $uid;
301
+		$cacheKey = 'userExistsOnLDAP'.$uid;
302 302
 		$userExists = $this->access->connection->getFromCache($cacheKey);
303
-		if(!is_null($userExists)) {
304
-			return (bool)$userExists;
303
+		if (!is_null($userExists)) {
304
+			return (bool) $userExists;
305 305
 		}
306 306
 
307 307
 		$dn = $user->getDN();
308 308
 		//check if user really still exists by reading its entry
309
-		if(!is_array($this->access->readAttribute($dn, '', $this->access->connection->ldapUserFilter))) {
309
+		if (!is_array($this->access->readAttribute($dn, '', $this->access->connection->ldapUserFilter))) {
310 310
 			try {
311 311
 				$uuid = $this->access->getUserMapper()->getUUIDByDN($dn);
312 312
 				if (!$uuid) {
@@ -330,7 +330,7 @@  discard block
 block discarded – undo
330 330
 			}
331 331
 		}
332 332
 
333
-		if($user instanceof OfflineUser) {
333
+		if ($user instanceof OfflineUser) {
334 334
 			$user->unmark();
335 335
 		}
336 336
 
@@ -346,13 +346,13 @@  discard block
 block discarded – undo
346 346
 	 */
347 347
 	public function userExists($uid) {
348 348
 		$userExists = $this->access->connection->getFromCache('userExists'.$uid);
349
-		if(!is_null($userExists)) {
350
-			return (bool)$userExists;
349
+		if (!is_null($userExists)) {
350
+			return (bool) $userExists;
351 351
 		}
352 352
 		//getting dn, if false the user does not exist. If dn, he may be mapped only, requires more checking.
353 353
 		$user = $this->access->userManager->get($uid);
354 354
 
355
-		if(is_null($user)) {
355
+		if (is_null($user)) {
356 356
 			Util::writeLog('user_ldap', 'No DN found for '.$uid.' on '.
357 357
 				$this->access->connection->ldapHost, ILogger::DEBUG);
358 358
 			$this->access->connection->writeToCache('userExists'.$uid, false);
@@ -372,19 +372,19 @@  discard block
 block discarded – undo
372 372
 	public function deleteUser($uid) {
373 373
 		if ($this->userPluginManager->canDeleteUser()) {
374 374
 			$status = $this->userPluginManager->deleteUser($uid);
375
-			if($status === false) {
375
+			if ($status === false) {
376 376
 				return false;
377 377
 			}
378 378
 		}
379 379
 
380 380
 		$marked = $this->ocConfig->getUserValue($uid, 'user_ldap', 'isDeleted', 0);
381
-		if((int)$marked === 0) {
381
+		if ((int) $marked === 0) {
382 382
 			\OC::$server->getLogger()->notice(
383
-				'User '.$uid . ' is not marked as deleted, not cleaning up.',
383
+				'User '.$uid.' is not marked as deleted, not cleaning up.',
384 384
 				['app' => 'user_ldap']);
385 385
 			return false;
386 386
 		}
387
-		\OC::$server->getLogger()->info('Cleaning up after user ' . $uid,
387
+		\OC::$server->getLogger()->info('Cleaning up after user '.$uid,
388 388
 			['app' => 'user_ldap']);
389 389
 
390 390
 		$this->access->getUserMapper()->unmap($uid); // we don't emit unassign signals here, since it is implicit to delete signals fired from core
@@ -402,7 +402,7 @@  discard block
 block discarded – undo
402 402
 	 */
403 403
 	public function getHome($uid) {
404 404
 		// user Exists check required as it is not done in user proxy!
405
-		if(!$this->userExists($uid)) {
405
+		if (!$this->userExists($uid)) {
406 406
 			return false;
407 407
 		}
408 408
 
@@ -412,16 +412,16 @@  discard block
 block discarded – undo
412 412
 
413 413
 		$cacheKey = 'getHome'.$uid;
414 414
 		$path = $this->access->connection->getFromCache($cacheKey);
415
-		if(!is_null($path)) {
415
+		if (!is_null($path)) {
416 416
 			return $path;
417 417
 		}
418 418
 
419 419
 		// early return path if it is a deleted user
420 420
 		$user = $this->access->userManager->get($uid);
421
-		if($user instanceof User || $user instanceof OfflineUser) {
421
+		if ($user instanceof User || $user instanceof OfflineUser) {
422 422
 			$path = $user->getHomePath() ?: false;
423 423
 		} else {
424
-			throw new NoUserException($uid . ' is not a valid user anymore');
424
+			throw new NoUserException($uid.' is not a valid user anymore');
425 425
 		}
426 426
 
427 427
 		$this->access->cacheUserHome($uid, $path);
@@ -438,12 +438,12 @@  discard block
 block discarded – undo
438 438
 			return $this->userPluginManager->getDisplayName($uid);
439 439
 		}
440 440
 
441
-		if(!$this->userExists($uid)) {
441
+		if (!$this->userExists($uid)) {
442 442
 			return false;
443 443
 		}
444 444
 
445 445
 		$cacheKey = 'getDisplayName'.$uid;
446
-		if(!is_null($displayName = $this->access->connection->getFromCache($cacheKey))) {
446
+		if (!is_null($displayName = $this->access->connection->getFromCache($cacheKey))) {
447 447
 			return $displayName;
448 448
 		}
449 449
 
@@ -460,10 +460,10 @@  discard block
 block discarded – undo
460 460
 			$this->access->username2dn($uid),
461 461
 			$this->access->connection->ldapUserDisplayName);
462 462
 
463
-		if($displayName && (count($displayName) > 0)) {
463
+		if ($displayName && (count($displayName) > 0)) {
464 464
 			$displayName = $displayName[0];
465 465
 
466
-			if (is_array($displayName2)){
466
+			if (is_array($displayName2)) {
467 467
 				$displayName2 = count($displayName2) > 0 ? $displayName2[0] : '';
468 468
 			}
469 469
 
@@ -507,7 +507,7 @@  discard block
 block discarded – undo
507 507
 	 */
508 508
 	public function getDisplayNames($search = '', $limit = null, $offset = null) {
509 509
 		$cacheKey = 'getDisplayNames-'.$search.'-'.$limit.'-'.$offset;
510
-		if(!is_null($displayNames = $this->access->connection->getFromCache($cacheKey))) {
510
+		if (!is_null($displayNames = $this->access->connection->getFromCache($cacheKey))) {
511 511
 			return $displayNames;
512 512
 		}
513 513
 
@@ -529,12 +529,12 @@  discard block
 block discarded – undo
529 529
 	* compared with \OC\User\Backend::CREATE_USER etc.
530 530
 	*/
531 531
 	public function implementsActions($actions) {
532
-		return (bool)((Backend::CHECK_PASSWORD
532
+		return (bool) ((Backend::CHECK_PASSWORD
533 533
 			| Backend::GET_HOME
534 534
 			| Backend::GET_DISPLAYNAME
535 535
 			| (($this->access->connection->ldapUserAvatarRule !== 'none') ? Backend::PROVIDE_AVATAR : 0)
536 536
 			| Backend::COUNT_USERS
537
-			| (((int)$this->access->connection->turnOnPasswordChange === 1)? Backend::SET_PASSWORD :0)
537
+			| (((int) $this->access->connection->turnOnPasswordChange === 1) ? Backend::SET_PASSWORD : 0)
538 538
 			| $this->userPluginManager->getImplementedActions())
539 539
 			& $actions);
540 540
 	}
@@ -558,7 +558,7 @@  discard block
 block discarded – undo
558 558
 
559 559
 		$filter = $this->access->getFilterForUserCount();
560 560
 		$cacheKey = 'countUsers-'.$filter;
561
-		if(!is_null($entries = $this->access->connection->getFromCache($cacheKey))) {
561
+		if (!is_null($entries = $this->access->connection->getFromCache($cacheKey))) {
562 562
 			return $entries;
563 563
 		}
564 564
 		$entries = $this->access->countUsers($filter);
@@ -570,7 +570,7 @@  discard block
 block discarded – undo
570 570
 	 * Backend name to be shown in user management
571 571
 	 * @return string the name of the backend to be shown
572 572
 	 */
573
-	public function getBackendName(){
573
+	public function getBackendName() {
574 574
 		return 'LDAP';
575 575
 	}
576 576
 	
@@ -608,7 +608,7 @@  discard block
 block discarded – undo
608 608
 				if (is_string($dn)) {
609 609
 					// the NC user creation work flow requires a know user id up front
610 610
 					$uuid = $this->access->getUUID($dn, true);
611
-					if(is_string($uuid)) {
611
+					if (is_string($uuid)) {
612 612
 						$this->access->mapAndAnnounceIfApplicable(
613 613
 							$this->access->getUserMapper(),
614 614
 							$dn,
Please login to merge, or discard this patch.
apps/user_ldap/lib/User_Proxy.php 2 patches
Indentation   +307 added lines, -307 removed lines patch added patch discarded remove patch
@@ -37,335 +37,335 @@
 block discarded – undo
37 37
 use OCP\Notification\IManager as INotificationManager;
38 38
 
39 39
 class User_Proxy extends Proxy implements \OCP\IUserBackend, \OCP\UserInterface, IUserLDAP {
40
-	private $backends = [];
41
-	/** @var User_LDAP */
42
-	private $refBackend = null;
40
+    private $backends = [];
41
+    /** @var User_LDAP */
42
+    private $refBackend = null;
43 43
 
44
-	/**
45
-	 * Constructor
46
-	 *
47
-	 * @param array $serverConfigPrefixes array containing the config Prefixes
48
-	 * @param ILDAPWrapper $ldap
49
-	 * @param IConfig $ocConfig
50
-	 * @param INotificationManager $notificationManager
51
-	 * @param IUserSession $userSession
52
-	 */
53
-	public function __construct(
54
-		array $serverConfigPrefixes,
55
-		ILDAPWrapper $ldap,
56
-		IConfig $ocConfig,
57
-		INotificationManager $notificationManager,
58
-		IUserSession $userSession,
59
-		UserPluginManager $userPluginManager
60
-	) {
61
-		parent::__construct($ldap);
62
-		foreach($serverConfigPrefixes as $configPrefix) {
63
-			$this->backends[$configPrefix] =
64
-				new User_LDAP($this->getAccess($configPrefix), $ocConfig, $notificationManager, $userSession, $userPluginManager);
44
+    /**
45
+     * Constructor
46
+     *
47
+     * @param array $serverConfigPrefixes array containing the config Prefixes
48
+     * @param ILDAPWrapper $ldap
49
+     * @param IConfig $ocConfig
50
+     * @param INotificationManager $notificationManager
51
+     * @param IUserSession $userSession
52
+     */
53
+    public function __construct(
54
+        array $serverConfigPrefixes,
55
+        ILDAPWrapper $ldap,
56
+        IConfig $ocConfig,
57
+        INotificationManager $notificationManager,
58
+        IUserSession $userSession,
59
+        UserPluginManager $userPluginManager
60
+    ) {
61
+        parent::__construct($ldap);
62
+        foreach($serverConfigPrefixes as $configPrefix) {
63
+            $this->backends[$configPrefix] =
64
+                new User_LDAP($this->getAccess($configPrefix), $ocConfig, $notificationManager, $userSession, $userPluginManager);
65 65
 
66
-			if(is_null($this->refBackend)) {
67
-				$this->refBackend = &$this->backends[$configPrefix];
68
-			}
69
-		}
70
-	}
66
+            if(is_null($this->refBackend)) {
67
+                $this->refBackend = &$this->backends[$configPrefix];
68
+            }
69
+        }
70
+    }
71 71
 
72
-	/**
73
-	 * Tries the backends one after the other until a positive result is returned from the specified method
74
-	 * @param string $uid the uid connected to the request
75
-	 * @param string $method the method of the user backend that shall be called
76
-	 * @param array $parameters an array of parameters to be passed
77
-	 * @return mixed the result of the method or false
78
-	 */
79
-	protected function walkBackends($uid, $method, $parameters) {
80
-		$cacheKey = $this->getUserCacheKey($uid);
81
-		foreach($this->backends as $configPrefix => $backend) {
82
-			$instance = $backend;
83
-			if(!method_exists($instance, $method)
84
-				&& method_exists($this->getAccess($configPrefix), $method)) {
85
-				$instance = $this->getAccess($configPrefix);
86
-			}
87
-			if($result = call_user_func_array([$instance, $method], $parameters)) {
88
-				$this->writeToCache($cacheKey, $configPrefix);
89
-				return $result;
90
-			}
91
-		}
92
-		return false;
93
-	}
72
+    /**
73
+     * Tries the backends one after the other until a positive result is returned from the specified method
74
+     * @param string $uid the uid connected to the request
75
+     * @param string $method the method of the user backend that shall be called
76
+     * @param array $parameters an array of parameters to be passed
77
+     * @return mixed the result of the method or false
78
+     */
79
+    protected function walkBackends($uid, $method, $parameters) {
80
+        $cacheKey = $this->getUserCacheKey($uid);
81
+        foreach($this->backends as $configPrefix => $backend) {
82
+            $instance = $backend;
83
+            if(!method_exists($instance, $method)
84
+                && method_exists($this->getAccess($configPrefix), $method)) {
85
+                $instance = $this->getAccess($configPrefix);
86
+            }
87
+            if($result = call_user_func_array([$instance, $method], $parameters)) {
88
+                $this->writeToCache($cacheKey, $configPrefix);
89
+                return $result;
90
+            }
91
+        }
92
+        return false;
93
+    }
94 94
 
95
-	/**
96
-	 * Asks the backend connected to the server that supposely takes care of the uid from the request.
97
-	 * @param string $uid the uid connected to the request
98
-	 * @param string $method the method of the user backend that shall be called
99
-	 * @param array $parameters an array of parameters to be passed
100
-	 * @param mixed $passOnWhen the result matches this variable
101
-	 * @return mixed the result of the method or false
102
-	 */
103
-	protected function callOnLastSeenOn($uid, $method, $parameters, $passOnWhen) {
104
-		$cacheKey = $this->getUserCacheKey($uid);
105
-		$prefix = $this->getFromCache($cacheKey);
106
-		//in case the uid has been found in the past, try this stored connection first
107
-		if(!is_null($prefix)) {
108
-			if(isset($this->backends[$prefix])) {
109
-				$instance = $this->backends[$prefix];
110
-				if(!method_exists($instance, $method)
111
-					&& method_exists($this->getAccess($prefix), $method)) {
112
-					$instance = $this->getAccess($prefix);
113
-				}
114
-				$result = call_user_func_array([$instance, $method], $parameters);
115
-				if($result === $passOnWhen) {
116
-					//not found here, reset cache to null if user vanished
117
-					//because sometimes methods return false with a reason
118
-					$userExists = call_user_func_array(
119
-						[$this->backends[$prefix], 'userExistsOnLDAP'],
120
-						[$uid]
121
-					);
122
-					if(!$userExists) {
123
-						$this->writeToCache($cacheKey, null);
124
-					}
125
-				}
126
-				return $result;
127
-			}
128
-		}
129
-		return false;
130
-	}
95
+    /**
96
+     * Asks the backend connected to the server that supposely takes care of the uid from the request.
97
+     * @param string $uid the uid connected to the request
98
+     * @param string $method the method of the user backend that shall be called
99
+     * @param array $parameters an array of parameters to be passed
100
+     * @param mixed $passOnWhen the result matches this variable
101
+     * @return mixed the result of the method or false
102
+     */
103
+    protected function callOnLastSeenOn($uid, $method, $parameters, $passOnWhen) {
104
+        $cacheKey = $this->getUserCacheKey($uid);
105
+        $prefix = $this->getFromCache($cacheKey);
106
+        //in case the uid has been found in the past, try this stored connection first
107
+        if(!is_null($prefix)) {
108
+            if(isset($this->backends[$prefix])) {
109
+                $instance = $this->backends[$prefix];
110
+                if(!method_exists($instance, $method)
111
+                    && method_exists($this->getAccess($prefix), $method)) {
112
+                    $instance = $this->getAccess($prefix);
113
+                }
114
+                $result = call_user_func_array([$instance, $method], $parameters);
115
+                if($result === $passOnWhen) {
116
+                    //not found here, reset cache to null if user vanished
117
+                    //because sometimes methods return false with a reason
118
+                    $userExists = call_user_func_array(
119
+                        [$this->backends[$prefix], 'userExistsOnLDAP'],
120
+                        [$uid]
121
+                    );
122
+                    if(!$userExists) {
123
+                        $this->writeToCache($cacheKey, null);
124
+                    }
125
+                }
126
+                return $result;
127
+            }
128
+        }
129
+        return false;
130
+    }
131 131
 
132
-	/**
133
-	 * Check if backend implements actions
134
-	 * @param int $actions bitwise-or'ed actions
135
-	 * @return boolean
136
-	 *
137
-	 * Returns the supported actions as int to be
138
-	 * compared with \OC\User\Backend::CREATE_USER etc.
139
-	 */
140
-	public function implementsActions($actions) {
141
-		//it's the same across all our user backends obviously
142
-		return $this->refBackend->implementsActions($actions);
143
-	}
132
+    /**
133
+     * Check if backend implements actions
134
+     * @param int $actions bitwise-or'ed actions
135
+     * @return boolean
136
+     *
137
+     * Returns the supported actions as int to be
138
+     * compared with \OC\User\Backend::CREATE_USER etc.
139
+     */
140
+    public function implementsActions($actions) {
141
+        //it's the same across all our user backends obviously
142
+        return $this->refBackend->implementsActions($actions);
143
+    }
144 144
 
145
-	/**
146
-	 * Backend name to be shown in user management
147
-	 * @return string the name of the backend to be shown
148
-	 */
149
-	public function getBackendName() {
150
-		return $this->refBackend->getBackendName();
151
-	}
145
+    /**
146
+     * Backend name to be shown in user management
147
+     * @return string the name of the backend to be shown
148
+     */
149
+    public function getBackendName() {
150
+        return $this->refBackend->getBackendName();
151
+    }
152 152
 
153
-	/**
154
-	 * Get a list of all users
155
-	 *
156
-	 * @param string $search
157
-	 * @param null|int $limit
158
-	 * @param null|int $offset
159
-	 * @return string[] an array of all uids
160
-	 */
161
-	public function getUsers($search = '', $limit = 10, $offset = 0) {
162
-		//we do it just as the /OC_User implementation: do not play around with limit and offset but ask all backends
163
-		$users = [];
164
-		foreach($this->backends as $backend) {
165
-			$backendUsers = $backend->getUsers($search, $limit, $offset);
166
-			if (is_array($backendUsers)) {
167
-				$users = array_merge($users, $backendUsers);
168
-			}
169
-		}
170
-		return $users;
171
-	}
153
+    /**
154
+     * Get a list of all users
155
+     *
156
+     * @param string $search
157
+     * @param null|int $limit
158
+     * @param null|int $offset
159
+     * @return string[] an array of all uids
160
+     */
161
+    public function getUsers($search = '', $limit = 10, $offset = 0) {
162
+        //we do it just as the /OC_User implementation: do not play around with limit and offset but ask all backends
163
+        $users = [];
164
+        foreach($this->backends as $backend) {
165
+            $backendUsers = $backend->getUsers($search, $limit, $offset);
166
+            if (is_array($backendUsers)) {
167
+                $users = array_merge($users, $backendUsers);
168
+            }
169
+        }
170
+        return $users;
171
+    }
172 172
 
173
-	/**
174
-	 * check if a user exists
175
-	 * @param string $uid the username
176
-	 * @return boolean
177
-	 */
178
-	public function userExists($uid) {
179
-		$existsOnLDAP = false;
180
-		$existsLocally = $this->handleRequest($uid, 'userExists', [$uid]);
181
-		if($existsLocally) {
182
-			$existsOnLDAP = $this->userExistsOnLDAP($uid);
183
-		}
184
-		if($existsLocally && !$existsOnLDAP) {
185
-			try {
186
-				$user = $this->getLDAPAccess($uid)->userManager->get($uid);
187
-				if($user instanceof User) {
188
-					$user->markUser();
189
-				}
190
-			} catch (\Exception $e) {
191
-				// ignore
192
-			}
193
-		}
194
-		return $existsLocally;
195
-	}
173
+    /**
174
+     * check if a user exists
175
+     * @param string $uid the username
176
+     * @return boolean
177
+     */
178
+    public function userExists($uid) {
179
+        $existsOnLDAP = false;
180
+        $existsLocally = $this->handleRequest($uid, 'userExists', [$uid]);
181
+        if($existsLocally) {
182
+            $existsOnLDAP = $this->userExistsOnLDAP($uid);
183
+        }
184
+        if($existsLocally && !$existsOnLDAP) {
185
+            try {
186
+                $user = $this->getLDAPAccess($uid)->userManager->get($uid);
187
+                if($user instanceof User) {
188
+                    $user->markUser();
189
+                }
190
+            } catch (\Exception $e) {
191
+                // ignore
192
+            }
193
+        }
194
+        return $existsLocally;
195
+    }
196 196
 
197
-	/**
198
-	 * check if a user exists on LDAP
199
-	 * @param string|\OCA\User_LDAP\User\User $user either the Nextcloud user
200
-	 * name or an instance of that user
201
-	 * @return boolean
202
-	 */
203
-	public function userExistsOnLDAP($user) {
204
-		$id = ($user instanceof User) ? $user->getUsername() : $user;
205
-		return $this->handleRequest($id, 'userExistsOnLDAP', [$user]);
206
-	}
197
+    /**
198
+     * check if a user exists on LDAP
199
+     * @param string|\OCA\User_LDAP\User\User $user either the Nextcloud user
200
+     * name or an instance of that user
201
+     * @return boolean
202
+     */
203
+    public function userExistsOnLDAP($user) {
204
+        $id = ($user instanceof User) ? $user->getUsername() : $user;
205
+        return $this->handleRequest($id, 'userExistsOnLDAP', [$user]);
206
+    }
207 207
 
208
-	/**
209
-	 * Check if the password is correct
210
-	 * @param string $uid The username
211
-	 * @param string $password The password
212
-	 * @return bool
213
-	 *
214
-	 * Check if the password is correct without logging in the user
215
-	 */
216
-	public function checkPassword($uid, $password) {
217
-		return $this->handleRequest($uid, 'checkPassword', [$uid, $password]);
218
-	}
208
+    /**
209
+     * Check if the password is correct
210
+     * @param string $uid The username
211
+     * @param string $password The password
212
+     * @return bool
213
+     *
214
+     * Check if the password is correct without logging in the user
215
+     */
216
+    public function checkPassword($uid, $password) {
217
+        return $this->handleRequest($uid, 'checkPassword', [$uid, $password]);
218
+    }
219 219
 
220
-	/**
221
-	 * returns the username for the given login name, if available
222
-	 *
223
-	 * @param string $loginName
224
-	 * @return string|false
225
-	 */
226
-	public function loginName2UserName($loginName) {
227
-		$id = 'LOGINNAME,' . $loginName;
228
-		return $this->handleRequest($id, 'loginName2UserName', [$loginName]);
229
-	}
220
+    /**
221
+     * returns the username for the given login name, if available
222
+     *
223
+     * @param string $loginName
224
+     * @return string|false
225
+     */
226
+    public function loginName2UserName($loginName) {
227
+        $id = 'LOGINNAME,' . $loginName;
228
+        return $this->handleRequest($id, 'loginName2UserName', [$loginName]);
229
+    }
230 230
 	
231
-	/**
232
-	 * returns the username for the given LDAP DN, if available
233
-	 *
234
-	 * @param string $dn
235
-	 * @return string|false with the username
236
-	 */
237
-	public function dn2UserName($dn) {
238
-		$id = 'DN,' . $dn;
239
-		return $this->handleRequest($id, 'dn2UserName', [$dn]);
240
-	}
231
+    /**
232
+     * returns the username for the given LDAP DN, if available
233
+     *
234
+     * @param string $dn
235
+     * @return string|false with the username
236
+     */
237
+    public function dn2UserName($dn) {
238
+        $id = 'DN,' . $dn;
239
+        return $this->handleRequest($id, 'dn2UserName', [$dn]);
240
+    }
241 241
 
242
-	/**
243
-	 * get the user's home directory
244
-	 * @param string $uid the username
245
-	 * @return boolean
246
-	 */
247
-	public function getHome($uid) {
248
-		return $this->handleRequest($uid, 'getHome', [$uid]);
249
-	}
242
+    /**
243
+     * get the user's home directory
244
+     * @param string $uid the username
245
+     * @return boolean
246
+     */
247
+    public function getHome($uid) {
248
+        return $this->handleRequest($uid, 'getHome', [$uid]);
249
+    }
250 250
 
251
-	/**
252
-	 * get display name of the user
253
-	 * @param string $uid user ID of the user
254
-	 * @return string display name
255
-	 */
256
-	public function getDisplayName($uid) {
257
-		return $this->handleRequest($uid, 'getDisplayName', [$uid]);
258
-	}
251
+    /**
252
+     * get display name of the user
253
+     * @param string $uid user ID of the user
254
+     * @return string display name
255
+     */
256
+    public function getDisplayName($uid) {
257
+        return $this->handleRequest($uid, 'getDisplayName', [$uid]);
258
+    }
259 259
 
260
-	/**
261
-	 * set display name of the user
262
-	 *
263
-	 * @param string $uid user ID of the user
264
-	 * @param string $displayName new display name
265
-	 * @return string display name
266
-	 */
267
-	public function setDisplayName($uid, $displayName) {
268
-		return $this->handleRequest($uid, 'setDisplayName', [$uid, $displayName]);
269
-	}
260
+    /**
261
+     * set display name of the user
262
+     *
263
+     * @param string $uid user ID of the user
264
+     * @param string $displayName new display name
265
+     * @return string display name
266
+     */
267
+    public function setDisplayName($uid, $displayName) {
268
+        return $this->handleRequest($uid, 'setDisplayName', [$uid, $displayName]);
269
+    }
270 270
 
271
-	/**
272
-	 * checks whether the user is allowed to change his avatar in Nextcloud
273
-	 * @param string $uid the Nextcloud user name
274
-	 * @return boolean either the user can or cannot
275
-	 */
276
-	public function canChangeAvatar($uid) {
277
-		return $this->handleRequest($uid, 'canChangeAvatar', [$uid], true);
278
-	}
271
+    /**
272
+     * checks whether the user is allowed to change his avatar in Nextcloud
273
+     * @param string $uid the Nextcloud user name
274
+     * @return boolean either the user can or cannot
275
+     */
276
+    public function canChangeAvatar($uid) {
277
+        return $this->handleRequest($uid, 'canChangeAvatar', [$uid], true);
278
+    }
279 279
 
280
-	/**
281
-	 * Get a list of all display names and user ids.
282
-	 * @param string $search
283
-	 * @param string|null $limit
284
-	 * @param string|null $offset
285
-	 * @return array an array of all displayNames (value) and the corresponding uids (key)
286
-	 */
287
-	public function getDisplayNames($search = '', $limit = null, $offset = null) {
288
-		//we do it just as the /OC_User implementation: do not play around with limit and offset but ask all backends
289
-		$users = [];
290
-		foreach($this->backends as $backend) {
291
-			$backendUsers = $backend->getDisplayNames($search, $limit, $offset);
292
-			if (is_array($backendUsers)) {
293
-				$users = $users + $backendUsers;
294
-			}
295
-		}
296
-		return $users;
297
-	}
280
+    /**
281
+     * Get a list of all display names and user ids.
282
+     * @param string $search
283
+     * @param string|null $limit
284
+     * @param string|null $offset
285
+     * @return array an array of all displayNames (value) and the corresponding uids (key)
286
+     */
287
+    public function getDisplayNames($search = '', $limit = null, $offset = null) {
288
+        //we do it just as the /OC_User implementation: do not play around with limit and offset but ask all backends
289
+        $users = [];
290
+        foreach($this->backends as $backend) {
291
+            $backendUsers = $backend->getDisplayNames($search, $limit, $offset);
292
+            if (is_array($backendUsers)) {
293
+                $users = $users + $backendUsers;
294
+            }
295
+        }
296
+        return $users;
297
+    }
298 298
 
299
-	/**
300
-	 * delete a user
301
-	 * @param string $uid The username of the user to delete
302
-	 * @return bool
303
-	 *
304
-	 * Deletes a user
305
-	 */
306
-	public function deleteUser($uid) {
307
-		return $this->handleRequest($uid, 'deleteUser', [$uid]);
308
-	}
299
+    /**
300
+     * delete a user
301
+     * @param string $uid The username of the user to delete
302
+     * @return bool
303
+     *
304
+     * Deletes a user
305
+     */
306
+    public function deleteUser($uid) {
307
+        return $this->handleRequest($uid, 'deleteUser', [$uid]);
308
+    }
309 309
 	
310
-	/**
311
-	 * Set password
312
-	 * @param string $uid The username
313
-	 * @param string $password The new password
314
-	 * @return bool
315
-	 *
316
-	 */
317
-	public function setPassword($uid, $password) {
318
-		return $this->handleRequest($uid, 'setPassword', [$uid, $password]);
319
-	}
310
+    /**
311
+     * Set password
312
+     * @param string $uid The username
313
+     * @param string $password The new password
314
+     * @return bool
315
+     *
316
+     */
317
+    public function setPassword($uid, $password) {
318
+        return $this->handleRequest($uid, 'setPassword', [$uid, $password]);
319
+    }
320 320
 
321
-	/**
322
-	 * @return bool
323
-	 */
324
-	public function hasUserListings() {
325
-		return $this->refBackend->hasUserListings();
326
-	}
321
+    /**
322
+     * @return bool
323
+     */
324
+    public function hasUserListings() {
325
+        return $this->refBackend->hasUserListings();
326
+    }
327 327
 
328
-	/**
329
-	 * Count the number of users
330
-	 * @return int|bool
331
-	 */
332
-	public function countUsers() {
333
-		$users = false;
334
-		foreach($this->backends as $backend) {
335
-			$backendUsers = $backend->countUsers();
336
-			if ($backendUsers !== false) {
337
-				$users += $backendUsers;
338
-			}
339
-		}
340
-		return $users;
341
-	}
328
+    /**
329
+     * Count the number of users
330
+     * @return int|bool
331
+     */
332
+    public function countUsers() {
333
+        $users = false;
334
+        foreach($this->backends as $backend) {
335
+            $backendUsers = $backend->countUsers();
336
+            if ($backendUsers !== false) {
337
+                $users += $backendUsers;
338
+            }
339
+        }
340
+        return $users;
341
+    }
342 342
 
343
-	/**
344
-	 * Return access for LDAP interaction.
345
-	 * @param string $uid
346
-	 * @return Access instance of Access for LDAP interaction
347
-	 */
348
-	public function getLDAPAccess($uid) {
349
-		return $this->handleRequest($uid, 'getLDAPAccess', [$uid]);
350
-	}
343
+    /**
344
+     * Return access for LDAP interaction.
345
+     * @param string $uid
346
+     * @return Access instance of Access for LDAP interaction
347
+     */
348
+    public function getLDAPAccess($uid) {
349
+        return $this->handleRequest($uid, 'getLDAPAccess', [$uid]);
350
+    }
351 351
 	
352
-	/**
353
-	 * Return a new LDAP connection for the specified user.
354
-	 * The connection needs to be closed manually.
355
-	 * @param string $uid
356
-	 * @return resource of the LDAP connection
357
-	 */
358
-	public function getNewLDAPConnection($uid) {
359
-		return $this->handleRequest($uid, 'getNewLDAPConnection', [$uid]);
360
-	}
352
+    /**
353
+     * Return a new LDAP connection for the specified user.
354
+     * The connection needs to be closed manually.
355
+     * @param string $uid
356
+     * @return resource of the LDAP connection
357
+     */
358
+    public function getNewLDAPConnection($uid) {
359
+        return $this->handleRequest($uid, 'getNewLDAPConnection', [$uid]);
360
+    }
361 361
 
362
-	/**
363
-	 * Creates a new user in LDAP
364
-	 * @param $username
365
-	 * @param $password
366
-	 * @return bool
367
-	 */
368
-	public function createUser($username, $password) {
369
-		return $this->handleRequest($username, 'createUser', [$username,$password]);
370
-	}
362
+    /**
363
+     * Creates a new user in LDAP
364
+     * @param $username
365
+     * @param $password
366
+     * @return bool
367
+     */
368
+    public function createUser($username, $password) {
369
+        return $this->handleRequest($username, 'createUser', [$username,$password]);
370
+    }
371 371
 }
Please login to merge, or discard this patch.
Spacing   +19 added lines, -19 removed lines patch added patch discarded remove patch
@@ -59,11 +59,11 @@  discard block
 block discarded – undo
59 59
 		UserPluginManager $userPluginManager
60 60
 	) {
61 61
 		parent::__construct($ldap);
62
-		foreach($serverConfigPrefixes as $configPrefix) {
62
+		foreach ($serverConfigPrefixes as $configPrefix) {
63 63
 			$this->backends[$configPrefix] =
64 64
 				new User_LDAP($this->getAccess($configPrefix), $ocConfig, $notificationManager, $userSession, $userPluginManager);
65 65
 
66
-			if(is_null($this->refBackend)) {
66
+			if (is_null($this->refBackend)) {
67 67
 				$this->refBackend = &$this->backends[$configPrefix];
68 68
 			}
69 69
 		}
@@ -78,13 +78,13 @@  discard block
 block discarded – undo
78 78
 	 */
79 79
 	protected function walkBackends($uid, $method, $parameters) {
80 80
 		$cacheKey = $this->getUserCacheKey($uid);
81
-		foreach($this->backends as $configPrefix => $backend) {
81
+		foreach ($this->backends as $configPrefix => $backend) {
82 82
 			$instance = $backend;
83
-			if(!method_exists($instance, $method)
83
+			if (!method_exists($instance, $method)
84 84
 				&& method_exists($this->getAccess($configPrefix), $method)) {
85 85
 				$instance = $this->getAccess($configPrefix);
86 86
 			}
87
-			if($result = call_user_func_array([$instance, $method], $parameters)) {
87
+			if ($result = call_user_func_array([$instance, $method], $parameters)) {
88 88
 				$this->writeToCache($cacheKey, $configPrefix);
89 89
 				return $result;
90 90
 			}
@@ -104,22 +104,22 @@  discard block
 block discarded – undo
104 104
 		$cacheKey = $this->getUserCacheKey($uid);
105 105
 		$prefix = $this->getFromCache($cacheKey);
106 106
 		//in case the uid has been found in the past, try this stored connection first
107
-		if(!is_null($prefix)) {
108
-			if(isset($this->backends[$prefix])) {
107
+		if (!is_null($prefix)) {
108
+			if (isset($this->backends[$prefix])) {
109 109
 				$instance = $this->backends[$prefix];
110
-				if(!method_exists($instance, $method)
110
+				if (!method_exists($instance, $method)
111 111
 					&& method_exists($this->getAccess($prefix), $method)) {
112 112
 					$instance = $this->getAccess($prefix);
113 113
 				}
114 114
 				$result = call_user_func_array([$instance, $method], $parameters);
115
-				if($result === $passOnWhen) {
115
+				if ($result === $passOnWhen) {
116 116
 					//not found here, reset cache to null if user vanished
117 117
 					//because sometimes methods return false with a reason
118 118
 					$userExists = call_user_func_array(
119 119
 						[$this->backends[$prefix], 'userExistsOnLDAP'],
120 120
 						[$uid]
121 121
 					);
122
-					if(!$userExists) {
122
+					if (!$userExists) {
123 123
 						$this->writeToCache($cacheKey, null);
124 124
 					}
125 125
 				}
@@ -161,7 +161,7 @@  discard block
 block discarded – undo
161 161
 	public function getUsers($search = '', $limit = 10, $offset = 0) {
162 162
 		//we do it just as the /OC_User implementation: do not play around with limit and offset but ask all backends
163 163
 		$users = [];
164
-		foreach($this->backends as $backend) {
164
+		foreach ($this->backends as $backend) {
165 165
 			$backendUsers = $backend->getUsers($search, $limit, $offset);
166 166
 			if (is_array($backendUsers)) {
167 167
 				$users = array_merge($users, $backendUsers);
@@ -178,13 +178,13 @@  discard block
 block discarded – undo
178 178
 	public function userExists($uid) {
179 179
 		$existsOnLDAP = false;
180 180
 		$existsLocally = $this->handleRequest($uid, 'userExists', [$uid]);
181
-		if($existsLocally) {
181
+		if ($existsLocally) {
182 182
 			$existsOnLDAP = $this->userExistsOnLDAP($uid);
183 183
 		}
184
-		if($existsLocally && !$existsOnLDAP) {
184
+		if ($existsLocally && !$existsOnLDAP) {
185 185
 			try {
186 186
 				$user = $this->getLDAPAccess($uid)->userManager->get($uid);
187
-				if($user instanceof User) {
187
+				if ($user instanceof User) {
188 188
 					$user->markUser();
189 189
 				}
190 190
 			} catch (\Exception $e) {
@@ -224,7 +224,7 @@  discard block
 block discarded – undo
224 224
 	 * @return string|false
225 225
 	 */
226 226
 	public function loginName2UserName($loginName) {
227
-		$id = 'LOGINNAME,' . $loginName;
227
+		$id = 'LOGINNAME,'.$loginName;
228 228
 		return $this->handleRequest($id, 'loginName2UserName', [$loginName]);
229 229
 	}
230 230
 	
@@ -235,7 +235,7 @@  discard block
 block discarded – undo
235 235
 	 * @return string|false with the username
236 236
 	 */
237 237
 	public function dn2UserName($dn) {
238
-		$id = 'DN,' . $dn;
238
+		$id = 'DN,'.$dn;
239 239
 		return $this->handleRequest($id, 'dn2UserName', [$dn]);
240 240
 	}
241 241
 
@@ -287,7 +287,7 @@  discard block
 block discarded – undo
287 287
 	public function getDisplayNames($search = '', $limit = null, $offset = null) {
288 288
 		//we do it just as the /OC_User implementation: do not play around with limit and offset but ask all backends
289 289
 		$users = [];
290
-		foreach($this->backends as $backend) {
290
+		foreach ($this->backends as $backend) {
291 291
 			$backendUsers = $backend->getDisplayNames($search, $limit, $offset);
292 292
 			if (is_array($backendUsers)) {
293 293
 				$users = $users + $backendUsers;
@@ -331,7 +331,7 @@  discard block
 block discarded – undo
331 331
 	 */
332 332
 	public function countUsers() {
333 333
 		$users = false;
334
-		foreach($this->backends as $backend) {
334
+		foreach ($this->backends as $backend) {
335 335
 			$backendUsers = $backend->countUsers();
336 336
 			if ($backendUsers !== false) {
337 337
 				$users += $backendUsers;
@@ -366,6 +366,6 @@  discard block
 block discarded – undo
366 366
 	 * @return bool
367 367
 	 */
368 368
 	public function createUser($username, $password) {
369
-		return $this->handleRequest($username, 'createUser', [$username,$password]);
369
+		return $this->handleRequest($username, 'createUser', [$username, $password]);
370 370
 	}
371 371
 }
Please login to merge, or discard this patch.
apps/files_trashbin/lib/Trashbin.php 2 patches
Indentation   +962 added lines, -962 removed lines patch added patch discarded remove patch
@@ -55,966 +55,966 @@
 block discarded – undo
55 55
 
56 56
 class Trashbin {
57 57
 
58
-	// unit: percentage; 50% of available disk space/quota
59
-	const DEFAULTMAXSIZE = 50;
60
-
61
-	/**
62
-	 * Whether versions have already be rescanned during this PHP request
63
-	 *
64
-	 * @var bool
65
-	 */
66
-	private static $scannedVersions = false;
67
-
68
-	/**
69
-	 * Ensure we don't need to scan the file during the move to trash
70
-	 * by triggering the scan in the pre-hook
71
-	 *
72
-	 * @param array $params
73
-	 */
74
-	public static function ensureFileScannedHook($params) {
75
-		try {
76
-			self::getUidAndFilename($params['path']);
77
-		} catch (NotFoundException $e) {
78
-			// nothing to scan for non existing files
79
-		}
80
-	}
81
-
82
-	/**
83
-	 * get the UID of the owner of the file and the path to the file relative to
84
-	 * owners files folder
85
-	 *
86
-	 * @param string $filename
87
-	 * @return array
88
-	 * @throws \OC\User\NoUserException
89
-	 */
90
-	public static function getUidAndFilename($filename) {
91
-		$uid = Filesystem::getOwner($filename);
92
-		$userManager = \OC::$server->getUserManager();
93
-		// if the user with the UID doesn't exists, e.g. because the UID points
94
-		// to a remote user with a federated cloud ID we use the current logged-in
95
-		// user. We need a valid local user to move the file to the right trash bin
96
-		if (!$userManager->userExists($uid)) {
97
-			$uid = User::getUser();
98
-		}
99
-		if (!$uid) {
100
-			// no owner, usually because of share link from ext storage
101
-			return [null, null];
102
-		}
103
-		Filesystem::initMountPoints($uid);
104
-		if ($uid !== User::getUser()) {
105
-			$info = Filesystem::getFileInfo($filename);
106
-			$ownerView = new View('/' . $uid . '/files');
107
-			try {
108
-				$filename = $ownerView->getPath($info['fileid']);
109
-			} catch (NotFoundException $e) {
110
-				$filename = null;
111
-			}
112
-		}
113
-		return [$uid, $filename];
114
-	}
115
-
116
-	/**
117
-	 * get original location of files for user
118
-	 *
119
-	 * @param string $user
120
-	 * @return array (filename => array (timestamp => original location))
121
-	 */
122
-	public static function getLocations($user) {
123
-		$query = \OC_DB::prepare('SELECT `id`, `timestamp`, `location`'
124
-			. ' FROM `*PREFIX*files_trash` WHERE `user`=?');
125
-		$result = $query->execute([$user]);
126
-		$array = [];
127
-		while ($row = $result->fetchRow()) {
128
-			if (isset($array[$row['id']])) {
129
-				$array[$row['id']][$row['timestamp']] = $row['location'];
130
-			} else {
131
-				$array[$row['id']] = [$row['timestamp'] => $row['location']];
132
-			}
133
-		}
134
-		return $array;
135
-	}
136
-
137
-	/**
138
-	 * get original location of file
139
-	 *
140
-	 * @param string $user
141
-	 * @param string $filename
142
-	 * @param string $timestamp
143
-	 * @return string original location
144
-	 */
145
-	public static function getLocation($user, $filename, $timestamp) {
146
-		$query = \OC_DB::prepare('SELECT `location` FROM `*PREFIX*files_trash`'
147
-			. ' WHERE `user`=? AND `id`=? AND `timestamp`=?');
148
-		$result = $query->execute([$user, $filename, $timestamp])->fetchAll();
149
-		if (isset($result[0]['location'])) {
150
-			return $result[0]['location'];
151
-		} else {
152
-			return false;
153
-		}
154
-	}
155
-
156
-	private static function setUpTrash($user) {
157
-		$view = new View('/' . $user);
158
-		if (!$view->is_dir('files_trashbin')) {
159
-			$view->mkdir('files_trashbin');
160
-		}
161
-		if (!$view->is_dir('files_trashbin/files')) {
162
-			$view->mkdir('files_trashbin/files');
163
-		}
164
-		if (!$view->is_dir('files_trashbin/versions')) {
165
-			$view->mkdir('files_trashbin/versions');
166
-		}
167
-		if (!$view->is_dir('files_trashbin/keys')) {
168
-			$view->mkdir('files_trashbin/keys');
169
-		}
170
-	}
171
-
172
-
173
-	/**
174
-	 * copy file to owners trash
175
-	 *
176
-	 * @param string $sourcePath
177
-	 * @param string $owner
178
-	 * @param string $targetPath
179
-	 * @param $user
180
-	 * @param integer $timestamp
181
-	 */
182
-	private static function copyFilesToUser($sourcePath, $owner, $targetPath, $user, $timestamp) {
183
-		self::setUpTrash($owner);
184
-
185
-		$targetFilename = basename($targetPath);
186
-		$targetLocation = dirname($targetPath);
187
-
188
-		$sourceFilename = basename($sourcePath);
189
-
190
-		$view = new View('/');
191
-
192
-		$target = $user . '/files_trashbin/files/' . $targetFilename . '.d' . $timestamp;
193
-		$source = $owner . '/files_trashbin/files/' . $sourceFilename . '.d' . $timestamp;
194
-		$free = $view->free_space($target);
195
-		$isUnknownOrUnlimitedFreeSpace = $free < 0;
196
-		$isEnoughFreeSpaceLeft = $view->filesize($source) < $free;
197
-		if ($isUnknownOrUnlimitedFreeSpace || $isEnoughFreeSpaceLeft) {
198
-			self::copy_recursive($source, $target, $view);
199
-		}
200
-
201
-
202
-		if ($view->file_exists($target)) {
203
-			$query = \OC_DB::prepare("INSERT INTO `*PREFIX*files_trash` (`id`,`timestamp`,`location`,`user`) VALUES (?,?,?,?)");
204
-			$result = $query->execute([$targetFilename, $timestamp, $targetLocation, $user]);
205
-			if (!$result) {
206
-				\OC::$server->getLogger()->error('trash bin database couldn\'t be updated for the files owner', ['app' => 'files_trashbin']);
207
-			}
208
-		}
209
-	}
210
-
211
-
212
-	/**
213
-	 * move file to the trash bin
214
-	 *
215
-	 * @param string $file_path path to the deleted file/directory relative to the files root directory
216
-	 * @param bool $ownerOnly delete for owner only (if file gets moved out of a shared folder)
217
-	 *
218
-	 * @return bool
219
-	 */
220
-	public static function move2trash($file_path, $ownerOnly = false) {
221
-		// get the user for which the filesystem is setup
222
-		$root = Filesystem::getRoot();
223
-		list(, $user) = explode('/', $root);
224
-		list($owner, $ownerPath) = self::getUidAndFilename($file_path);
225
-
226
-		// if no owner found (ex: ext storage + share link), will use the current user's trashbin then
227
-		if (is_null($owner)) {
228
-			$owner = $user;
229
-			$ownerPath = $file_path;
230
-		}
231
-
232
-		$ownerView = new View('/' . $owner);
233
-		// file has been deleted in between
234
-		if (is_null($ownerPath) || $ownerPath === '' || !$ownerView->file_exists('/files/' . $ownerPath)) {
235
-			return true;
236
-		}
237
-
238
-		self::setUpTrash($user);
239
-		if ($owner !== $user) {
240
-			// also setup for owner
241
-			self::setUpTrash($owner);
242
-		}
243
-
244
-		$path_parts = pathinfo($ownerPath);
245
-
246
-		$filename = $path_parts['basename'];
247
-		$location = $path_parts['dirname'];
248
-		$timestamp = time();
249
-
250
-		// disable proxy to prevent recursive calls
251
-		$trashPath = '/files_trashbin/files/' . $filename . '.d' . $timestamp;
252
-
253
-		/** @var \OC\Files\Storage\Storage $trashStorage */
254
-		list($trashStorage, $trashInternalPath) = $ownerView->resolvePath($trashPath);
255
-		/** @var \OC\Files\Storage\Storage $sourceStorage */
256
-		list($sourceStorage, $sourceInternalPath) = $ownerView->resolvePath('/files/' . $ownerPath);
257
-		try {
258
-			$moveSuccessful = true;
259
-			if ($trashStorage->file_exists($trashInternalPath)) {
260
-				$trashStorage->unlink($trashInternalPath);
261
-			}
262
-			$trashStorage->moveFromStorage($sourceStorage, $sourceInternalPath, $trashInternalPath);
263
-		} catch (\OCA\Files_Trashbin\Exceptions\CopyRecursiveException $e) {
264
-			$moveSuccessful = false;
265
-			if ($trashStorage->file_exists($trashInternalPath)) {
266
-				$trashStorage->unlink($trashInternalPath);
267
-			}
268
-			\OC::$server->getLogger()->error('Couldn\'t move ' . $file_path . ' to the trash bin', ['app' => 'files_trashbin']);
269
-		}
270
-
271
-		if ($sourceStorage->file_exists($sourceInternalPath)) { // failed to delete the original file, abort
272
-			if ($sourceStorage->is_dir($sourceInternalPath)) {
273
-				$sourceStorage->rmdir($sourceInternalPath);
274
-			} else {
275
-				$sourceStorage->unlink($sourceInternalPath);
276
-			}
277
-			return false;
278
-		}
279
-
280
-		$trashStorage->getUpdater()->renameFromStorage($sourceStorage, $sourceInternalPath, $trashInternalPath);
281
-
282
-		if ($moveSuccessful) {
283
-			$query = \OC_DB::prepare("INSERT INTO `*PREFIX*files_trash` (`id`,`timestamp`,`location`,`user`) VALUES (?,?,?,?)");
284
-			$result = $query->execute([$filename, $timestamp, $location, $owner]);
285
-			if (!$result) {
286
-				\OC::$server->getLogger()->error('trash bin database couldn\'t be updated', ['app' => 'files_trashbin']);
287
-			}
288
-			\OCP\Util::emitHook('\OCA\Files_Trashbin\Trashbin', 'post_moveToTrash', ['filePath' => Filesystem::normalizePath($file_path),
289
-				'trashPath' => Filesystem::normalizePath($filename . '.d' . $timestamp)]);
290
-
291
-			self::retainVersions($filename, $owner, $ownerPath, $timestamp);
292
-
293
-			// if owner !== user we need to also add a copy to the users trash
294
-			if ($user !== $owner && $ownerOnly === false) {
295
-				self::copyFilesToUser($ownerPath, $owner, $file_path, $user, $timestamp);
296
-			}
297
-		}
298
-
299
-		self::scheduleExpire($user);
300
-
301
-		// if owner !== user we also need to update the owners trash size
302
-		if ($owner !== $user) {
303
-			self::scheduleExpire($owner);
304
-		}
305
-
306
-		return $moveSuccessful;
307
-	}
308
-
309
-	/**
310
-	 * Move file versions to trash so that they can be restored later
311
-	 *
312
-	 * @param string $filename of deleted file
313
-	 * @param string $owner owner user id
314
-	 * @param string $ownerPath path relative to the owner's home storage
315
-	 * @param integer $timestamp when the file was deleted
316
-	 */
317
-	private static function retainVersions($filename, $owner, $ownerPath, $timestamp) {
318
-		if (\OCP\App::isEnabled('files_versions') && !empty($ownerPath)) {
319
-
320
-			$user = User::getUser();
321
-			$rootView = new View('/');
322
-
323
-			if ($rootView->is_dir($owner . '/files_versions/' . $ownerPath)) {
324
-				if ($owner !== $user) {
325
-					self::copy_recursive($owner . '/files_versions/' . $ownerPath, $owner . '/files_trashbin/versions/' . basename($ownerPath) . '.d' . $timestamp, $rootView);
326
-				}
327
-				self::move($rootView, $owner . '/files_versions/' . $ownerPath, $user . '/files_trashbin/versions/' . $filename . '.d' . $timestamp);
328
-			} else if ($versions = \OCA\Files_Versions\Storage::getVersions($owner, $ownerPath)) {
329
-
330
-				foreach ($versions as $v) {
331
-					if ($owner !== $user) {
332
-						self::copy($rootView, $owner . '/files_versions' . $v['path'] . '.v' . $v['version'], $owner . '/files_trashbin/versions/' . $v['name'] . '.v' . $v['version'] . '.d' . $timestamp);
333
-					}
334
-					self::move($rootView, $owner . '/files_versions' . $v['path'] . '.v' . $v['version'], $user . '/files_trashbin/versions/' . $filename . '.v' . $v['version'] . '.d' . $timestamp);
335
-				}
336
-			}
337
-		}
338
-	}
339
-
340
-	/**
341
-	 * Move a file or folder on storage level
342
-	 *
343
-	 * @param View $view
344
-	 * @param string $source
345
-	 * @param string $target
346
-	 * @return bool
347
-	 */
348
-	private static function move(View $view, $source, $target) {
349
-		/** @var \OC\Files\Storage\Storage $sourceStorage */
350
-		list($sourceStorage, $sourceInternalPath) = $view->resolvePath($source);
351
-		/** @var \OC\Files\Storage\Storage $targetStorage */
352
-		list($targetStorage, $targetInternalPath) = $view->resolvePath($target);
353
-		/** @var \OC\Files\Storage\Storage $ownerTrashStorage */
354
-
355
-		$result = $targetStorage->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
356
-		if ($result) {
357
-			$targetStorage->getUpdater()->renameFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
358
-		}
359
-		return $result;
360
-	}
361
-
362
-	/**
363
-	 * Copy a file or folder on storage level
364
-	 *
365
-	 * @param View $view
366
-	 * @param string $source
367
-	 * @param string $target
368
-	 * @return bool
369
-	 */
370
-	private static function copy(View $view, $source, $target) {
371
-		/** @var \OC\Files\Storage\Storage $sourceStorage */
372
-		list($sourceStorage, $sourceInternalPath) = $view->resolvePath($source);
373
-		/** @var \OC\Files\Storage\Storage $targetStorage */
374
-		list($targetStorage, $targetInternalPath) = $view->resolvePath($target);
375
-		/** @var \OC\Files\Storage\Storage $ownerTrashStorage */
376
-
377
-		$result = $targetStorage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
378
-		if ($result) {
379
-			$targetStorage->getUpdater()->update($targetInternalPath);
380
-		}
381
-		return $result;
382
-	}
383
-
384
-	/**
385
-	 * Restore a file or folder from trash bin
386
-	 *
387
-	 * @param string $file path to the deleted file/folder relative to "files_trashbin/files/",
388
-	 * including the timestamp suffix ".d12345678"
389
-	 * @param string $filename name of the file/folder
390
-	 * @param int $timestamp time when the file/folder was deleted
391
-	 *
392
-	 * @return bool true on success, false otherwise
393
-	 */
394
-	public static function restore($file, $filename, $timestamp) {
395
-		$user = User::getUser();
396
-		$view = new View('/' . $user);
397
-
398
-		$location = '';
399
-		if ($timestamp) {
400
-			$location = self::getLocation($user, $filename, $timestamp);
401
-			if ($location === false) {
402
-				\OC::$server->getLogger()->error('trash bin database inconsistent! ($user: ' . $user . ' $filename: ' . $filename . ', $timestamp: ' . $timestamp . ')', ['app' => 'files_trashbin']);
403
-			} else {
404
-				// if location no longer exists, restore file in the root directory
405
-				if ($location !== '/' &&
406
-					(!$view->is_dir('files/' . $location) ||
407
-						!$view->isCreatable('files/' . $location))
408
-				) {
409
-					$location = '';
410
-				}
411
-			}
412
-		}
413
-
414
-		// we need a  extension in case a file/dir with the same name already exists
415
-		$uniqueFilename = self::getUniqueFilename($location, $filename, $view);
416
-
417
-		$source = Filesystem::normalizePath('files_trashbin/files/' . $file);
418
-		$target = Filesystem::normalizePath('files/' . $location . '/' . $uniqueFilename);
419
-		if (!$view->file_exists($source)) {
420
-			return false;
421
-		}
422
-		$mtime = $view->filemtime($source);
423
-
424
-		// restore file
425
-		if (!$view->isCreatable(dirname($target))) {
426
-			throw new NotPermittedException("Can't restore trash item because the target folder is not writable");
427
-		}
428
-		$restoreResult = $view->rename($source, $target);
429
-
430
-		// handle the restore result
431
-		if ($restoreResult) {
432
-			$fakeRoot = $view->getRoot();
433
-			$view->chroot('/' . $user . '/files');
434
-			$view->touch('/' . $location . '/' . $uniqueFilename, $mtime);
435
-			$view->chroot($fakeRoot);
436
-			\OCP\Util::emitHook('\OCA\Files_Trashbin\Trashbin', 'post_restore', ['filePath' => Filesystem::normalizePath('/' . $location . '/' . $uniqueFilename),
437
-				'trashPath' => Filesystem::normalizePath($file)]);
438
-
439
-			self::restoreVersions($view, $file, $filename, $uniqueFilename, $location, $timestamp);
440
-
441
-			if ($timestamp) {
442
-				$query = \OC_DB::prepare('DELETE FROM `*PREFIX*files_trash` WHERE `user`=? AND `id`=? AND `timestamp`=?');
443
-				$query->execute([$user, $filename, $timestamp]);
444
-			}
445
-
446
-			return true;
447
-		}
448
-
449
-		return false;
450
-	}
451
-
452
-	/**
453
-	 * restore versions from trash bin
454
-	 *
455
-	 * @param View $view file view
456
-	 * @param string $file complete path to file
457
-	 * @param string $filename name of file once it was deleted
458
-	 * @param string $uniqueFilename new file name to restore the file without overwriting existing files
459
-	 * @param string $location location if file
460
-	 * @param int $timestamp deletion time
461
-	 * @return false|null
462
-	 */
463
-	private static function restoreVersions(View $view, $file, $filename, $uniqueFilename, $location, $timestamp) {
464
-
465
-		if (\OCP\App::isEnabled('files_versions')) {
466
-
467
-			$user = User::getUser();
468
-			$rootView = new View('/');
469
-
470
-			$target = Filesystem::normalizePath('/' . $location . '/' . $uniqueFilename);
471
-
472
-			list($owner, $ownerPath) = self::getUidAndFilename($target);
473
-
474
-			// file has been deleted in between
475
-			if (empty($ownerPath)) {
476
-				return false;
477
-			}
478
-
479
-			if ($timestamp) {
480
-				$versionedFile = $filename;
481
-			} else {
482
-				$versionedFile = $file;
483
-			}
484
-
485
-			if ($view->is_dir('/files_trashbin/versions/' . $file)) {
486
-				$rootView->rename(Filesystem::normalizePath($user . '/files_trashbin/versions/' . $file), Filesystem::normalizePath($owner . '/files_versions/' . $ownerPath));
487
-			} else if ($versions = self::getVersionsFromTrash($versionedFile, $timestamp, $user)) {
488
-				foreach ($versions as $v) {
489
-					if ($timestamp) {
490
-						$rootView->rename($user . '/files_trashbin/versions/' . $versionedFile . '.v' . $v . '.d' . $timestamp, $owner . '/files_versions/' . $ownerPath . '.v' . $v);
491
-					} else {
492
-						$rootView->rename($user . '/files_trashbin/versions/' . $versionedFile . '.v' . $v, $owner . '/files_versions/' . $ownerPath . '.v' . $v);
493
-					}
494
-				}
495
-			}
496
-		}
497
-	}
498
-
499
-	/**
500
-	 * delete all files from the trash
501
-	 */
502
-	public static function deleteAll() {
503
-		$user = User::getUser();
504
-		$userRoot = \OC::$server->getUserFolder($user)->getParent();
505
-		$view = new View('/' . $user);
506
-		$fileInfos = $view->getDirectoryContent('files_trashbin/files');
507
-
508
-		try {
509
-			$trash = $userRoot->get('files_trashbin');
510
-		} catch (NotFoundException $e) {
511
-			return false;
512
-		}
513
-
514
-		// Array to store the relative path in (after the file is deleted, the view won't be able to relativise the path anymore)
515
-		$filePaths = [];
516
-		foreach($fileInfos as $fileInfo){
517
-			$filePaths[] = $view->getRelativePath($fileInfo->getPath());
518
-		}
519
-		unset($fileInfos); // save memory
520
-
521
-		// Bulk PreDelete-Hook
522
-		\OC_Hook::emit('\OCP\Trashbin', 'preDeleteAll', ['paths' => $filePaths]);
523
-
524
-		// Single-File Hooks
525
-		foreach($filePaths as $path){
526
-			self::emitTrashbinPreDelete($path);
527
-		}
528
-
529
-		// actual file deletion
530
-		$trash->delete();
531
-		$query = \OC_DB::prepare('DELETE FROM `*PREFIX*files_trash` WHERE `user`=?');
532
-		$query->execute([$user]);
533
-
534
-		// Bulk PostDelete-Hook
535
-		\OC_Hook::emit('\OCP\Trashbin', 'deleteAll', ['paths' => $filePaths]);
536
-
537
-		// Single-File Hooks
538
-		foreach($filePaths as $path){
539
-			self::emitTrashbinPostDelete($path);
540
-		}
541
-
542
-		$trash = $userRoot->newFolder('files_trashbin');
543
-		$trash->newFolder('files');
544
-
545
-		return true;
546
-	}
547
-
548
-	/**
549
-	 * wrapper function to emit the 'preDelete' hook of \OCP\Trashbin before a file is deleted
550
-	 * @param string $path
551
-	 */
552
-	protected static function emitTrashbinPreDelete($path){
553
-		\OC_Hook::emit('\OCP\Trashbin', 'preDelete', ['path' => $path]);
554
-	}
555
-
556
-	/**
557
-	 * wrapper function to emit the 'delete' hook of \OCP\Trashbin after a file has been deleted
558
-	 * @param string $path
559
-	 */
560
-	protected static function emitTrashbinPostDelete($path){
561
-		\OC_Hook::emit('\OCP\Trashbin', 'delete', ['path' => $path]);
562
-	}
563
-
564
-	/**
565
-	 * delete file from trash bin permanently
566
-	 *
567
-	 * @param string $filename path to the file
568
-	 * @param string $user
569
-	 * @param int $timestamp of deletion time
570
-	 *
571
-	 * @return int size of deleted files
572
-	 */
573
-	public static function delete($filename, $user, $timestamp = null) {
574
-		$userRoot = \OC::$server->getUserFolder($user)->getParent();
575
-		$view = new View('/' . $user);
576
-		$size = 0;
577
-
578
-		if ($timestamp) {
579
-			$query = \OC_DB::prepare('DELETE FROM `*PREFIX*files_trash` WHERE `user`=? AND `id`=? AND `timestamp`=?');
580
-			$query->execute([$user, $filename, $timestamp]);
581
-			$file = $filename . '.d' . $timestamp;
582
-		} else {
583
-			$file = $filename;
584
-		}
585
-
586
-		$size += self::deleteVersions($view, $file, $filename, $timestamp, $user);
587
-
588
-		try {
589
-			$node = $userRoot->get('/files_trashbin/files/' . $file);
590
-		} catch (NotFoundException $e) {
591
-			return $size;
592
-		}
593
-
594
-		if ($node instanceof Folder) {
595
-			$size += self::calculateSize(new View('/' . $user . '/files_trashbin/files/' . $file));
596
-		} else if ($node instanceof File) {
597
-			$size += $view->filesize('/files_trashbin/files/' . $file);
598
-		}
599
-
600
-		self::emitTrashbinPreDelete('/files_trashbin/files/' . $file);
601
-		$node->delete();
602
-		self::emitTrashbinPostDelete('/files_trashbin/files/' . $file);
603
-
604
-		return $size;
605
-	}
606
-
607
-	/**
608
-	 * @param View $view
609
-	 * @param string $file
610
-	 * @param string $filename
611
-	 * @param integer|null $timestamp
612
-	 * @param string $user
613
-	 * @return int
614
-	 */
615
-	private static function deleteVersions(View $view, $file, $filename, $timestamp, $user) {
616
-		$size = 0;
617
-		if (\OCP\App::isEnabled('files_versions')) {
618
-			if ($view->is_dir('files_trashbin/versions/' . $file)) {
619
-				$size += self::calculateSize(new View('/' . $user . '/files_trashbin/versions/' . $file));
620
-				$view->unlink('files_trashbin/versions/' . $file);
621
-			} else if ($versions = self::getVersionsFromTrash($filename, $timestamp, $user)) {
622
-				foreach ($versions as $v) {
623
-					if ($timestamp) {
624
-						$size += $view->filesize('/files_trashbin/versions/' . $filename . '.v' . $v . '.d' . $timestamp);
625
-						$view->unlink('/files_trashbin/versions/' . $filename . '.v' . $v . '.d' . $timestamp);
626
-					} else {
627
-						$size += $view->filesize('/files_trashbin/versions/' . $filename . '.v' . $v);
628
-						$view->unlink('/files_trashbin/versions/' . $filename . '.v' . $v);
629
-					}
630
-				}
631
-			}
632
-		}
633
-		return $size;
634
-	}
635
-
636
-	/**
637
-	 * check to see whether a file exists in trashbin
638
-	 *
639
-	 * @param string $filename path to the file
640
-	 * @param int $timestamp of deletion time
641
-	 * @return bool true if file exists, otherwise false
642
-	 */
643
-	public static function file_exists($filename, $timestamp = null) {
644
-		$user = User::getUser();
645
-		$view = new View('/' . $user);
646
-
647
-		if ($timestamp) {
648
-			$filename = $filename . '.d' . $timestamp;
649
-		}
650
-
651
-		$target = Filesystem::normalizePath('files_trashbin/files/' . $filename);
652
-		return $view->file_exists($target);
653
-	}
654
-
655
-	/**
656
-	 * deletes used space for trash bin in db if user was deleted
657
-	 *
658
-	 * @param string $uid id of deleted user
659
-	 * @return bool result of db delete operation
660
-	 */
661
-	public static function deleteUser($uid) {
662
-		$query = \OC_DB::prepare('DELETE FROM `*PREFIX*files_trash` WHERE `user`=?');
663
-		return $query->execute([$uid]);
664
-	}
665
-
666
-	/**
667
-	 * calculate remaining free space for trash bin
668
-	 *
669
-	 * @param integer $trashbinSize current size of the trash bin
670
-	 * @param string $user
671
-	 * @return int available free space for trash bin
672
-	 */
673
-	private static function calculateFreeSpace($trashbinSize, $user) {
674
-		$softQuota = true;
675
-		$userObject = \OC::$server->getUserManager()->get($user);
676
-		if(is_null($userObject)) {
677
-			return 0;
678
-		}
679
-		$quota = $userObject->getQuota();
680
-		if ($quota === null || $quota === 'none') {
681
-			$quota = Filesystem::free_space('/');
682
-			$softQuota = false;
683
-			// inf or unknown free space
684
-			if ($quota < 0) {
685
-				$quota = PHP_INT_MAX;
686
-			}
687
-		} else {
688
-			$quota = \OCP\Util::computerFileSize($quota);
689
-		}
690
-
691
-		// calculate available space for trash bin
692
-		// subtract size of files and current trash bin size from quota
693
-		if ($softQuota) {
694
-			$userFolder = \OC::$server->getUserFolder($user);
695
-			if(is_null($userFolder)) {
696
-				return 0;
697
-			}
698
-			$free = $quota - $userFolder->getSize(false); // remaining free space for user
699
-			if ($free > 0) {
700
-				$availableSpace = ($free * self::DEFAULTMAXSIZE / 100) - $trashbinSize; // how much space can be used for versions
701
-			} else {
702
-				$availableSpace = $free - $trashbinSize;
703
-			}
704
-		} else {
705
-			$availableSpace = $quota;
706
-		}
707
-
708
-		return $availableSpace;
709
-	}
710
-
711
-	/**
712
-	 * resize trash bin if necessary after a new file was added to Nextcloud
713
-	 *
714
-	 * @param string $user user id
715
-	 */
716
-	public static function resizeTrash($user) {
717
-
718
-		$size = self::getTrashbinSize($user);
719
-
720
-		$freeSpace = self::calculateFreeSpace($size, $user);
721
-
722
-		if ($freeSpace < 0) {
723
-			self::scheduleExpire($user);
724
-		}
725
-	}
726
-
727
-	/**
728
-	 * clean up the trash bin
729
-	 *
730
-	 * @param string $user
731
-	 */
732
-	public static function expire($user) {
733
-		$trashBinSize = self::getTrashbinSize($user);
734
-		$availableSpace = self::calculateFreeSpace($trashBinSize, $user);
735
-
736
-		$dirContent = Helper::getTrashFiles('/', $user, 'mtime');
737
-
738
-		// delete all files older then $retention_obligation
739
-		list($delSize, $count) = self::deleteExpiredFiles($dirContent, $user);
740
-
741
-		$availableSpace += $delSize;
742
-
743
-		// delete files from trash until we meet the trash bin size limit again
744
-		self::deleteFiles(array_slice($dirContent, $count), $user, $availableSpace);
745
-	}
746
-
747
-	/**
748
-	 * @param string $user
749
-	 */
750
-	private static function scheduleExpire($user) {
751
-		// let the admin disable auto expire
752
-		/** @var Application $application */
753
-		$application = \OC::$server->query(Application::class);
754
-		$expiration = $application->getContainer()->query('Expiration');
755
-		if ($expiration->isEnabled()) {
756
-			\OC::$server->getCommandBus()->push(new Expire($user));
757
-		}
758
-	}
759
-
760
-	/**
761
-	 * if the size limit for the trash bin is reached, we delete the oldest
762
-	 * files in the trash bin until we meet the limit again
763
-	 *
764
-	 * @param array $files
765
-	 * @param string $user
766
-	 * @param int $availableSpace available disc space
767
-	 * @return int size of deleted files
768
-	 */
769
-	protected static function deleteFiles($files, $user, $availableSpace) {
770
-		/** @var Application $application */
771
-		$application = \OC::$server->query(Application::class);
772
-		$expiration = $application->getContainer()->query('Expiration');
773
-		$size = 0;
774
-
775
-		if ($availableSpace < 0) {
776
-			foreach ($files as $file) {
777
-				if ($availableSpace < 0 && $expiration->isExpired($file['mtime'], true)) {
778
-					$tmp = self::delete($file['name'], $user, $file['mtime']);
779
-					\OC::$server->getLogger()->info('remove "' . $file['name'] . '" (' . $tmp . 'B) to meet the limit of trash bin size (50% of available quota)', ['app' => 'files_trashbin']);
780
-					$availableSpace += $tmp;
781
-					$size += $tmp;
782
-				} else {
783
-					break;
784
-				}
785
-			}
786
-		}
787
-		return $size;
788
-	}
789
-
790
-	/**
791
-	 * delete files older then max storage time
792
-	 *
793
-	 * @param array $files list of files sorted by mtime
794
-	 * @param string $user
795
-	 * @return integer[] size of deleted files and number of deleted files
796
-	 */
797
-	public static function deleteExpiredFiles($files, $user) {
798
-		/** @var Expiration $expiration */
799
-		$expiration = \OC::$server->query(Expiration::class);
800
-		$size = 0;
801
-		$count = 0;
802
-		foreach ($files as $file) {
803
-			$timestamp = $file['mtime'];
804
-			$filename = $file['name'];
805
-			if ($expiration->isExpired($timestamp)) {
806
-				try {
807
-					$size += self::delete($filename, $user, $timestamp);
808
-					$count++;
809
-				} catch (\OCP\Files\NotPermittedException $e) {
810
-					\OC::$server->getLogger()->logException($e, ['app' => 'files_trashbin', 'level' => \OCP\ILogger::WARN, 'message' => 'Removing "' . $filename . '" from trashbin failed.']);
811
-				}
812
-				\OC::$server->getLogger()->info(
813
-					'Remove "' . $filename . '" from trashbin because it exceeds max retention obligation term.',
814
-					['app' => 'files_trashbin']
815
-				);
816
-			} else {
817
-				break;
818
-			}
819
-		}
820
-
821
-		return [$size, $count];
822
-	}
823
-
824
-	/**
825
-	 * recursive copy to copy a whole directory
826
-	 *
827
-	 * @param string $source source path, relative to the users files directory
828
-	 * @param string $destination destination path relative to the users root directoy
829
-	 * @param View $view file view for the users root directory
830
-	 * @return int
831
-	 * @throws Exceptions\CopyRecursiveException
832
-	 */
833
-	private static function copy_recursive($source, $destination, View $view) {
834
-		$size = 0;
835
-		if ($view->is_dir($source)) {
836
-			$view->mkdir($destination);
837
-			$view->touch($destination, $view->filemtime($source));
838
-			foreach ($view->getDirectoryContent($source) as $i) {
839
-				$pathDir = $source . '/' . $i['name'];
840
-				if ($view->is_dir($pathDir)) {
841
-					$size += self::copy_recursive($pathDir, $destination . '/' . $i['name'], $view);
842
-				} else {
843
-					$size += $view->filesize($pathDir);
844
-					$result = $view->copy($pathDir, $destination . '/' . $i['name']);
845
-					if (!$result) {
846
-						throw new \OCA\Files_Trashbin\Exceptions\CopyRecursiveException();
847
-					}
848
-					$view->touch($destination . '/' . $i['name'], $view->filemtime($pathDir));
849
-				}
850
-			}
851
-		} else {
852
-			$size += $view->filesize($source);
853
-			$result = $view->copy($source, $destination);
854
-			if (!$result) {
855
-				throw new \OCA\Files_Trashbin\Exceptions\CopyRecursiveException();
856
-			}
857
-			$view->touch($destination, $view->filemtime($source));
858
-		}
859
-		return $size;
860
-	}
861
-
862
-	/**
863
-	 * find all versions which belong to the file we want to restore
864
-	 *
865
-	 * @param string $filename name of the file which should be restored
866
-	 * @param int $timestamp timestamp when the file was deleted
867
-	 * @return array
868
-	 */
869
-	private static function getVersionsFromTrash($filename, $timestamp, $user) {
870
-		$view = new View('/' . $user . '/files_trashbin/versions');
871
-		$versions = [];
872
-
873
-		//force rescan of versions, local storage may not have updated the cache
874
-		if (!self::$scannedVersions) {
875
-			/** @var \OC\Files\Storage\Storage $storage */
876
-			list($storage,) = $view->resolvePath('/');
877
-			$storage->getScanner()->scan('files_trashbin/versions');
878
-			self::$scannedVersions = true;
879
-		}
880
-
881
-		if ($timestamp) {
882
-			// fetch for old versions
883
-			$matches = $view->searchRaw($filename . '.v%.d' . $timestamp);
884
-			$offset = -strlen($timestamp) - 2;
885
-		} else {
886
-			$matches = $view->searchRaw($filename . '.v%');
887
-		}
888
-
889
-		if (is_array($matches)) {
890
-			foreach ($matches as $ma) {
891
-				if ($timestamp) {
892
-					$parts = explode('.v', substr($ma['path'], 0, $offset));
893
-					$versions[] = end($parts);
894
-				} else {
895
-					$parts = explode('.v', $ma);
896
-					$versions[] = end($parts);
897
-				}
898
-			}
899
-		}
900
-		return $versions;
901
-	}
902
-
903
-	/**
904
-	 * find unique extension for restored file if a file with the same name already exists
905
-	 *
906
-	 * @param string $location where the file should be restored
907
-	 * @param string $filename name of the file
908
-	 * @param View $view filesystem view relative to users root directory
909
-	 * @return string with unique extension
910
-	 */
911
-	private static function getUniqueFilename($location, $filename, View $view) {
912
-		$ext = pathinfo($filename, PATHINFO_EXTENSION);
913
-		$name = pathinfo($filename, PATHINFO_FILENAME);
914
-		$l = \OC::$server->getL10N('files_trashbin');
915
-
916
-		$location = '/' . trim($location, '/');
917
-
918
-		// if extension is not empty we set a dot in front of it
919
-		if ($ext !== '') {
920
-			$ext = '.' . $ext;
921
-		}
922
-
923
-		if ($view->file_exists('files' . $location . '/' . $filename)) {
924
-			$i = 2;
925
-			$uniqueName = $name . " (" . $l->t("restored") . ")" . $ext;
926
-			while ($view->file_exists('files' . $location . '/' . $uniqueName)) {
927
-				$uniqueName = $name . " (" . $l->t("restored") . " " . $i . ")" . $ext;
928
-				$i++;
929
-			}
930
-
931
-			return $uniqueName;
932
-		}
933
-
934
-		return $filename;
935
-	}
936
-
937
-	/**
938
-	 * get the size from a given root folder
939
-	 *
940
-	 * @param View $view file view on the root folder
941
-	 * @return integer size of the folder
942
-	 */
943
-	private static function calculateSize($view) {
944
-		$root = \OC::$server->getConfig()->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . $view->getAbsolutePath('');
945
-		if (!file_exists($root)) {
946
-			return 0;
947
-		}
948
-		$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($root), \RecursiveIteratorIterator::CHILD_FIRST);
949
-		$size = 0;
950
-
951
-		/**
952
-		 * RecursiveDirectoryIterator on an NFS path isn't iterable with foreach
953
-		 * This bug is fixed in PHP 5.5.9 or before
954
-		 * See #8376
955
-		 */
956
-		$iterator->rewind();
957
-		while ($iterator->valid()) {
958
-			$path = $iterator->current();
959
-			$relpath = substr($path, strlen($root) - 1);
960
-			if (!$view->is_dir($relpath)) {
961
-				$size += $view->filesize($relpath);
962
-			}
963
-			$iterator->next();
964
-		}
965
-		return $size;
966
-	}
967
-
968
-	/**
969
-	 * get current size of trash bin from a given user
970
-	 *
971
-	 * @param string $user user who owns the trash bin
972
-	 * @return integer trash bin size
973
-	 */
974
-	private static function getTrashbinSize($user) {
975
-		$view = new View('/' . $user);
976
-		$fileInfo = $view->getFileInfo('/files_trashbin');
977
-		return isset($fileInfo['size']) ? $fileInfo['size'] : 0;
978
-	}
979
-
980
-	/**
981
-	 * register hooks
982
-	 */
983
-	public static function registerHooks() {
984
-		// create storage wrapper on setup
985
-		\OCP\Util::connectHook('OC_Filesystem', 'preSetup', 'OCA\Files_Trashbin\Storage', 'setupStorage');
986
-		//Listen to delete user signal
987
-		\OCP\Util::connectHook('OC_User', 'pre_deleteUser', 'OCA\Files_Trashbin\Hooks', 'deleteUser_hook');
988
-		//Listen to post write hook
989
-		\OCP\Util::connectHook('OC_Filesystem', 'post_write', 'OCA\Files_Trashbin\Hooks', 'post_write_hook');
990
-		// pre and post-rename, disable trash logic for the copy+unlink case
991
-		\OCP\Util::connectHook('OC_Filesystem', 'delete', 'OCA\Files_Trashbin\Trashbin', 'ensureFileScannedHook');
992
-	}
993
-
994
-	/**
995
-	 * check if trash bin is empty for a given user
996
-	 *
997
-	 * @param string $user
998
-	 * @return bool
999
-	 */
1000
-	public static function isEmpty($user) {
1001
-
1002
-		$view = new View('/' . $user . '/files_trashbin');
1003
-		if ($view->is_dir('/files') && $dh = $view->opendir('/files')) {
1004
-			while ($file = readdir($dh)) {
1005
-				if (!Filesystem::isIgnoredDir($file)) {
1006
-					return false;
1007
-				}
1008
-			}
1009
-		}
1010
-		return true;
1011
-	}
1012
-
1013
-	/**
1014
-	 * @param $path
1015
-	 * @return string
1016
-	 */
1017
-	public static function preview_icon($path) {
1018
-		return \OC::$server->getURLGenerator()->linkToRoute('core_ajax_trashbin_preview', ['x' => 32, 'y' => 32, 'file' => $path]);
1019
-	}
58
+    // unit: percentage; 50% of available disk space/quota
59
+    const DEFAULTMAXSIZE = 50;
60
+
61
+    /**
62
+     * Whether versions have already be rescanned during this PHP request
63
+     *
64
+     * @var bool
65
+     */
66
+    private static $scannedVersions = false;
67
+
68
+    /**
69
+     * Ensure we don't need to scan the file during the move to trash
70
+     * by triggering the scan in the pre-hook
71
+     *
72
+     * @param array $params
73
+     */
74
+    public static function ensureFileScannedHook($params) {
75
+        try {
76
+            self::getUidAndFilename($params['path']);
77
+        } catch (NotFoundException $e) {
78
+            // nothing to scan for non existing files
79
+        }
80
+    }
81
+
82
+    /**
83
+     * get the UID of the owner of the file and the path to the file relative to
84
+     * owners files folder
85
+     *
86
+     * @param string $filename
87
+     * @return array
88
+     * @throws \OC\User\NoUserException
89
+     */
90
+    public static function getUidAndFilename($filename) {
91
+        $uid = Filesystem::getOwner($filename);
92
+        $userManager = \OC::$server->getUserManager();
93
+        // if the user with the UID doesn't exists, e.g. because the UID points
94
+        // to a remote user with a federated cloud ID we use the current logged-in
95
+        // user. We need a valid local user to move the file to the right trash bin
96
+        if (!$userManager->userExists($uid)) {
97
+            $uid = User::getUser();
98
+        }
99
+        if (!$uid) {
100
+            // no owner, usually because of share link from ext storage
101
+            return [null, null];
102
+        }
103
+        Filesystem::initMountPoints($uid);
104
+        if ($uid !== User::getUser()) {
105
+            $info = Filesystem::getFileInfo($filename);
106
+            $ownerView = new View('/' . $uid . '/files');
107
+            try {
108
+                $filename = $ownerView->getPath($info['fileid']);
109
+            } catch (NotFoundException $e) {
110
+                $filename = null;
111
+            }
112
+        }
113
+        return [$uid, $filename];
114
+    }
115
+
116
+    /**
117
+     * get original location of files for user
118
+     *
119
+     * @param string $user
120
+     * @return array (filename => array (timestamp => original location))
121
+     */
122
+    public static function getLocations($user) {
123
+        $query = \OC_DB::prepare('SELECT `id`, `timestamp`, `location`'
124
+            . ' FROM `*PREFIX*files_trash` WHERE `user`=?');
125
+        $result = $query->execute([$user]);
126
+        $array = [];
127
+        while ($row = $result->fetchRow()) {
128
+            if (isset($array[$row['id']])) {
129
+                $array[$row['id']][$row['timestamp']] = $row['location'];
130
+            } else {
131
+                $array[$row['id']] = [$row['timestamp'] => $row['location']];
132
+            }
133
+        }
134
+        return $array;
135
+    }
136
+
137
+    /**
138
+     * get original location of file
139
+     *
140
+     * @param string $user
141
+     * @param string $filename
142
+     * @param string $timestamp
143
+     * @return string original location
144
+     */
145
+    public static function getLocation($user, $filename, $timestamp) {
146
+        $query = \OC_DB::prepare('SELECT `location` FROM `*PREFIX*files_trash`'
147
+            . ' WHERE `user`=? AND `id`=? AND `timestamp`=?');
148
+        $result = $query->execute([$user, $filename, $timestamp])->fetchAll();
149
+        if (isset($result[0]['location'])) {
150
+            return $result[0]['location'];
151
+        } else {
152
+            return false;
153
+        }
154
+    }
155
+
156
+    private static function setUpTrash($user) {
157
+        $view = new View('/' . $user);
158
+        if (!$view->is_dir('files_trashbin')) {
159
+            $view->mkdir('files_trashbin');
160
+        }
161
+        if (!$view->is_dir('files_trashbin/files')) {
162
+            $view->mkdir('files_trashbin/files');
163
+        }
164
+        if (!$view->is_dir('files_trashbin/versions')) {
165
+            $view->mkdir('files_trashbin/versions');
166
+        }
167
+        if (!$view->is_dir('files_trashbin/keys')) {
168
+            $view->mkdir('files_trashbin/keys');
169
+        }
170
+    }
171
+
172
+
173
+    /**
174
+     * copy file to owners trash
175
+     *
176
+     * @param string $sourcePath
177
+     * @param string $owner
178
+     * @param string $targetPath
179
+     * @param $user
180
+     * @param integer $timestamp
181
+     */
182
+    private static function copyFilesToUser($sourcePath, $owner, $targetPath, $user, $timestamp) {
183
+        self::setUpTrash($owner);
184
+
185
+        $targetFilename = basename($targetPath);
186
+        $targetLocation = dirname($targetPath);
187
+
188
+        $sourceFilename = basename($sourcePath);
189
+
190
+        $view = new View('/');
191
+
192
+        $target = $user . '/files_trashbin/files/' . $targetFilename . '.d' . $timestamp;
193
+        $source = $owner . '/files_trashbin/files/' . $sourceFilename . '.d' . $timestamp;
194
+        $free = $view->free_space($target);
195
+        $isUnknownOrUnlimitedFreeSpace = $free < 0;
196
+        $isEnoughFreeSpaceLeft = $view->filesize($source) < $free;
197
+        if ($isUnknownOrUnlimitedFreeSpace || $isEnoughFreeSpaceLeft) {
198
+            self::copy_recursive($source, $target, $view);
199
+        }
200
+
201
+
202
+        if ($view->file_exists($target)) {
203
+            $query = \OC_DB::prepare("INSERT INTO `*PREFIX*files_trash` (`id`,`timestamp`,`location`,`user`) VALUES (?,?,?,?)");
204
+            $result = $query->execute([$targetFilename, $timestamp, $targetLocation, $user]);
205
+            if (!$result) {
206
+                \OC::$server->getLogger()->error('trash bin database couldn\'t be updated for the files owner', ['app' => 'files_trashbin']);
207
+            }
208
+        }
209
+    }
210
+
211
+
212
+    /**
213
+     * move file to the trash bin
214
+     *
215
+     * @param string $file_path path to the deleted file/directory relative to the files root directory
216
+     * @param bool $ownerOnly delete for owner only (if file gets moved out of a shared folder)
217
+     *
218
+     * @return bool
219
+     */
220
+    public static function move2trash($file_path, $ownerOnly = false) {
221
+        // get the user for which the filesystem is setup
222
+        $root = Filesystem::getRoot();
223
+        list(, $user) = explode('/', $root);
224
+        list($owner, $ownerPath) = self::getUidAndFilename($file_path);
225
+
226
+        // if no owner found (ex: ext storage + share link), will use the current user's trashbin then
227
+        if (is_null($owner)) {
228
+            $owner = $user;
229
+            $ownerPath = $file_path;
230
+        }
231
+
232
+        $ownerView = new View('/' . $owner);
233
+        // file has been deleted in between
234
+        if (is_null($ownerPath) || $ownerPath === '' || !$ownerView->file_exists('/files/' . $ownerPath)) {
235
+            return true;
236
+        }
237
+
238
+        self::setUpTrash($user);
239
+        if ($owner !== $user) {
240
+            // also setup for owner
241
+            self::setUpTrash($owner);
242
+        }
243
+
244
+        $path_parts = pathinfo($ownerPath);
245
+
246
+        $filename = $path_parts['basename'];
247
+        $location = $path_parts['dirname'];
248
+        $timestamp = time();
249
+
250
+        // disable proxy to prevent recursive calls
251
+        $trashPath = '/files_trashbin/files/' . $filename . '.d' . $timestamp;
252
+
253
+        /** @var \OC\Files\Storage\Storage $trashStorage */
254
+        list($trashStorage, $trashInternalPath) = $ownerView->resolvePath($trashPath);
255
+        /** @var \OC\Files\Storage\Storage $sourceStorage */
256
+        list($sourceStorage, $sourceInternalPath) = $ownerView->resolvePath('/files/' . $ownerPath);
257
+        try {
258
+            $moveSuccessful = true;
259
+            if ($trashStorage->file_exists($trashInternalPath)) {
260
+                $trashStorage->unlink($trashInternalPath);
261
+            }
262
+            $trashStorage->moveFromStorage($sourceStorage, $sourceInternalPath, $trashInternalPath);
263
+        } catch (\OCA\Files_Trashbin\Exceptions\CopyRecursiveException $e) {
264
+            $moveSuccessful = false;
265
+            if ($trashStorage->file_exists($trashInternalPath)) {
266
+                $trashStorage->unlink($trashInternalPath);
267
+            }
268
+            \OC::$server->getLogger()->error('Couldn\'t move ' . $file_path . ' to the trash bin', ['app' => 'files_trashbin']);
269
+        }
270
+
271
+        if ($sourceStorage->file_exists($sourceInternalPath)) { // failed to delete the original file, abort
272
+            if ($sourceStorage->is_dir($sourceInternalPath)) {
273
+                $sourceStorage->rmdir($sourceInternalPath);
274
+            } else {
275
+                $sourceStorage->unlink($sourceInternalPath);
276
+            }
277
+            return false;
278
+        }
279
+
280
+        $trashStorage->getUpdater()->renameFromStorage($sourceStorage, $sourceInternalPath, $trashInternalPath);
281
+
282
+        if ($moveSuccessful) {
283
+            $query = \OC_DB::prepare("INSERT INTO `*PREFIX*files_trash` (`id`,`timestamp`,`location`,`user`) VALUES (?,?,?,?)");
284
+            $result = $query->execute([$filename, $timestamp, $location, $owner]);
285
+            if (!$result) {
286
+                \OC::$server->getLogger()->error('trash bin database couldn\'t be updated', ['app' => 'files_trashbin']);
287
+            }
288
+            \OCP\Util::emitHook('\OCA\Files_Trashbin\Trashbin', 'post_moveToTrash', ['filePath' => Filesystem::normalizePath($file_path),
289
+                'trashPath' => Filesystem::normalizePath($filename . '.d' . $timestamp)]);
290
+
291
+            self::retainVersions($filename, $owner, $ownerPath, $timestamp);
292
+
293
+            // if owner !== user we need to also add a copy to the users trash
294
+            if ($user !== $owner && $ownerOnly === false) {
295
+                self::copyFilesToUser($ownerPath, $owner, $file_path, $user, $timestamp);
296
+            }
297
+        }
298
+
299
+        self::scheduleExpire($user);
300
+
301
+        // if owner !== user we also need to update the owners trash size
302
+        if ($owner !== $user) {
303
+            self::scheduleExpire($owner);
304
+        }
305
+
306
+        return $moveSuccessful;
307
+    }
308
+
309
+    /**
310
+     * Move file versions to trash so that they can be restored later
311
+     *
312
+     * @param string $filename of deleted file
313
+     * @param string $owner owner user id
314
+     * @param string $ownerPath path relative to the owner's home storage
315
+     * @param integer $timestamp when the file was deleted
316
+     */
317
+    private static function retainVersions($filename, $owner, $ownerPath, $timestamp) {
318
+        if (\OCP\App::isEnabled('files_versions') && !empty($ownerPath)) {
319
+
320
+            $user = User::getUser();
321
+            $rootView = new View('/');
322
+
323
+            if ($rootView->is_dir($owner . '/files_versions/' . $ownerPath)) {
324
+                if ($owner !== $user) {
325
+                    self::copy_recursive($owner . '/files_versions/' . $ownerPath, $owner . '/files_trashbin/versions/' . basename($ownerPath) . '.d' . $timestamp, $rootView);
326
+                }
327
+                self::move($rootView, $owner . '/files_versions/' . $ownerPath, $user . '/files_trashbin/versions/' . $filename . '.d' . $timestamp);
328
+            } else if ($versions = \OCA\Files_Versions\Storage::getVersions($owner, $ownerPath)) {
329
+
330
+                foreach ($versions as $v) {
331
+                    if ($owner !== $user) {
332
+                        self::copy($rootView, $owner . '/files_versions' . $v['path'] . '.v' . $v['version'], $owner . '/files_trashbin/versions/' . $v['name'] . '.v' . $v['version'] . '.d' . $timestamp);
333
+                    }
334
+                    self::move($rootView, $owner . '/files_versions' . $v['path'] . '.v' . $v['version'], $user . '/files_trashbin/versions/' . $filename . '.v' . $v['version'] . '.d' . $timestamp);
335
+                }
336
+            }
337
+        }
338
+    }
339
+
340
+    /**
341
+     * Move a file or folder on storage level
342
+     *
343
+     * @param View $view
344
+     * @param string $source
345
+     * @param string $target
346
+     * @return bool
347
+     */
348
+    private static function move(View $view, $source, $target) {
349
+        /** @var \OC\Files\Storage\Storage $sourceStorage */
350
+        list($sourceStorage, $sourceInternalPath) = $view->resolvePath($source);
351
+        /** @var \OC\Files\Storage\Storage $targetStorage */
352
+        list($targetStorage, $targetInternalPath) = $view->resolvePath($target);
353
+        /** @var \OC\Files\Storage\Storage $ownerTrashStorage */
354
+
355
+        $result = $targetStorage->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
356
+        if ($result) {
357
+            $targetStorage->getUpdater()->renameFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
358
+        }
359
+        return $result;
360
+    }
361
+
362
+    /**
363
+     * Copy a file or folder on storage level
364
+     *
365
+     * @param View $view
366
+     * @param string $source
367
+     * @param string $target
368
+     * @return bool
369
+     */
370
+    private static function copy(View $view, $source, $target) {
371
+        /** @var \OC\Files\Storage\Storage $sourceStorage */
372
+        list($sourceStorage, $sourceInternalPath) = $view->resolvePath($source);
373
+        /** @var \OC\Files\Storage\Storage $targetStorage */
374
+        list($targetStorage, $targetInternalPath) = $view->resolvePath($target);
375
+        /** @var \OC\Files\Storage\Storage $ownerTrashStorage */
376
+
377
+        $result = $targetStorage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
378
+        if ($result) {
379
+            $targetStorage->getUpdater()->update($targetInternalPath);
380
+        }
381
+        return $result;
382
+    }
383
+
384
+    /**
385
+     * Restore a file or folder from trash bin
386
+     *
387
+     * @param string $file path to the deleted file/folder relative to "files_trashbin/files/",
388
+     * including the timestamp suffix ".d12345678"
389
+     * @param string $filename name of the file/folder
390
+     * @param int $timestamp time when the file/folder was deleted
391
+     *
392
+     * @return bool true on success, false otherwise
393
+     */
394
+    public static function restore($file, $filename, $timestamp) {
395
+        $user = User::getUser();
396
+        $view = new View('/' . $user);
397
+
398
+        $location = '';
399
+        if ($timestamp) {
400
+            $location = self::getLocation($user, $filename, $timestamp);
401
+            if ($location === false) {
402
+                \OC::$server->getLogger()->error('trash bin database inconsistent! ($user: ' . $user . ' $filename: ' . $filename . ', $timestamp: ' . $timestamp . ')', ['app' => 'files_trashbin']);
403
+            } else {
404
+                // if location no longer exists, restore file in the root directory
405
+                if ($location !== '/' &&
406
+                    (!$view->is_dir('files/' . $location) ||
407
+                        !$view->isCreatable('files/' . $location))
408
+                ) {
409
+                    $location = '';
410
+                }
411
+            }
412
+        }
413
+
414
+        // we need a  extension in case a file/dir with the same name already exists
415
+        $uniqueFilename = self::getUniqueFilename($location, $filename, $view);
416
+
417
+        $source = Filesystem::normalizePath('files_trashbin/files/' . $file);
418
+        $target = Filesystem::normalizePath('files/' . $location . '/' . $uniqueFilename);
419
+        if (!$view->file_exists($source)) {
420
+            return false;
421
+        }
422
+        $mtime = $view->filemtime($source);
423
+
424
+        // restore file
425
+        if (!$view->isCreatable(dirname($target))) {
426
+            throw new NotPermittedException("Can't restore trash item because the target folder is not writable");
427
+        }
428
+        $restoreResult = $view->rename($source, $target);
429
+
430
+        // handle the restore result
431
+        if ($restoreResult) {
432
+            $fakeRoot = $view->getRoot();
433
+            $view->chroot('/' . $user . '/files');
434
+            $view->touch('/' . $location . '/' . $uniqueFilename, $mtime);
435
+            $view->chroot($fakeRoot);
436
+            \OCP\Util::emitHook('\OCA\Files_Trashbin\Trashbin', 'post_restore', ['filePath' => Filesystem::normalizePath('/' . $location . '/' . $uniqueFilename),
437
+                'trashPath' => Filesystem::normalizePath($file)]);
438
+
439
+            self::restoreVersions($view, $file, $filename, $uniqueFilename, $location, $timestamp);
440
+
441
+            if ($timestamp) {
442
+                $query = \OC_DB::prepare('DELETE FROM `*PREFIX*files_trash` WHERE `user`=? AND `id`=? AND `timestamp`=?');
443
+                $query->execute([$user, $filename, $timestamp]);
444
+            }
445
+
446
+            return true;
447
+        }
448
+
449
+        return false;
450
+    }
451
+
452
+    /**
453
+     * restore versions from trash bin
454
+     *
455
+     * @param View $view file view
456
+     * @param string $file complete path to file
457
+     * @param string $filename name of file once it was deleted
458
+     * @param string $uniqueFilename new file name to restore the file without overwriting existing files
459
+     * @param string $location location if file
460
+     * @param int $timestamp deletion time
461
+     * @return false|null
462
+     */
463
+    private static function restoreVersions(View $view, $file, $filename, $uniqueFilename, $location, $timestamp) {
464
+
465
+        if (\OCP\App::isEnabled('files_versions')) {
466
+
467
+            $user = User::getUser();
468
+            $rootView = new View('/');
469
+
470
+            $target = Filesystem::normalizePath('/' . $location . '/' . $uniqueFilename);
471
+
472
+            list($owner, $ownerPath) = self::getUidAndFilename($target);
473
+
474
+            // file has been deleted in between
475
+            if (empty($ownerPath)) {
476
+                return false;
477
+            }
478
+
479
+            if ($timestamp) {
480
+                $versionedFile = $filename;
481
+            } else {
482
+                $versionedFile = $file;
483
+            }
484
+
485
+            if ($view->is_dir('/files_trashbin/versions/' . $file)) {
486
+                $rootView->rename(Filesystem::normalizePath($user . '/files_trashbin/versions/' . $file), Filesystem::normalizePath($owner . '/files_versions/' . $ownerPath));
487
+            } else if ($versions = self::getVersionsFromTrash($versionedFile, $timestamp, $user)) {
488
+                foreach ($versions as $v) {
489
+                    if ($timestamp) {
490
+                        $rootView->rename($user . '/files_trashbin/versions/' . $versionedFile . '.v' . $v . '.d' . $timestamp, $owner . '/files_versions/' . $ownerPath . '.v' . $v);
491
+                    } else {
492
+                        $rootView->rename($user . '/files_trashbin/versions/' . $versionedFile . '.v' . $v, $owner . '/files_versions/' . $ownerPath . '.v' . $v);
493
+                    }
494
+                }
495
+            }
496
+        }
497
+    }
498
+
499
+    /**
500
+     * delete all files from the trash
501
+     */
502
+    public static function deleteAll() {
503
+        $user = User::getUser();
504
+        $userRoot = \OC::$server->getUserFolder($user)->getParent();
505
+        $view = new View('/' . $user);
506
+        $fileInfos = $view->getDirectoryContent('files_trashbin/files');
507
+
508
+        try {
509
+            $trash = $userRoot->get('files_trashbin');
510
+        } catch (NotFoundException $e) {
511
+            return false;
512
+        }
513
+
514
+        // Array to store the relative path in (after the file is deleted, the view won't be able to relativise the path anymore)
515
+        $filePaths = [];
516
+        foreach($fileInfos as $fileInfo){
517
+            $filePaths[] = $view->getRelativePath($fileInfo->getPath());
518
+        }
519
+        unset($fileInfos); // save memory
520
+
521
+        // Bulk PreDelete-Hook
522
+        \OC_Hook::emit('\OCP\Trashbin', 'preDeleteAll', ['paths' => $filePaths]);
523
+
524
+        // Single-File Hooks
525
+        foreach($filePaths as $path){
526
+            self::emitTrashbinPreDelete($path);
527
+        }
528
+
529
+        // actual file deletion
530
+        $trash->delete();
531
+        $query = \OC_DB::prepare('DELETE FROM `*PREFIX*files_trash` WHERE `user`=?');
532
+        $query->execute([$user]);
533
+
534
+        // Bulk PostDelete-Hook
535
+        \OC_Hook::emit('\OCP\Trashbin', 'deleteAll', ['paths' => $filePaths]);
536
+
537
+        // Single-File Hooks
538
+        foreach($filePaths as $path){
539
+            self::emitTrashbinPostDelete($path);
540
+        }
541
+
542
+        $trash = $userRoot->newFolder('files_trashbin');
543
+        $trash->newFolder('files');
544
+
545
+        return true;
546
+    }
547
+
548
+    /**
549
+     * wrapper function to emit the 'preDelete' hook of \OCP\Trashbin before a file is deleted
550
+     * @param string $path
551
+     */
552
+    protected static function emitTrashbinPreDelete($path){
553
+        \OC_Hook::emit('\OCP\Trashbin', 'preDelete', ['path' => $path]);
554
+    }
555
+
556
+    /**
557
+     * wrapper function to emit the 'delete' hook of \OCP\Trashbin after a file has been deleted
558
+     * @param string $path
559
+     */
560
+    protected static function emitTrashbinPostDelete($path){
561
+        \OC_Hook::emit('\OCP\Trashbin', 'delete', ['path' => $path]);
562
+    }
563
+
564
+    /**
565
+     * delete file from trash bin permanently
566
+     *
567
+     * @param string $filename path to the file
568
+     * @param string $user
569
+     * @param int $timestamp of deletion time
570
+     *
571
+     * @return int size of deleted files
572
+     */
573
+    public static function delete($filename, $user, $timestamp = null) {
574
+        $userRoot = \OC::$server->getUserFolder($user)->getParent();
575
+        $view = new View('/' . $user);
576
+        $size = 0;
577
+
578
+        if ($timestamp) {
579
+            $query = \OC_DB::prepare('DELETE FROM `*PREFIX*files_trash` WHERE `user`=? AND `id`=? AND `timestamp`=?');
580
+            $query->execute([$user, $filename, $timestamp]);
581
+            $file = $filename . '.d' . $timestamp;
582
+        } else {
583
+            $file = $filename;
584
+        }
585
+
586
+        $size += self::deleteVersions($view, $file, $filename, $timestamp, $user);
587
+
588
+        try {
589
+            $node = $userRoot->get('/files_trashbin/files/' . $file);
590
+        } catch (NotFoundException $e) {
591
+            return $size;
592
+        }
593
+
594
+        if ($node instanceof Folder) {
595
+            $size += self::calculateSize(new View('/' . $user . '/files_trashbin/files/' . $file));
596
+        } else if ($node instanceof File) {
597
+            $size += $view->filesize('/files_trashbin/files/' . $file);
598
+        }
599
+
600
+        self::emitTrashbinPreDelete('/files_trashbin/files/' . $file);
601
+        $node->delete();
602
+        self::emitTrashbinPostDelete('/files_trashbin/files/' . $file);
603
+
604
+        return $size;
605
+    }
606
+
607
+    /**
608
+     * @param View $view
609
+     * @param string $file
610
+     * @param string $filename
611
+     * @param integer|null $timestamp
612
+     * @param string $user
613
+     * @return int
614
+     */
615
+    private static function deleteVersions(View $view, $file, $filename, $timestamp, $user) {
616
+        $size = 0;
617
+        if (\OCP\App::isEnabled('files_versions')) {
618
+            if ($view->is_dir('files_trashbin/versions/' . $file)) {
619
+                $size += self::calculateSize(new View('/' . $user . '/files_trashbin/versions/' . $file));
620
+                $view->unlink('files_trashbin/versions/' . $file);
621
+            } else if ($versions = self::getVersionsFromTrash($filename, $timestamp, $user)) {
622
+                foreach ($versions as $v) {
623
+                    if ($timestamp) {
624
+                        $size += $view->filesize('/files_trashbin/versions/' . $filename . '.v' . $v . '.d' . $timestamp);
625
+                        $view->unlink('/files_trashbin/versions/' . $filename . '.v' . $v . '.d' . $timestamp);
626
+                    } else {
627
+                        $size += $view->filesize('/files_trashbin/versions/' . $filename . '.v' . $v);
628
+                        $view->unlink('/files_trashbin/versions/' . $filename . '.v' . $v);
629
+                    }
630
+                }
631
+            }
632
+        }
633
+        return $size;
634
+    }
635
+
636
+    /**
637
+     * check to see whether a file exists in trashbin
638
+     *
639
+     * @param string $filename path to the file
640
+     * @param int $timestamp of deletion time
641
+     * @return bool true if file exists, otherwise false
642
+     */
643
+    public static function file_exists($filename, $timestamp = null) {
644
+        $user = User::getUser();
645
+        $view = new View('/' . $user);
646
+
647
+        if ($timestamp) {
648
+            $filename = $filename . '.d' . $timestamp;
649
+        }
650
+
651
+        $target = Filesystem::normalizePath('files_trashbin/files/' . $filename);
652
+        return $view->file_exists($target);
653
+    }
654
+
655
+    /**
656
+     * deletes used space for trash bin in db if user was deleted
657
+     *
658
+     * @param string $uid id of deleted user
659
+     * @return bool result of db delete operation
660
+     */
661
+    public static function deleteUser($uid) {
662
+        $query = \OC_DB::prepare('DELETE FROM `*PREFIX*files_trash` WHERE `user`=?');
663
+        return $query->execute([$uid]);
664
+    }
665
+
666
+    /**
667
+     * calculate remaining free space for trash bin
668
+     *
669
+     * @param integer $trashbinSize current size of the trash bin
670
+     * @param string $user
671
+     * @return int available free space for trash bin
672
+     */
673
+    private static function calculateFreeSpace($trashbinSize, $user) {
674
+        $softQuota = true;
675
+        $userObject = \OC::$server->getUserManager()->get($user);
676
+        if(is_null($userObject)) {
677
+            return 0;
678
+        }
679
+        $quota = $userObject->getQuota();
680
+        if ($quota === null || $quota === 'none') {
681
+            $quota = Filesystem::free_space('/');
682
+            $softQuota = false;
683
+            // inf or unknown free space
684
+            if ($quota < 0) {
685
+                $quota = PHP_INT_MAX;
686
+            }
687
+        } else {
688
+            $quota = \OCP\Util::computerFileSize($quota);
689
+        }
690
+
691
+        // calculate available space for trash bin
692
+        // subtract size of files and current trash bin size from quota
693
+        if ($softQuota) {
694
+            $userFolder = \OC::$server->getUserFolder($user);
695
+            if(is_null($userFolder)) {
696
+                return 0;
697
+            }
698
+            $free = $quota - $userFolder->getSize(false); // remaining free space for user
699
+            if ($free > 0) {
700
+                $availableSpace = ($free * self::DEFAULTMAXSIZE / 100) - $trashbinSize; // how much space can be used for versions
701
+            } else {
702
+                $availableSpace = $free - $trashbinSize;
703
+            }
704
+        } else {
705
+            $availableSpace = $quota;
706
+        }
707
+
708
+        return $availableSpace;
709
+    }
710
+
711
+    /**
712
+     * resize trash bin if necessary after a new file was added to Nextcloud
713
+     *
714
+     * @param string $user user id
715
+     */
716
+    public static function resizeTrash($user) {
717
+
718
+        $size = self::getTrashbinSize($user);
719
+
720
+        $freeSpace = self::calculateFreeSpace($size, $user);
721
+
722
+        if ($freeSpace < 0) {
723
+            self::scheduleExpire($user);
724
+        }
725
+    }
726
+
727
+    /**
728
+     * clean up the trash bin
729
+     *
730
+     * @param string $user
731
+     */
732
+    public static function expire($user) {
733
+        $trashBinSize = self::getTrashbinSize($user);
734
+        $availableSpace = self::calculateFreeSpace($trashBinSize, $user);
735
+
736
+        $dirContent = Helper::getTrashFiles('/', $user, 'mtime');
737
+
738
+        // delete all files older then $retention_obligation
739
+        list($delSize, $count) = self::deleteExpiredFiles($dirContent, $user);
740
+
741
+        $availableSpace += $delSize;
742
+
743
+        // delete files from trash until we meet the trash bin size limit again
744
+        self::deleteFiles(array_slice($dirContent, $count), $user, $availableSpace);
745
+    }
746
+
747
+    /**
748
+     * @param string $user
749
+     */
750
+    private static function scheduleExpire($user) {
751
+        // let the admin disable auto expire
752
+        /** @var Application $application */
753
+        $application = \OC::$server->query(Application::class);
754
+        $expiration = $application->getContainer()->query('Expiration');
755
+        if ($expiration->isEnabled()) {
756
+            \OC::$server->getCommandBus()->push(new Expire($user));
757
+        }
758
+    }
759
+
760
+    /**
761
+     * if the size limit for the trash bin is reached, we delete the oldest
762
+     * files in the trash bin until we meet the limit again
763
+     *
764
+     * @param array $files
765
+     * @param string $user
766
+     * @param int $availableSpace available disc space
767
+     * @return int size of deleted files
768
+     */
769
+    protected static function deleteFiles($files, $user, $availableSpace) {
770
+        /** @var Application $application */
771
+        $application = \OC::$server->query(Application::class);
772
+        $expiration = $application->getContainer()->query('Expiration');
773
+        $size = 0;
774
+
775
+        if ($availableSpace < 0) {
776
+            foreach ($files as $file) {
777
+                if ($availableSpace < 0 && $expiration->isExpired($file['mtime'], true)) {
778
+                    $tmp = self::delete($file['name'], $user, $file['mtime']);
779
+                    \OC::$server->getLogger()->info('remove "' . $file['name'] . '" (' . $tmp . 'B) to meet the limit of trash bin size (50% of available quota)', ['app' => 'files_trashbin']);
780
+                    $availableSpace += $tmp;
781
+                    $size += $tmp;
782
+                } else {
783
+                    break;
784
+                }
785
+            }
786
+        }
787
+        return $size;
788
+    }
789
+
790
+    /**
791
+     * delete files older then max storage time
792
+     *
793
+     * @param array $files list of files sorted by mtime
794
+     * @param string $user
795
+     * @return integer[] size of deleted files and number of deleted files
796
+     */
797
+    public static function deleteExpiredFiles($files, $user) {
798
+        /** @var Expiration $expiration */
799
+        $expiration = \OC::$server->query(Expiration::class);
800
+        $size = 0;
801
+        $count = 0;
802
+        foreach ($files as $file) {
803
+            $timestamp = $file['mtime'];
804
+            $filename = $file['name'];
805
+            if ($expiration->isExpired($timestamp)) {
806
+                try {
807
+                    $size += self::delete($filename, $user, $timestamp);
808
+                    $count++;
809
+                } catch (\OCP\Files\NotPermittedException $e) {
810
+                    \OC::$server->getLogger()->logException($e, ['app' => 'files_trashbin', 'level' => \OCP\ILogger::WARN, 'message' => 'Removing "' . $filename . '" from trashbin failed.']);
811
+                }
812
+                \OC::$server->getLogger()->info(
813
+                    'Remove "' . $filename . '" from trashbin because it exceeds max retention obligation term.',
814
+                    ['app' => 'files_trashbin']
815
+                );
816
+            } else {
817
+                break;
818
+            }
819
+        }
820
+
821
+        return [$size, $count];
822
+    }
823
+
824
+    /**
825
+     * recursive copy to copy a whole directory
826
+     *
827
+     * @param string $source source path, relative to the users files directory
828
+     * @param string $destination destination path relative to the users root directoy
829
+     * @param View $view file view for the users root directory
830
+     * @return int
831
+     * @throws Exceptions\CopyRecursiveException
832
+     */
833
+    private static function copy_recursive($source, $destination, View $view) {
834
+        $size = 0;
835
+        if ($view->is_dir($source)) {
836
+            $view->mkdir($destination);
837
+            $view->touch($destination, $view->filemtime($source));
838
+            foreach ($view->getDirectoryContent($source) as $i) {
839
+                $pathDir = $source . '/' . $i['name'];
840
+                if ($view->is_dir($pathDir)) {
841
+                    $size += self::copy_recursive($pathDir, $destination . '/' . $i['name'], $view);
842
+                } else {
843
+                    $size += $view->filesize($pathDir);
844
+                    $result = $view->copy($pathDir, $destination . '/' . $i['name']);
845
+                    if (!$result) {
846
+                        throw new \OCA\Files_Trashbin\Exceptions\CopyRecursiveException();
847
+                    }
848
+                    $view->touch($destination . '/' . $i['name'], $view->filemtime($pathDir));
849
+                }
850
+            }
851
+        } else {
852
+            $size += $view->filesize($source);
853
+            $result = $view->copy($source, $destination);
854
+            if (!$result) {
855
+                throw new \OCA\Files_Trashbin\Exceptions\CopyRecursiveException();
856
+            }
857
+            $view->touch($destination, $view->filemtime($source));
858
+        }
859
+        return $size;
860
+    }
861
+
862
+    /**
863
+     * find all versions which belong to the file we want to restore
864
+     *
865
+     * @param string $filename name of the file which should be restored
866
+     * @param int $timestamp timestamp when the file was deleted
867
+     * @return array
868
+     */
869
+    private static function getVersionsFromTrash($filename, $timestamp, $user) {
870
+        $view = new View('/' . $user . '/files_trashbin/versions');
871
+        $versions = [];
872
+
873
+        //force rescan of versions, local storage may not have updated the cache
874
+        if (!self::$scannedVersions) {
875
+            /** @var \OC\Files\Storage\Storage $storage */
876
+            list($storage,) = $view->resolvePath('/');
877
+            $storage->getScanner()->scan('files_trashbin/versions');
878
+            self::$scannedVersions = true;
879
+        }
880
+
881
+        if ($timestamp) {
882
+            // fetch for old versions
883
+            $matches = $view->searchRaw($filename . '.v%.d' . $timestamp);
884
+            $offset = -strlen($timestamp) - 2;
885
+        } else {
886
+            $matches = $view->searchRaw($filename . '.v%');
887
+        }
888
+
889
+        if (is_array($matches)) {
890
+            foreach ($matches as $ma) {
891
+                if ($timestamp) {
892
+                    $parts = explode('.v', substr($ma['path'], 0, $offset));
893
+                    $versions[] = end($parts);
894
+                } else {
895
+                    $parts = explode('.v', $ma);
896
+                    $versions[] = end($parts);
897
+                }
898
+            }
899
+        }
900
+        return $versions;
901
+    }
902
+
903
+    /**
904
+     * find unique extension for restored file if a file with the same name already exists
905
+     *
906
+     * @param string $location where the file should be restored
907
+     * @param string $filename name of the file
908
+     * @param View $view filesystem view relative to users root directory
909
+     * @return string with unique extension
910
+     */
911
+    private static function getUniqueFilename($location, $filename, View $view) {
912
+        $ext = pathinfo($filename, PATHINFO_EXTENSION);
913
+        $name = pathinfo($filename, PATHINFO_FILENAME);
914
+        $l = \OC::$server->getL10N('files_trashbin');
915
+
916
+        $location = '/' . trim($location, '/');
917
+
918
+        // if extension is not empty we set a dot in front of it
919
+        if ($ext !== '') {
920
+            $ext = '.' . $ext;
921
+        }
922
+
923
+        if ($view->file_exists('files' . $location . '/' . $filename)) {
924
+            $i = 2;
925
+            $uniqueName = $name . " (" . $l->t("restored") . ")" . $ext;
926
+            while ($view->file_exists('files' . $location . '/' . $uniqueName)) {
927
+                $uniqueName = $name . " (" . $l->t("restored") . " " . $i . ")" . $ext;
928
+                $i++;
929
+            }
930
+
931
+            return $uniqueName;
932
+        }
933
+
934
+        return $filename;
935
+    }
936
+
937
+    /**
938
+     * get the size from a given root folder
939
+     *
940
+     * @param View $view file view on the root folder
941
+     * @return integer size of the folder
942
+     */
943
+    private static function calculateSize($view) {
944
+        $root = \OC::$server->getConfig()->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . $view->getAbsolutePath('');
945
+        if (!file_exists($root)) {
946
+            return 0;
947
+        }
948
+        $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($root), \RecursiveIteratorIterator::CHILD_FIRST);
949
+        $size = 0;
950
+
951
+        /**
952
+         * RecursiveDirectoryIterator on an NFS path isn't iterable with foreach
953
+         * This bug is fixed in PHP 5.5.9 or before
954
+         * See #8376
955
+         */
956
+        $iterator->rewind();
957
+        while ($iterator->valid()) {
958
+            $path = $iterator->current();
959
+            $relpath = substr($path, strlen($root) - 1);
960
+            if (!$view->is_dir($relpath)) {
961
+                $size += $view->filesize($relpath);
962
+            }
963
+            $iterator->next();
964
+        }
965
+        return $size;
966
+    }
967
+
968
+    /**
969
+     * get current size of trash bin from a given user
970
+     *
971
+     * @param string $user user who owns the trash bin
972
+     * @return integer trash bin size
973
+     */
974
+    private static function getTrashbinSize($user) {
975
+        $view = new View('/' . $user);
976
+        $fileInfo = $view->getFileInfo('/files_trashbin');
977
+        return isset($fileInfo['size']) ? $fileInfo['size'] : 0;
978
+    }
979
+
980
+    /**
981
+     * register hooks
982
+     */
983
+    public static function registerHooks() {
984
+        // create storage wrapper on setup
985
+        \OCP\Util::connectHook('OC_Filesystem', 'preSetup', 'OCA\Files_Trashbin\Storage', 'setupStorage');
986
+        //Listen to delete user signal
987
+        \OCP\Util::connectHook('OC_User', 'pre_deleteUser', 'OCA\Files_Trashbin\Hooks', 'deleteUser_hook');
988
+        //Listen to post write hook
989
+        \OCP\Util::connectHook('OC_Filesystem', 'post_write', 'OCA\Files_Trashbin\Hooks', 'post_write_hook');
990
+        // pre and post-rename, disable trash logic for the copy+unlink case
991
+        \OCP\Util::connectHook('OC_Filesystem', 'delete', 'OCA\Files_Trashbin\Trashbin', 'ensureFileScannedHook');
992
+    }
993
+
994
+    /**
995
+     * check if trash bin is empty for a given user
996
+     *
997
+     * @param string $user
998
+     * @return bool
999
+     */
1000
+    public static function isEmpty($user) {
1001
+
1002
+        $view = new View('/' . $user . '/files_trashbin');
1003
+        if ($view->is_dir('/files') && $dh = $view->opendir('/files')) {
1004
+            while ($file = readdir($dh)) {
1005
+                if (!Filesystem::isIgnoredDir($file)) {
1006
+                    return false;
1007
+                }
1008
+            }
1009
+        }
1010
+        return true;
1011
+    }
1012
+
1013
+    /**
1014
+     * @param $path
1015
+     * @return string
1016
+     */
1017
+    public static function preview_icon($path) {
1018
+        return \OC::$server->getURLGenerator()->linkToRoute('core_ajax_trashbin_preview', ['x' => 32, 'y' => 32, 'file' => $path]);
1019
+    }
1020 1020
 }
Please login to merge, or discard this patch.
Spacing   +73 added lines, -73 removed lines patch added patch discarded remove patch
@@ -103,7 +103,7 @@  discard block
 block discarded – undo
103 103
 		Filesystem::initMountPoints($uid);
104 104
 		if ($uid !== User::getUser()) {
105 105
 			$info = Filesystem::getFileInfo($filename);
106
-			$ownerView = new View('/' . $uid . '/files');
106
+			$ownerView = new View('/'.$uid.'/files');
107 107
 			try {
108 108
 				$filename = $ownerView->getPath($info['fileid']);
109 109
 			} catch (NotFoundException $e) {
@@ -154,7 +154,7 @@  discard block
 block discarded – undo
154 154
 	}
155 155
 
156 156
 	private static function setUpTrash($user) {
157
-		$view = new View('/' . $user);
157
+		$view = new View('/'.$user);
158 158
 		if (!$view->is_dir('files_trashbin')) {
159 159
 			$view->mkdir('files_trashbin');
160 160
 		}
@@ -189,8 +189,8 @@  discard block
 block discarded – undo
189 189
 
190 190
 		$view = new View('/');
191 191
 
192
-		$target = $user . '/files_trashbin/files/' . $targetFilename . '.d' . $timestamp;
193
-		$source = $owner . '/files_trashbin/files/' . $sourceFilename . '.d' . $timestamp;
192
+		$target = $user.'/files_trashbin/files/'.$targetFilename.'.d'.$timestamp;
193
+		$source = $owner.'/files_trashbin/files/'.$sourceFilename.'.d'.$timestamp;
194 194
 		$free = $view->free_space($target);
195 195
 		$isUnknownOrUnlimitedFreeSpace = $free < 0;
196 196
 		$isEnoughFreeSpaceLeft = $view->filesize($source) < $free;
@@ -229,9 +229,9 @@  discard block
 block discarded – undo
229 229
 			$ownerPath = $file_path;
230 230
 		}
231 231
 
232
-		$ownerView = new View('/' . $owner);
232
+		$ownerView = new View('/'.$owner);
233 233
 		// file has been deleted in between
234
-		if (is_null($ownerPath) || $ownerPath === '' || !$ownerView->file_exists('/files/' . $ownerPath)) {
234
+		if (is_null($ownerPath) || $ownerPath === '' || !$ownerView->file_exists('/files/'.$ownerPath)) {
235 235
 			return true;
236 236
 		}
237 237
 
@@ -248,12 +248,12 @@  discard block
 block discarded – undo
248 248
 		$timestamp = time();
249 249
 
250 250
 		// disable proxy to prevent recursive calls
251
-		$trashPath = '/files_trashbin/files/' . $filename . '.d' . $timestamp;
251
+		$trashPath = '/files_trashbin/files/'.$filename.'.d'.$timestamp;
252 252
 
253 253
 		/** @var \OC\Files\Storage\Storage $trashStorage */
254 254
 		list($trashStorage, $trashInternalPath) = $ownerView->resolvePath($trashPath);
255 255
 		/** @var \OC\Files\Storage\Storage $sourceStorage */
256
-		list($sourceStorage, $sourceInternalPath) = $ownerView->resolvePath('/files/' . $ownerPath);
256
+		list($sourceStorage, $sourceInternalPath) = $ownerView->resolvePath('/files/'.$ownerPath);
257 257
 		try {
258 258
 			$moveSuccessful = true;
259 259
 			if ($trashStorage->file_exists($trashInternalPath)) {
@@ -265,7 +265,7 @@  discard block
 block discarded – undo
265 265
 			if ($trashStorage->file_exists($trashInternalPath)) {
266 266
 				$trashStorage->unlink($trashInternalPath);
267 267
 			}
268
-			\OC::$server->getLogger()->error('Couldn\'t move ' . $file_path . ' to the trash bin', ['app' => 'files_trashbin']);
268
+			\OC::$server->getLogger()->error('Couldn\'t move '.$file_path.' to the trash bin', ['app' => 'files_trashbin']);
269 269
 		}
270 270
 
271 271
 		if ($sourceStorage->file_exists($sourceInternalPath)) { // failed to delete the original file, abort
@@ -286,7 +286,7 @@  discard block
 block discarded – undo
286 286
 				\OC::$server->getLogger()->error('trash bin database couldn\'t be updated', ['app' => 'files_trashbin']);
287 287
 			}
288 288
 			\OCP\Util::emitHook('\OCA\Files_Trashbin\Trashbin', 'post_moveToTrash', ['filePath' => Filesystem::normalizePath($file_path),
289
-				'trashPath' => Filesystem::normalizePath($filename . '.d' . $timestamp)]);
289
+				'trashPath' => Filesystem::normalizePath($filename.'.d'.$timestamp)]);
290 290
 
291 291
 			self::retainVersions($filename, $owner, $ownerPath, $timestamp);
292 292
 
@@ -320,18 +320,18 @@  discard block
 block discarded – undo
320 320
 			$user = User::getUser();
321 321
 			$rootView = new View('/');
322 322
 
323
-			if ($rootView->is_dir($owner . '/files_versions/' . $ownerPath)) {
323
+			if ($rootView->is_dir($owner.'/files_versions/'.$ownerPath)) {
324 324
 				if ($owner !== $user) {
325
-					self::copy_recursive($owner . '/files_versions/' . $ownerPath, $owner . '/files_trashbin/versions/' . basename($ownerPath) . '.d' . $timestamp, $rootView);
325
+					self::copy_recursive($owner.'/files_versions/'.$ownerPath, $owner.'/files_trashbin/versions/'.basename($ownerPath).'.d'.$timestamp, $rootView);
326 326
 				}
327
-				self::move($rootView, $owner . '/files_versions/' . $ownerPath, $user . '/files_trashbin/versions/' . $filename . '.d' . $timestamp);
327
+				self::move($rootView, $owner.'/files_versions/'.$ownerPath, $user.'/files_trashbin/versions/'.$filename.'.d'.$timestamp);
328 328
 			} else if ($versions = \OCA\Files_Versions\Storage::getVersions($owner, $ownerPath)) {
329 329
 
330 330
 				foreach ($versions as $v) {
331 331
 					if ($owner !== $user) {
332
-						self::copy($rootView, $owner . '/files_versions' . $v['path'] . '.v' . $v['version'], $owner . '/files_trashbin/versions/' . $v['name'] . '.v' . $v['version'] . '.d' . $timestamp);
332
+						self::copy($rootView, $owner.'/files_versions'.$v['path'].'.v'.$v['version'], $owner.'/files_trashbin/versions/'.$v['name'].'.v'.$v['version'].'.d'.$timestamp);
333 333
 					}
334
-					self::move($rootView, $owner . '/files_versions' . $v['path'] . '.v' . $v['version'], $user . '/files_trashbin/versions/' . $filename . '.v' . $v['version'] . '.d' . $timestamp);
334
+					self::move($rootView, $owner.'/files_versions'.$v['path'].'.v'.$v['version'], $user.'/files_trashbin/versions/'.$filename.'.v'.$v['version'].'.d'.$timestamp);
335 335
 				}
336 336
 			}
337 337
 		}
@@ -393,18 +393,18 @@  discard block
 block discarded – undo
393 393
 	 */
394 394
 	public static function restore($file, $filename, $timestamp) {
395 395
 		$user = User::getUser();
396
-		$view = new View('/' . $user);
396
+		$view = new View('/'.$user);
397 397
 
398 398
 		$location = '';
399 399
 		if ($timestamp) {
400 400
 			$location = self::getLocation($user, $filename, $timestamp);
401 401
 			if ($location === false) {
402
-				\OC::$server->getLogger()->error('trash bin database inconsistent! ($user: ' . $user . ' $filename: ' . $filename . ', $timestamp: ' . $timestamp . ')', ['app' => 'files_trashbin']);
402
+				\OC::$server->getLogger()->error('trash bin database inconsistent! ($user: '.$user.' $filename: '.$filename.', $timestamp: '.$timestamp.')', ['app' => 'files_trashbin']);
403 403
 			} else {
404 404
 				// if location no longer exists, restore file in the root directory
405 405
 				if ($location !== '/' &&
406
-					(!$view->is_dir('files/' . $location) ||
407
-						!$view->isCreatable('files/' . $location))
406
+					(!$view->is_dir('files/'.$location) ||
407
+						!$view->isCreatable('files/'.$location))
408 408
 				) {
409 409
 					$location = '';
410 410
 				}
@@ -414,8 +414,8 @@  discard block
 block discarded – undo
414 414
 		// we need a  extension in case a file/dir with the same name already exists
415 415
 		$uniqueFilename = self::getUniqueFilename($location, $filename, $view);
416 416
 
417
-		$source = Filesystem::normalizePath('files_trashbin/files/' . $file);
418
-		$target = Filesystem::normalizePath('files/' . $location . '/' . $uniqueFilename);
417
+		$source = Filesystem::normalizePath('files_trashbin/files/'.$file);
418
+		$target = Filesystem::normalizePath('files/'.$location.'/'.$uniqueFilename);
419 419
 		if (!$view->file_exists($source)) {
420 420
 			return false;
421 421
 		}
@@ -430,10 +430,10 @@  discard block
 block discarded – undo
430 430
 		// handle the restore result
431 431
 		if ($restoreResult) {
432 432
 			$fakeRoot = $view->getRoot();
433
-			$view->chroot('/' . $user . '/files');
434
-			$view->touch('/' . $location . '/' . $uniqueFilename, $mtime);
433
+			$view->chroot('/'.$user.'/files');
434
+			$view->touch('/'.$location.'/'.$uniqueFilename, $mtime);
435 435
 			$view->chroot($fakeRoot);
436
-			\OCP\Util::emitHook('\OCA\Files_Trashbin\Trashbin', 'post_restore', ['filePath' => Filesystem::normalizePath('/' . $location . '/' . $uniqueFilename),
436
+			\OCP\Util::emitHook('\OCA\Files_Trashbin\Trashbin', 'post_restore', ['filePath' => Filesystem::normalizePath('/'.$location.'/'.$uniqueFilename),
437 437
 				'trashPath' => Filesystem::normalizePath($file)]);
438 438
 
439 439
 			self::restoreVersions($view, $file, $filename, $uniqueFilename, $location, $timestamp);
@@ -467,7 +467,7 @@  discard block
 block discarded – undo
467 467
 			$user = User::getUser();
468 468
 			$rootView = new View('/');
469 469
 
470
-			$target = Filesystem::normalizePath('/' . $location . '/' . $uniqueFilename);
470
+			$target = Filesystem::normalizePath('/'.$location.'/'.$uniqueFilename);
471 471
 
472 472
 			list($owner, $ownerPath) = self::getUidAndFilename($target);
473 473
 
@@ -482,14 +482,14 @@  discard block
 block discarded – undo
482 482
 				$versionedFile = $file;
483 483
 			}
484 484
 
485
-			if ($view->is_dir('/files_trashbin/versions/' . $file)) {
486
-				$rootView->rename(Filesystem::normalizePath($user . '/files_trashbin/versions/' . $file), Filesystem::normalizePath($owner . '/files_versions/' . $ownerPath));
485
+			if ($view->is_dir('/files_trashbin/versions/'.$file)) {
486
+				$rootView->rename(Filesystem::normalizePath($user.'/files_trashbin/versions/'.$file), Filesystem::normalizePath($owner.'/files_versions/'.$ownerPath));
487 487
 			} else if ($versions = self::getVersionsFromTrash($versionedFile, $timestamp, $user)) {
488 488
 				foreach ($versions as $v) {
489 489
 					if ($timestamp) {
490
-						$rootView->rename($user . '/files_trashbin/versions/' . $versionedFile . '.v' . $v . '.d' . $timestamp, $owner . '/files_versions/' . $ownerPath . '.v' . $v);
490
+						$rootView->rename($user.'/files_trashbin/versions/'.$versionedFile.'.v'.$v.'.d'.$timestamp, $owner.'/files_versions/'.$ownerPath.'.v'.$v);
491 491
 					} else {
492
-						$rootView->rename($user . '/files_trashbin/versions/' . $versionedFile . '.v' . $v, $owner . '/files_versions/' . $ownerPath . '.v' . $v);
492
+						$rootView->rename($user.'/files_trashbin/versions/'.$versionedFile.'.v'.$v, $owner.'/files_versions/'.$ownerPath.'.v'.$v);
493 493
 					}
494 494
 				}
495 495
 			}
@@ -502,7 +502,7 @@  discard block
 block discarded – undo
502 502
 	public static function deleteAll() {
503 503
 		$user = User::getUser();
504 504
 		$userRoot = \OC::$server->getUserFolder($user)->getParent();
505
-		$view = new View('/' . $user);
505
+		$view = new View('/'.$user);
506 506
 		$fileInfos = $view->getDirectoryContent('files_trashbin/files');
507 507
 
508 508
 		try {
@@ -513,7 +513,7 @@  discard block
 block discarded – undo
513 513
 
514 514
 		// Array to store the relative path in (after the file is deleted, the view won't be able to relativise the path anymore)
515 515
 		$filePaths = [];
516
-		foreach($fileInfos as $fileInfo){
516
+		foreach ($fileInfos as $fileInfo) {
517 517
 			$filePaths[] = $view->getRelativePath($fileInfo->getPath());
518 518
 		}
519 519
 		unset($fileInfos); // save memory
@@ -522,7 +522,7 @@  discard block
 block discarded – undo
522 522
 		\OC_Hook::emit('\OCP\Trashbin', 'preDeleteAll', ['paths' => $filePaths]);
523 523
 
524 524
 		// Single-File Hooks
525
-		foreach($filePaths as $path){
525
+		foreach ($filePaths as $path) {
526 526
 			self::emitTrashbinPreDelete($path);
527 527
 		}
528 528
 
@@ -535,7 +535,7 @@  discard block
 block discarded – undo
535 535
 		\OC_Hook::emit('\OCP\Trashbin', 'deleteAll', ['paths' => $filePaths]);
536 536
 
537 537
 		// Single-File Hooks
538
-		foreach($filePaths as $path){
538
+		foreach ($filePaths as $path) {
539 539
 			self::emitTrashbinPostDelete($path);
540 540
 		}
541 541
 
@@ -549,7 +549,7 @@  discard block
 block discarded – undo
549 549
 	 * wrapper function to emit the 'preDelete' hook of \OCP\Trashbin before a file is deleted
550 550
 	 * @param string $path
551 551
 	 */
552
-	protected static function emitTrashbinPreDelete($path){
552
+	protected static function emitTrashbinPreDelete($path) {
553 553
 		\OC_Hook::emit('\OCP\Trashbin', 'preDelete', ['path' => $path]);
554 554
 	}
555 555
 
@@ -557,7 +557,7 @@  discard block
 block discarded – undo
557 557
 	 * wrapper function to emit the 'delete' hook of \OCP\Trashbin after a file has been deleted
558 558
 	 * @param string $path
559 559
 	 */
560
-	protected static function emitTrashbinPostDelete($path){
560
+	protected static function emitTrashbinPostDelete($path) {
561 561
 		\OC_Hook::emit('\OCP\Trashbin', 'delete', ['path' => $path]);
562 562
 	}
563 563
 
@@ -572,13 +572,13 @@  discard block
 block discarded – undo
572 572
 	 */
573 573
 	public static function delete($filename, $user, $timestamp = null) {
574 574
 		$userRoot = \OC::$server->getUserFolder($user)->getParent();
575
-		$view = new View('/' . $user);
575
+		$view = new View('/'.$user);
576 576
 		$size = 0;
577 577
 
578 578
 		if ($timestamp) {
579 579
 			$query = \OC_DB::prepare('DELETE FROM `*PREFIX*files_trash` WHERE `user`=? AND `id`=? AND `timestamp`=?');
580 580
 			$query->execute([$user, $filename, $timestamp]);
581
-			$file = $filename . '.d' . $timestamp;
581
+			$file = $filename.'.d'.$timestamp;
582 582
 		} else {
583 583
 			$file = $filename;
584 584
 		}
@@ -586,20 +586,20 @@  discard block
 block discarded – undo
586 586
 		$size += self::deleteVersions($view, $file, $filename, $timestamp, $user);
587 587
 
588 588
 		try {
589
-			$node = $userRoot->get('/files_trashbin/files/' . $file);
589
+			$node = $userRoot->get('/files_trashbin/files/'.$file);
590 590
 		} catch (NotFoundException $e) {
591 591
 			return $size;
592 592
 		}
593 593
 
594 594
 		if ($node instanceof Folder) {
595
-			$size += self::calculateSize(new View('/' . $user . '/files_trashbin/files/' . $file));
595
+			$size += self::calculateSize(new View('/'.$user.'/files_trashbin/files/'.$file));
596 596
 		} else if ($node instanceof File) {
597
-			$size += $view->filesize('/files_trashbin/files/' . $file);
597
+			$size += $view->filesize('/files_trashbin/files/'.$file);
598 598
 		}
599 599
 
600
-		self::emitTrashbinPreDelete('/files_trashbin/files/' . $file);
600
+		self::emitTrashbinPreDelete('/files_trashbin/files/'.$file);
601 601
 		$node->delete();
602
-		self::emitTrashbinPostDelete('/files_trashbin/files/' . $file);
602
+		self::emitTrashbinPostDelete('/files_trashbin/files/'.$file);
603 603
 
604 604
 		return $size;
605 605
 	}
@@ -615,17 +615,17 @@  discard block
 block discarded – undo
615 615
 	private static function deleteVersions(View $view, $file, $filename, $timestamp, $user) {
616 616
 		$size = 0;
617 617
 		if (\OCP\App::isEnabled('files_versions')) {
618
-			if ($view->is_dir('files_trashbin/versions/' . $file)) {
619
-				$size += self::calculateSize(new View('/' . $user . '/files_trashbin/versions/' . $file));
620
-				$view->unlink('files_trashbin/versions/' . $file);
618
+			if ($view->is_dir('files_trashbin/versions/'.$file)) {
619
+				$size += self::calculateSize(new View('/'.$user.'/files_trashbin/versions/'.$file));
620
+				$view->unlink('files_trashbin/versions/'.$file);
621 621
 			} else if ($versions = self::getVersionsFromTrash($filename, $timestamp, $user)) {
622 622
 				foreach ($versions as $v) {
623 623
 					if ($timestamp) {
624
-						$size += $view->filesize('/files_trashbin/versions/' . $filename . '.v' . $v . '.d' . $timestamp);
625
-						$view->unlink('/files_trashbin/versions/' . $filename . '.v' . $v . '.d' . $timestamp);
624
+						$size += $view->filesize('/files_trashbin/versions/'.$filename.'.v'.$v.'.d'.$timestamp);
625
+						$view->unlink('/files_trashbin/versions/'.$filename.'.v'.$v.'.d'.$timestamp);
626 626
 					} else {
627
-						$size += $view->filesize('/files_trashbin/versions/' . $filename . '.v' . $v);
628
-						$view->unlink('/files_trashbin/versions/' . $filename . '.v' . $v);
627
+						$size += $view->filesize('/files_trashbin/versions/'.$filename.'.v'.$v);
628
+						$view->unlink('/files_trashbin/versions/'.$filename.'.v'.$v);
629 629
 					}
630 630
 				}
631 631
 			}
@@ -642,13 +642,13 @@  discard block
 block discarded – undo
642 642
 	 */
643 643
 	public static function file_exists($filename, $timestamp = null) {
644 644
 		$user = User::getUser();
645
-		$view = new View('/' . $user);
645
+		$view = new View('/'.$user);
646 646
 
647 647
 		if ($timestamp) {
648
-			$filename = $filename . '.d' . $timestamp;
648
+			$filename = $filename.'.d'.$timestamp;
649 649
 		}
650 650
 
651
-		$target = Filesystem::normalizePath('files_trashbin/files/' . $filename);
651
+		$target = Filesystem::normalizePath('files_trashbin/files/'.$filename);
652 652
 		return $view->file_exists($target);
653 653
 	}
654 654
 
@@ -673,7 +673,7 @@  discard block
 block discarded – undo
673 673
 	private static function calculateFreeSpace($trashbinSize, $user) {
674 674
 		$softQuota = true;
675 675
 		$userObject = \OC::$server->getUserManager()->get($user);
676
-		if(is_null($userObject)) {
676
+		if (is_null($userObject)) {
677 677
 			return 0;
678 678
 		}
679 679
 		$quota = $userObject->getQuota();
@@ -692,7 +692,7 @@  discard block
 block discarded – undo
692 692
 		// subtract size of files and current trash bin size from quota
693 693
 		if ($softQuota) {
694 694
 			$userFolder = \OC::$server->getUserFolder($user);
695
-			if(is_null($userFolder)) {
695
+			if (is_null($userFolder)) {
696 696
 				return 0;
697 697
 			}
698 698
 			$free = $quota - $userFolder->getSize(false); // remaining free space for user
@@ -776,7 +776,7 @@  discard block
 block discarded – undo
776 776
 			foreach ($files as $file) {
777 777
 				if ($availableSpace < 0 && $expiration->isExpired($file['mtime'], true)) {
778 778
 					$tmp = self::delete($file['name'], $user, $file['mtime']);
779
-					\OC::$server->getLogger()->info('remove "' . $file['name'] . '" (' . $tmp . 'B) to meet the limit of trash bin size (50% of available quota)', ['app' => 'files_trashbin']);
779
+					\OC::$server->getLogger()->info('remove "'.$file['name'].'" ('.$tmp.'B) to meet the limit of trash bin size (50% of available quota)', ['app' => 'files_trashbin']);
780 780
 					$availableSpace += $tmp;
781 781
 					$size += $tmp;
782 782
 				} else {
@@ -807,10 +807,10 @@  discard block
 block discarded – undo
807 807
 					$size += self::delete($filename, $user, $timestamp);
808 808
 					$count++;
809 809
 				} catch (\OCP\Files\NotPermittedException $e) {
810
-					\OC::$server->getLogger()->logException($e, ['app' => 'files_trashbin', 'level' => \OCP\ILogger::WARN, 'message' => 'Removing "' . $filename . '" from trashbin failed.']);
810
+					\OC::$server->getLogger()->logException($e, ['app' => 'files_trashbin', 'level' => \OCP\ILogger::WARN, 'message' => 'Removing "'.$filename.'" from trashbin failed.']);
811 811
 				}
812 812
 				\OC::$server->getLogger()->info(
813
-					'Remove "' . $filename . '" from trashbin because it exceeds max retention obligation term.',
813
+					'Remove "'.$filename.'" from trashbin because it exceeds max retention obligation term.',
814 814
 					['app' => 'files_trashbin']
815 815
 				);
816 816
 			} else {
@@ -836,16 +836,16 @@  discard block
 block discarded – undo
836 836
 			$view->mkdir($destination);
837 837
 			$view->touch($destination, $view->filemtime($source));
838 838
 			foreach ($view->getDirectoryContent($source) as $i) {
839
-				$pathDir = $source . '/' . $i['name'];
839
+				$pathDir = $source.'/'.$i['name'];
840 840
 				if ($view->is_dir($pathDir)) {
841
-					$size += self::copy_recursive($pathDir, $destination . '/' . $i['name'], $view);
841
+					$size += self::copy_recursive($pathDir, $destination.'/'.$i['name'], $view);
842 842
 				} else {
843 843
 					$size += $view->filesize($pathDir);
844
-					$result = $view->copy($pathDir, $destination . '/' . $i['name']);
844
+					$result = $view->copy($pathDir, $destination.'/'.$i['name']);
845 845
 					if (!$result) {
846 846
 						throw new \OCA\Files_Trashbin\Exceptions\CopyRecursiveException();
847 847
 					}
848
-					$view->touch($destination . '/' . $i['name'], $view->filemtime($pathDir));
848
+					$view->touch($destination.'/'.$i['name'], $view->filemtime($pathDir));
849 849
 				}
850 850
 			}
851 851
 		} else {
@@ -867,7 +867,7 @@  discard block
 block discarded – undo
867 867
 	 * @return array
868 868
 	 */
869 869
 	private static function getVersionsFromTrash($filename, $timestamp, $user) {
870
-		$view = new View('/' . $user . '/files_trashbin/versions');
870
+		$view = new View('/'.$user.'/files_trashbin/versions');
871 871
 		$versions = [];
872 872
 
873 873
 		//force rescan of versions, local storage may not have updated the cache
@@ -880,10 +880,10 @@  discard block
 block discarded – undo
880 880
 
881 881
 		if ($timestamp) {
882 882
 			// fetch for old versions
883
-			$matches = $view->searchRaw($filename . '.v%.d' . $timestamp);
883
+			$matches = $view->searchRaw($filename.'.v%.d'.$timestamp);
884 884
 			$offset = -strlen($timestamp) - 2;
885 885
 		} else {
886
-			$matches = $view->searchRaw($filename . '.v%');
886
+			$matches = $view->searchRaw($filename.'.v%');
887 887
 		}
888 888
 
889 889
 		if (is_array($matches)) {
@@ -913,18 +913,18 @@  discard block
 block discarded – undo
913 913
 		$name = pathinfo($filename, PATHINFO_FILENAME);
914 914
 		$l = \OC::$server->getL10N('files_trashbin');
915 915
 
916
-		$location = '/' . trim($location, '/');
916
+		$location = '/'.trim($location, '/');
917 917
 
918 918
 		// if extension is not empty we set a dot in front of it
919 919
 		if ($ext !== '') {
920
-			$ext = '.' . $ext;
920
+			$ext = '.'.$ext;
921 921
 		}
922 922
 
923
-		if ($view->file_exists('files' . $location . '/' . $filename)) {
923
+		if ($view->file_exists('files'.$location.'/'.$filename)) {
924 924
 			$i = 2;
925
-			$uniqueName = $name . " (" . $l->t("restored") . ")" . $ext;
926
-			while ($view->file_exists('files' . $location . '/' . $uniqueName)) {
927
-				$uniqueName = $name . " (" . $l->t("restored") . " " . $i . ")" . $ext;
925
+			$uniqueName = $name." (".$l->t("restored").")".$ext;
926
+			while ($view->file_exists('files'.$location.'/'.$uniqueName)) {
927
+				$uniqueName = $name." (".$l->t("restored")." ".$i.")".$ext;
928 928
 				$i++;
929 929
 			}
930 930
 
@@ -941,7 +941,7 @@  discard block
 block discarded – undo
941 941
 	 * @return integer size of the folder
942 942
 	 */
943 943
 	private static function calculateSize($view) {
944
-		$root = \OC::$server->getConfig()->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . $view->getAbsolutePath('');
944
+		$root = \OC::$server->getConfig()->getSystemValue('datadirectory', \OC::$SERVERROOT.'/data').$view->getAbsolutePath('');
945 945
 		if (!file_exists($root)) {
946 946
 			return 0;
947 947
 		}
@@ -972,7 +972,7 @@  discard block
 block discarded – undo
972 972
 	 * @return integer trash bin size
973 973
 	 */
974 974
 	private static function getTrashbinSize($user) {
975
-		$view = new View('/' . $user);
975
+		$view = new View('/'.$user);
976 976
 		$fileInfo = $view->getFileInfo('/files_trashbin');
977 977
 		return isset($fileInfo['size']) ? $fileInfo['size'] : 0;
978 978
 	}
@@ -999,7 +999,7 @@  discard block
 block discarded – undo
999 999
 	 */
1000 1000
 	public static function isEmpty($user) {
1001 1001
 
1002
-		$view = new View('/' . $user . '/files_trashbin');
1002
+		$view = new View('/'.$user.'/files_trashbin');
1003 1003
 		if ($view->is_dir('/files') && $dh = $view->opendir('/files')) {
1004 1004
 			while ($file = readdir($dh)) {
1005 1005
 				if (!Filesystem::isIgnoredDir($file)) {
Please login to merge, or discard this patch.
apps/files_trashbin/lib/Helper.php 2 patches
Indentation   +85 added lines, -85 removed lines patch added patch discarded remove patch
@@ -35,96 +35,96 @@
 block discarded – undo
35 35
 use OCP\Files\Cache\ICacheEntry;
36 36
 
37 37
 class Helper {
38
-	/**
39
-	 * Retrieves the contents of a trash bin directory.
40
-	 *
41
-	 * @param string $dir path to the directory inside the trashbin
42
-	 * or empty to retrieve the root of the trashbin
43
-	 * @param string $user
44
-	 * @param string $sortAttribute attribute to sort on or empty to disable sorting
45
-	 * @param bool $sortDescending true for descending sort, false otherwise
46
-	 * @return \OCP\Files\FileInfo[]
47
-	 */
48
-	public static function getTrashFiles($dir, $user, $sortAttribute = '', $sortDescending = false) {
49
-		$result = [];
50
-		$timestamp = null;
38
+    /**
39
+     * Retrieves the contents of a trash bin directory.
40
+     *
41
+     * @param string $dir path to the directory inside the trashbin
42
+     * or empty to retrieve the root of the trashbin
43
+     * @param string $user
44
+     * @param string $sortAttribute attribute to sort on or empty to disable sorting
45
+     * @param bool $sortDescending true for descending sort, false otherwise
46
+     * @return \OCP\Files\FileInfo[]
47
+     */
48
+    public static function getTrashFiles($dir, $user, $sortAttribute = '', $sortDescending = false) {
49
+        $result = [];
50
+        $timestamp = null;
51 51
 
52
-		$view = new \OC\Files\View('/' . $user . '/files_trashbin/files');
52
+        $view = new \OC\Files\View('/' . $user . '/files_trashbin/files');
53 53
 
54
-		if (ltrim($dir, '/') !== '' && !$view->is_dir($dir)) {
55
-			throw new \Exception('Directory does not exists');
56
-		}
54
+        if (ltrim($dir, '/') !== '' && !$view->is_dir($dir)) {
55
+            throw new \Exception('Directory does not exists');
56
+        }
57 57
 
58
-		$mount = $view->getMount($dir);
59
-		$storage = $mount->getStorage();
60
-		$absoluteDir = $view->getAbsolutePath($dir);
61
-		$internalPath = $mount->getInternalPath($absoluteDir);
58
+        $mount = $view->getMount($dir);
59
+        $storage = $mount->getStorage();
60
+        $absoluteDir = $view->getAbsolutePath($dir);
61
+        $internalPath = $mount->getInternalPath($absoluteDir);
62 62
 
63
-		$originalLocations = \OCA\Files_Trashbin\Trashbin::getLocations($user);
64
-		$dirContent = $storage->getCache()->getFolderContents($mount->getInternalPath($view->getAbsolutePath($dir)));
65
-		foreach ($dirContent as $entry) {
66
-			$entryName = $entry->getName();
67
-			$name = $entryName;
68
-			if ($dir === '' || $dir === '/') {
69
-				$pathparts = pathinfo($entryName);
70
-				$timestamp = substr($pathparts['extension'], 1);
71
-				$name = $pathparts['filename'];
63
+        $originalLocations = \OCA\Files_Trashbin\Trashbin::getLocations($user);
64
+        $dirContent = $storage->getCache()->getFolderContents($mount->getInternalPath($view->getAbsolutePath($dir)));
65
+        foreach ($dirContent as $entry) {
66
+            $entryName = $entry->getName();
67
+            $name = $entryName;
68
+            if ($dir === '' || $dir === '/') {
69
+                $pathparts = pathinfo($entryName);
70
+                $timestamp = substr($pathparts['extension'], 1);
71
+                $name = $pathparts['filename'];
72 72
 
73
-			} else if ($timestamp === null) {
74
-				// for subfolders we need to calculate the timestamp only once
75
-				$parts = explode('/', ltrim($dir, '/'));
76
-				$timestamp = substr(pathinfo($parts[0], PATHINFO_EXTENSION), 1);
77
-			}
78
-			$originalPath = '';
79
-			$originalName = substr($entryName, 0, -strlen($timestamp)-2);
80
-			if (isset($originalLocations[$originalName][$timestamp])) {
81
-				$originalPath = $originalLocations[$originalName][$timestamp];
82
-				if (substr($originalPath, -1) === '/') {
83
-					$originalPath = substr($originalPath, 0, -1);
84
-				}
85
-			}
86
-			$type = $entry->getMimeType() === ICacheEntry::DIRECTORY_MIMETYPE ? 'dir' : 'file';
87
-			$i = [
88
-				'name' => $name,
89
-				'mtime' => $timestamp,
90
-				'mimetype' => $type === 'dir' ? 'httpd/unix-directory' : \OC::$server->getMimeTypeDetector()->detectPath($name),
91
-				'type' => $type,
92
-				'directory' => ($dir === '/') ? '' : $dir,
93
-				'size' => $entry->getSize(),
94
-				'etag' => '',
95
-				'permissions' => Constants::PERMISSION_ALL - Constants::PERMISSION_SHARE,
96
-				'fileid' => $entry->getId(),
97
-			];
98
-			if ($originalPath) {
99
-				if ($originalPath !== '.') {
100
-					$i['extraData'] = $originalPath . '/' . $originalName;
101
-				} else {
102
-					$i['extraData'] = $originalName;
103
-				}
104
-			}
105
-			$result[] = new FileInfo($absoluteDir . '/' . $i['name'], $storage, $internalPath . '/' . $i['name'], $i, $mount);
106
-		}
73
+            } else if ($timestamp === null) {
74
+                // for subfolders we need to calculate the timestamp only once
75
+                $parts = explode('/', ltrim($dir, '/'));
76
+                $timestamp = substr(pathinfo($parts[0], PATHINFO_EXTENSION), 1);
77
+            }
78
+            $originalPath = '';
79
+            $originalName = substr($entryName, 0, -strlen($timestamp)-2);
80
+            if (isset($originalLocations[$originalName][$timestamp])) {
81
+                $originalPath = $originalLocations[$originalName][$timestamp];
82
+                if (substr($originalPath, -1) === '/') {
83
+                    $originalPath = substr($originalPath, 0, -1);
84
+                }
85
+            }
86
+            $type = $entry->getMimeType() === ICacheEntry::DIRECTORY_MIMETYPE ? 'dir' : 'file';
87
+            $i = [
88
+                'name' => $name,
89
+                'mtime' => $timestamp,
90
+                'mimetype' => $type === 'dir' ? 'httpd/unix-directory' : \OC::$server->getMimeTypeDetector()->detectPath($name),
91
+                'type' => $type,
92
+                'directory' => ($dir === '/') ? '' : $dir,
93
+                'size' => $entry->getSize(),
94
+                'etag' => '',
95
+                'permissions' => Constants::PERMISSION_ALL - Constants::PERMISSION_SHARE,
96
+                'fileid' => $entry->getId(),
97
+            ];
98
+            if ($originalPath) {
99
+                if ($originalPath !== '.') {
100
+                    $i['extraData'] = $originalPath . '/' . $originalName;
101
+                } else {
102
+                    $i['extraData'] = $originalName;
103
+                }
104
+            }
105
+            $result[] = new FileInfo($absoluteDir . '/' . $i['name'], $storage, $internalPath . '/' . $i['name'], $i, $mount);
106
+        }
107 107
 
108
-		if ($sortAttribute !== '') {
109
-			return \OCA\Files\Helper::sortFiles($result, $sortAttribute, $sortDescending);
110
-		}
111
-		return $result;
112
-	}
108
+        if ($sortAttribute !== '') {
109
+            return \OCA\Files\Helper::sortFiles($result, $sortAttribute, $sortDescending);
110
+        }
111
+        return $result;
112
+    }
113 113
 
114
-	/**
115
-	 * Format file infos for JSON
116
-	 *
117
-	 * @param \OCP\Files\FileInfo[] $fileInfos file infos
118
-	 */
119
-	public static function formatFileInfos($fileInfos) {
120
-		$files = [];
121
-		foreach ($fileInfos as $i) {
122
-			$entry = \OCA\Files\Helper::formatFileInfo($i);
123
-			$entry['id'] = $i->getId();
124
-			$entry['etag'] = $entry['mtime']; // add fake etag, it is only needed to identify the preview image
125
-			$entry['permissions'] = \OCP\Constants::PERMISSION_READ;
126
-			$files[] = $entry;
127
-		}
128
-		return $files;
129
-	}
114
+    /**
115
+     * Format file infos for JSON
116
+     *
117
+     * @param \OCP\Files\FileInfo[] $fileInfos file infos
118
+     */
119
+    public static function formatFileInfos($fileInfos) {
120
+        $files = [];
121
+        foreach ($fileInfos as $i) {
122
+            $entry = \OCA\Files\Helper::formatFileInfo($i);
123
+            $entry['id'] = $i->getId();
124
+            $entry['etag'] = $entry['mtime']; // add fake etag, it is only needed to identify the preview image
125
+            $entry['permissions'] = \OCP\Constants::PERMISSION_READ;
126
+            $files[] = $entry;
127
+        }
128
+        return $files;
129
+    }
130 130
 }
Please login to merge, or discard this patch.
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -49,7 +49,7 @@  discard block
 block discarded – undo
49 49
 		$result = [];
50 50
 		$timestamp = null;
51 51
 
52
-		$view = new \OC\Files\View('/' . $user . '/files_trashbin/files');
52
+		$view = new \OC\Files\View('/'.$user.'/files_trashbin/files');
53 53
 
54 54
 		if (ltrim($dir, '/') !== '' && !$view->is_dir($dir)) {
55 55
 			throw new \Exception('Directory does not exists');
@@ -76,7 +76,7 @@  discard block
 block discarded – undo
76 76
 				$timestamp = substr(pathinfo($parts[0], PATHINFO_EXTENSION), 1);
77 77
 			}
78 78
 			$originalPath = '';
79
-			$originalName = substr($entryName, 0, -strlen($timestamp)-2);
79
+			$originalName = substr($entryName, 0, -strlen($timestamp) - 2);
80 80
 			if (isset($originalLocations[$originalName][$timestamp])) {
81 81
 				$originalPath = $originalLocations[$originalName][$timestamp];
82 82
 				if (substr($originalPath, -1) === '/') {
@@ -97,12 +97,12 @@  discard block
 block discarded – undo
97 97
 			];
98 98
 			if ($originalPath) {
99 99
 				if ($originalPath !== '.') {
100
-					$i['extraData'] = $originalPath . '/' . $originalName;
100
+					$i['extraData'] = $originalPath.'/'.$originalName;
101 101
 				} else {
102 102
 					$i['extraData'] = $originalName;
103 103
 				}
104 104
 			}
105
-			$result[] = new FileInfo($absoluteDir . '/' . $i['name'], $storage, $internalPath . '/' . $i['name'], $i, $mount);
105
+			$result[] = new FileInfo($absoluteDir.'/'.$i['name'], $storage, $internalPath.'/'.$i['name'], $i, $mount);
106 106
 		}
107 107
 
108 108
 		if ($sortAttribute !== '') {
Please login to merge, or discard this patch.
apps/settings/lib/Settings/Personal/PersonalInfo.php 1 patch
Indentation   +242 added lines, -242 removed lines patch added patch discarded remove patch
@@ -47,247 +47,247 @@
 block discarded – undo
47 47
 
48 48
 class PersonalInfo implements ISettings {
49 49
 
50
-	/** @var IConfig */
51
-	private $config;
52
-	/** @var IUserManager */
53
-	private $userManager;
54
-	/** @var AccountManager */
55
-	private $accountManager;
56
-	/** @var IGroupManager */
57
-	private $groupManager;
58
-	/** @var IAppManager */
59
-	private $appManager;
60
-	/** @var IFactory */
61
-	private $l10nFactory;
62
-	/** @var IL10N */
63
-	private $l;
64
-
65
-	/**
66
-	 * @param IConfig $config
67
-	 * @param IUserManager $userManager
68
-	 * @param IGroupManager $groupManager
69
-	 * @param AccountManager $accountManager
70
-	 * @param IFactory $l10nFactory
71
-	 * @param IL10N $l
72
-	 */
73
-	public function __construct(
74
-		IConfig $config,
75
-		IUserManager $userManager,
76
-		IGroupManager $groupManager,
77
-		AccountManager $accountManager,
78
-		IAppManager $appManager,
79
-		IFactory $l10nFactory,
80
-		IL10N $l
81
-	) {
82
-		$this->config = $config;
83
-		$this->userManager = $userManager;
84
-		$this->accountManager = $accountManager;
85
-		$this->groupManager = $groupManager;
86
-		$this->appManager = $appManager;
87
-		$this->l10nFactory = $l10nFactory;
88
-		$this->l = $l;
89
-	}
90
-
91
-	/**
92
-	 * @return TemplateResponse returns the instance with all parameters set, ready to be rendered
93
-	 * @since 9.1
94
-	 */
95
-	public function getForm() {
96
-		$federatedFileSharingEnabled = $this->appManager->isEnabledForUser('federatedfilesharing');
97
-		$lookupServerUploadEnabled = false;
98
-		if($federatedFileSharingEnabled) {
99
-			$federatedFileSharing = \OC::$server->query(Application::class);
100
-			$shareProvider = $federatedFileSharing->getFederatedShareProvider();
101
-			$lookupServerUploadEnabled = $shareProvider->isLookupServerUploadEnabled();
102
-		}
103
-
104
-		$uid = \OC_User::getUser();
105
-		$user = $this->userManager->get($uid);
106
-		$userData = $this->accountManager->getUser($user);
107
-
108
-		$storageInfo = \OC_Helper::getStorageInfo('/');
109
-		if ($storageInfo['quota'] === FileInfo::SPACE_UNLIMITED) {
110
-			$totalSpace = $this->l->t('Unlimited');
111
-		} else {
112
-			$totalSpace = \OC_Helper::humanFileSize($storageInfo['total']);
113
-		}
114
-
115
-		$languageParameters = $this->getLanguages($user);
116
-		$localeParameters = $this->getLocales($user);
117
-		$messageParameters = $this->getMessageParameters($userData);
118
-
119
-		$parameters = [
120
-			'total_space' => $totalSpace,
121
-			'usage' => \OC_Helper::humanFileSize($storageInfo['used']),
122
-			'usage_relative' => round($storageInfo['relative']),
123
-			'quota' => $storageInfo['quota'],
124
-			'avatarChangeSupported' => $user->canChangeAvatar(),
125
-			'lookupServerUploadEnabled' => $lookupServerUploadEnabled,
126
-			'avatarScope' => $userData[AccountManager::PROPERTY_AVATAR]['scope'],
127
-			'displayNameChangeSupported' => $user->canChangeDisplayName(),
128
-			'displayName' => $userData[AccountManager::PROPERTY_DISPLAYNAME]['value'],
129
-			'displayNameScope' => $userData[AccountManager::PROPERTY_DISPLAYNAME]['scope'],
130
-			'email' => $userData[AccountManager::PROPERTY_EMAIL]['value'],
131
-			'emailScope' => $userData[AccountManager::PROPERTY_EMAIL]['scope'],
132
-			'emailVerification' => $userData[AccountManager::PROPERTY_EMAIL]['verified'],
133
-			'phone' => $userData[AccountManager::PROPERTY_PHONE]['value'],
134
-			'phoneScope' => $userData[AccountManager::PROPERTY_PHONE]['scope'],
135
-			'address' => $userData[AccountManager::PROPERTY_ADDRESS]['value'],
136
-			'addressScope' => $userData[AccountManager::PROPERTY_ADDRESS]['scope'],
137
-			'website' =>  $userData[AccountManager::PROPERTY_WEBSITE]['value'],
138
-			'websiteScope' =>  $userData[AccountManager::PROPERTY_WEBSITE]['scope'],
139
-			'websiteVerification' => $userData[AccountManager::PROPERTY_WEBSITE]['verified'],
140
-			'twitter' => $userData[AccountManager::PROPERTY_TWITTER]['value'],
141
-			'twitterScope' => $userData[AccountManager::PROPERTY_TWITTER]['scope'],
142
-			'twitterVerification' => $userData[AccountManager::PROPERTY_TWITTER]['verified'],
143
-			'groups' => $this->getGroups($user),
144
-		] + $messageParameters + $languageParameters + $localeParameters;
145
-
146
-
147
-		return new TemplateResponse('settings', 'settings/personal/personal.info', $parameters, '');
148
-	}
149
-
150
-	/**
151
-	 * @return string the section ID, e.g. 'sharing'
152
-	 * @since 9.1
153
-	 */
154
-	public function getSection() {
155
-		return 'personal-info';
156
-	}
157
-
158
-	/**
159
-	 * @return int whether the form should be rather on the top or bottom of
160
-	 * the admin section. The forms are arranged in ascending order of the
161
-	 * priority values. It is required to return a value between 0 and 100.
162
-	 *
163
-	 * E.g.: 70
164
-	 * @since 9.1
165
-	 */
166
-	public function getPriority() {
167
-		return 10;
168
-	}
169
-
170
-	/**
171
-	 * returns a sorted list of the user's group GIDs
172
-	 *
173
-	 * @param IUser $user
174
-	 * @return array
175
-	 */
176
-	private function getGroups(IUser $user) {
177
-		$groups = array_map(
178
-			function(IGroup $group) {
179
-				return $group->getDisplayName();
180
-			},
181
-			$this->groupManager->getUserGroups($user)
182
-		);
183
-		sort($groups);
184
-
185
-		return $groups;
186
-	}
187
-
188
-	/**
189
-	 * returns the user language, common language and other languages in an
190
-	 * associative array
191
-	 *
192
-	 * @param IUser $user
193
-	 * @return array
194
-	 */
195
-	private function getLanguages(IUser $user) {
196
-		$forceLanguage = $this->config->getSystemValue('force_language', false);
197
-		if($forceLanguage !== false) {
198
-			return [];
199
-		}
200
-
201
-		$uid = $user->getUID();
202
-
203
-		$userConfLang = $this->config->getUserValue($uid, 'core', 'lang', $this->l10nFactory->findLanguage());
204
-		$languages = $this->l10nFactory->getLanguages();
205
-
206
-		// associate the user language with the proper array
207
-		$userLangIndex = array_search($userConfLang, array_column($languages['commonlanguages'], 'code'));
208
-		$userLang = $languages['commonlanguages'][$userLangIndex];
209
-		// search in the other languages
210
-		if ($userLangIndex === false) {
211
-			$userLangIndex = array_search($userConfLang, array_column($languages['languages'], 'code'));
212
-			$userLang = $languages['languages'][$userLangIndex];
213
-		}
214
-		// if user language is not available but set somehow: show the actual code as name
215
-		if (!is_array($userLang)) {
216
-			$userLang = [
217
-				'code' => $userConfLang,
218
-				'name' => $userConfLang,
219
-			];
220
-		}
221
-
222
-		return array_merge(
223
-			['activelanguage' => $userLang],
224
-			$languages
225
-		);
226
-	}
227
-
228
-	private function getLocales(IUser $user) {
229
-		$forceLanguage = $this->config->getSystemValue('force_locale', false);
230
-		if($forceLanguage !== false) {
231
-			return [];
232
-		}
233
-
234
-		$uid = $user->getUID();
235
-
236
-		$userLocaleString = $this->config->getUserValue($uid, 'core', 'locale', $this->l10nFactory->findLocale());
237
-
238
-		$userLang = $this->config->getUserValue($uid, 'core', 'lang', $this->l10nFactory->findLanguage());
239
-
240
-		$localeCodes = $this->l10nFactory->findAvailableLocales();
241
-
242
-		$userLocale = array_filter($localeCodes, function($value) use ($userLocaleString) {
243
-			return $userLocaleString === $value['code'];
244
-		});
245
-
246
-		if (!empty($userLocale))
247
-		{
248
-			$userLocale = reset($userLocale);
249
-		}
250
-
251
-		$localesForLanguage = array_filter($localeCodes, function($localeCode) use ($userLang) {
252
-			return 0 === strpos($localeCode['code'], $userLang);
253
-		});
254
-
255
-		if (!$userLocale) {
256
-			$userLocale = [
257
-				'code' => 'en',
258
-				'name' => 'English'
259
-			];
260
-		}
261
-
262
-		return [
263
-			'activelocaleLang' => $userLocaleString,
264
-			'activelocale' => $userLocale,
265
-			'locales' => $localeCodes,
266
-			'localesForLanguage' => $localesForLanguage,
267
-		];
268
-	}
269
-
270
-	/**
271
-	 * @param array $userData
272
-	 * @return array
273
-	 */
274
-	private function getMessageParameters(array $userData) {
275
-		$needVerifyMessage = [AccountManager::PROPERTY_EMAIL, AccountManager::PROPERTY_WEBSITE, AccountManager::PROPERTY_TWITTER];
276
-		$messageParameters = [];
277
-		foreach ($needVerifyMessage as $property) {
278
-			switch ($userData[$property]['verified']) {
279
-				case AccountManager::VERIFIED:
280
-					$message = $this->l->t('Verifying');
281
-					break;
282
-				case AccountManager::VERIFICATION_IN_PROGRESS:
283
-					$message = $this->l->t('Verifying …');
284
-					break;
285
-				default:
286
-					$message = $this->l->t('Verify');
287
-			}
288
-			$messageParameters[$property . 'Message'] = $message;
289
-		}
290
-		return $messageParameters;
291
-	}
50
+    /** @var IConfig */
51
+    private $config;
52
+    /** @var IUserManager */
53
+    private $userManager;
54
+    /** @var AccountManager */
55
+    private $accountManager;
56
+    /** @var IGroupManager */
57
+    private $groupManager;
58
+    /** @var IAppManager */
59
+    private $appManager;
60
+    /** @var IFactory */
61
+    private $l10nFactory;
62
+    /** @var IL10N */
63
+    private $l;
64
+
65
+    /**
66
+     * @param IConfig $config
67
+     * @param IUserManager $userManager
68
+     * @param IGroupManager $groupManager
69
+     * @param AccountManager $accountManager
70
+     * @param IFactory $l10nFactory
71
+     * @param IL10N $l
72
+     */
73
+    public function __construct(
74
+        IConfig $config,
75
+        IUserManager $userManager,
76
+        IGroupManager $groupManager,
77
+        AccountManager $accountManager,
78
+        IAppManager $appManager,
79
+        IFactory $l10nFactory,
80
+        IL10N $l
81
+    ) {
82
+        $this->config = $config;
83
+        $this->userManager = $userManager;
84
+        $this->accountManager = $accountManager;
85
+        $this->groupManager = $groupManager;
86
+        $this->appManager = $appManager;
87
+        $this->l10nFactory = $l10nFactory;
88
+        $this->l = $l;
89
+    }
90
+
91
+    /**
92
+     * @return TemplateResponse returns the instance with all parameters set, ready to be rendered
93
+     * @since 9.1
94
+     */
95
+    public function getForm() {
96
+        $federatedFileSharingEnabled = $this->appManager->isEnabledForUser('federatedfilesharing');
97
+        $lookupServerUploadEnabled = false;
98
+        if($federatedFileSharingEnabled) {
99
+            $federatedFileSharing = \OC::$server->query(Application::class);
100
+            $shareProvider = $federatedFileSharing->getFederatedShareProvider();
101
+            $lookupServerUploadEnabled = $shareProvider->isLookupServerUploadEnabled();
102
+        }
103
+
104
+        $uid = \OC_User::getUser();
105
+        $user = $this->userManager->get($uid);
106
+        $userData = $this->accountManager->getUser($user);
107
+
108
+        $storageInfo = \OC_Helper::getStorageInfo('/');
109
+        if ($storageInfo['quota'] === FileInfo::SPACE_UNLIMITED) {
110
+            $totalSpace = $this->l->t('Unlimited');
111
+        } else {
112
+            $totalSpace = \OC_Helper::humanFileSize($storageInfo['total']);
113
+        }
114
+
115
+        $languageParameters = $this->getLanguages($user);
116
+        $localeParameters = $this->getLocales($user);
117
+        $messageParameters = $this->getMessageParameters($userData);
118
+
119
+        $parameters = [
120
+            'total_space' => $totalSpace,
121
+            'usage' => \OC_Helper::humanFileSize($storageInfo['used']),
122
+            'usage_relative' => round($storageInfo['relative']),
123
+            'quota' => $storageInfo['quota'],
124
+            'avatarChangeSupported' => $user->canChangeAvatar(),
125
+            'lookupServerUploadEnabled' => $lookupServerUploadEnabled,
126
+            'avatarScope' => $userData[AccountManager::PROPERTY_AVATAR]['scope'],
127
+            'displayNameChangeSupported' => $user->canChangeDisplayName(),
128
+            'displayName' => $userData[AccountManager::PROPERTY_DISPLAYNAME]['value'],
129
+            'displayNameScope' => $userData[AccountManager::PROPERTY_DISPLAYNAME]['scope'],
130
+            'email' => $userData[AccountManager::PROPERTY_EMAIL]['value'],
131
+            'emailScope' => $userData[AccountManager::PROPERTY_EMAIL]['scope'],
132
+            'emailVerification' => $userData[AccountManager::PROPERTY_EMAIL]['verified'],
133
+            'phone' => $userData[AccountManager::PROPERTY_PHONE]['value'],
134
+            'phoneScope' => $userData[AccountManager::PROPERTY_PHONE]['scope'],
135
+            'address' => $userData[AccountManager::PROPERTY_ADDRESS]['value'],
136
+            'addressScope' => $userData[AccountManager::PROPERTY_ADDRESS]['scope'],
137
+            'website' =>  $userData[AccountManager::PROPERTY_WEBSITE]['value'],
138
+            'websiteScope' =>  $userData[AccountManager::PROPERTY_WEBSITE]['scope'],
139
+            'websiteVerification' => $userData[AccountManager::PROPERTY_WEBSITE]['verified'],
140
+            'twitter' => $userData[AccountManager::PROPERTY_TWITTER]['value'],
141
+            'twitterScope' => $userData[AccountManager::PROPERTY_TWITTER]['scope'],
142
+            'twitterVerification' => $userData[AccountManager::PROPERTY_TWITTER]['verified'],
143
+            'groups' => $this->getGroups($user),
144
+        ] + $messageParameters + $languageParameters + $localeParameters;
145
+
146
+
147
+        return new TemplateResponse('settings', 'settings/personal/personal.info', $parameters, '');
148
+    }
149
+
150
+    /**
151
+     * @return string the section ID, e.g. 'sharing'
152
+     * @since 9.1
153
+     */
154
+    public function getSection() {
155
+        return 'personal-info';
156
+    }
157
+
158
+    /**
159
+     * @return int whether the form should be rather on the top or bottom of
160
+     * the admin section. The forms are arranged in ascending order of the
161
+     * priority values. It is required to return a value between 0 and 100.
162
+     *
163
+     * E.g.: 70
164
+     * @since 9.1
165
+     */
166
+    public function getPriority() {
167
+        return 10;
168
+    }
169
+
170
+    /**
171
+     * returns a sorted list of the user's group GIDs
172
+     *
173
+     * @param IUser $user
174
+     * @return array
175
+     */
176
+    private function getGroups(IUser $user) {
177
+        $groups = array_map(
178
+            function(IGroup $group) {
179
+                return $group->getDisplayName();
180
+            },
181
+            $this->groupManager->getUserGroups($user)
182
+        );
183
+        sort($groups);
184
+
185
+        return $groups;
186
+    }
187
+
188
+    /**
189
+     * returns the user language, common language and other languages in an
190
+     * associative array
191
+     *
192
+     * @param IUser $user
193
+     * @return array
194
+     */
195
+    private function getLanguages(IUser $user) {
196
+        $forceLanguage = $this->config->getSystemValue('force_language', false);
197
+        if($forceLanguage !== false) {
198
+            return [];
199
+        }
200
+
201
+        $uid = $user->getUID();
202
+
203
+        $userConfLang = $this->config->getUserValue($uid, 'core', 'lang', $this->l10nFactory->findLanguage());
204
+        $languages = $this->l10nFactory->getLanguages();
205
+
206
+        // associate the user language with the proper array
207
+        $userLangIndex = array_search($userConfLang, array_column($languages['commonlanguages'], 'code'));
208
+        $userLang = $languages['commonlanguages'][$userLangIndex];
209
+        // search in the other languages
210
+        if ($userLangIndex === false) {
211
+            $userLangIndex = array_search($userConfLang, array_column($languages['languages'], 'code'));
212
+            $userLang = $languages['languages'][$userLangIndex];
213
+        }
214
+        // if user language is not available but set somehow: show the actual code as name
215
+        if (!is_array($userLang)) {
216
+            $userLang = [
217
+                'code' => $userConfLang,
218
+                'name' => $userConfLang,
219
+            ];
220
+        }
221
+
222
+        return array_merge(
223
+            ['activelanguage' => $userLang],
224
+            $languages
225
+        );
226
+    }
227
+
228
+    private function getLocales(IUser $user) {
229
+        $forceLanguage = $this->config->getSystemValue('force_locale', false);
230
+        if($forceLanguage !== false) {
231
+            return [];
232
+        }
233
+
234
+        $uid = $user->getUID();
235
+
236
+        $userLocaleString = $this->config->getUserValue($uid, 'core', 'locale', $this->l10nFactory->findLocale());
237
+
238
+        $userLang = $this->config->getUserValue($uid, 'core', 'lang', $this->l10nFactory->findLanguage());
239
+
240
+        $localeCodes = $this->l10nFactory->findAvailableLocales();
241
+
242
+        $userLocale = array_filter($localeCodes, function($value) use ($userLocaleString) {
243
+            return $userLocaleString === $value['code'];
244
+        });
245
+
246
+        if (!empty($userLocale))
247
+        {
248
+            $userLocale = reset($userLocale);
249
+        }
250
+
251
+        $localesForLanguage = array_filter($localeCodes, function($localeCode) use ($userLang) {
252
+            return 0 === strpos($localeCode['code'], $userLang);
253
+        });
254
+
255
+        if (!$userLocale) {
256
+            $userLocale = [
257
+                'code' => 'en',
258
+                'name' => 'English'
259
+            ];
260
+        }
261
+
262
+        return [
263
+            'activelocaleLang' => $userLocaleString,
264
+            'activelocale' => $userLocale,
265
+            'locales' => $localeCodes,
266
+            'localesForLanguage' => $localesForLanguage,
267
+        ];
268
+    }
269
+
270
+    /**
271
+     * @param array $userData
272
+     * @return array
273
+     */
274
+    private function getMessageParameters(array $userData) {
275
+        $needVerifyMessage = [AccountManager::PROPERTY_EMAIL, AccountManager::PROPERTY_WEBSITE, AccountManager::PROPERTY_TWITTER];
276
+        $messageParameters = [];
277
+        foreach ($needVerifyMessage as $property) {
278
+            switch ($userData[$property]['verified']) {
279
+                case AccountManager::VERIFIED:
280
+                    $message = $this->l->t('Verifying');
281
+                    break;
282
+                case AccountManager::VERIFICATION_IN_PROGRESS:
283
+                    $message = $this->l->t('Verifying …');
284
+                    break;
285
+                default:
286
+                    $message = $this->l->t('Verify');
287
+            }
288
+            $messageParameters[$property . 'Message'] = $message;
289
+        }
290
+        return $messageParameters;
291
+    }
292 292
 
293 293
 }
Please login to merge, or discard this patch.
apps/settings/lib/Middleware/SubadminMiddleware.php 2 patches
Indentation   +47 added lines, -47 removed lines patch added patch discarded remove patch
@@ -38,56 +38,56 @@
 block discarded – undo
38 38
  * To bypass use the `@NoSubadminRequired` annotation
39 39
  */
40 40
 class SubadminMiddleware extends Middleware {
41
-	/** @var bool */
42
-	protected $isSubAdmin;
43
-	/** @var ControllerMethodReflector */
44
-	protected $reflector;
45
-	/** @var IL10N */
46
-	private $l10n;
41
+    /** @var bool */
42
+    protected $isSubAdmin;
43
+    /** @var ControllerMethodReflector */
44
+    protected $reflector;
45
+    /** @var IL10N */
46
+    private $l10n;
47 47
 
48
-	/**
49
-	 * @param ControllerMethodReflector $reflector
50
-	 * @param bool $isSubAdmin
51
-	 * @param IL10N $l10n
52
-	 */
53
-	public function __construct(ControllerMethodReflector $reflector,
54
-								$isSubAdmin,
55
-								IL10N $l10n) {
56
-		$this->reflector = $reflector;
57
-		$this->isSubAdmin = $isSubAdmin;
58
-		$this->l10n = $l10n;
59
-	}
48
+    /**
49
+     * @param ControllerMethodReflector $reflector
50
+     * @param bool $isSubAdmin
51
+     * @param IL10N $l10n
52
+     */
53
+    public function __construct(ControllerMethodReflector $reflector,
54
+                                $isSubAdmin,
55
+                                IL10N $l10n) {
56
+        $this->reflector = $reflector;
57
+        $this->isSubAdmin = $isSubAdmin;
58
+        $this->l10n = $l10n;
59
+    }
60 60
 
61
-	/**
62
-	 * Check if sharing is enabled before the controllers is executed
63
-	 * @param Controller $controller
64
-	 * @param string $methodName
65
-	 * @throws \Exception
66
-	 */
67
-	public function beforeController($controller, $methodName) {
68
-		if(!$this->reflector->hasAnnotation('NoSubadminRequired')) {
69
-			if(!$this->isSubAdmin) {
70
-				throw new NotAdminException($this->l10n->t('Logged in user must be a subadmin'));
71
-			}
72
-		}
73
-	}
61
+    /**
62
+     * Check if sharing is enabled before the controllers is executed
63
+     * @param Controller $controller
64
+     * @param string $methodName
65
+     * @throws \Exception
66
+     */
67
+    public function beforeController($controller, $methodName) {
68
+        if(!$this->reflector->hasAnnotation('NoSubadminRequired')) {
69
+            if(!$this->isSubAdmin) {
70
+                throw new NotAdminException($this->l10n->t('Logged in user must be a subadmin'));
71
+            }
72
+        }
73
+    }
74 74
 
75
-	/**
76
-	 * Return 403 page in case of an exception
77
-	 * @param Controller $controller
78
-	 * @param string $methodName
79
-	 * @param \Exception $exception
80
-	 * @return TemplateResponse
81
-	 * @throws \Exception
82
-	 */
83
-	public function afterException($controller, $methodName, \Exception $exception) {
84
-		if($exception instanceof NotAdminException) {
85
-			$response = new TemplateResponse('core', '403', [], 'guest');
86
-			$response->setStatus(Http::STATUS_FORBIDDEN);
87
-			return $response;
88
-		}
75
+    /**
76
+     * Return 403 page in case of an exception
77
+     * @param Controller $controller
78
+     * @param string $methodName
79
+     * @param \Exception $exception
80
+     * @return TemplateResponse
81
+     * @throws \Exception
82
+     */
83
+    public function afterException($controller, $methodName, \Exception $exception) {
84
+        if($exception instanceof NotAdminException) {
85
+            $response = new TemplateResponse('core', '403', [], 'guest');
86
+            $response->setStatus(Http::STATUS_FORBIDDEN);
87
+            return $response;
88
+        }
89 89
 
90
-		throw $exception;
91
-	}
90
+        throw $exception;
91
+    }
92 92
 
93 93
 }
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -65,8 +65,8 @@  discard block
 block discarded – undo
65 65
 	 * @throws \Exception
66 66
 	 */
67 67
 	public function beforeController($controller, $methodName) {
68
-		if(!$this->reflector->hasAnnotation('NoSubadminRequired')) {
69
-			if(!$this->isSubAdmin) {
68
+		if (!$this->reflector->hasAnnotation('NoSubadminRequired')) {
69
+			if (!$this->isSubAdmin) {
70 70
 				throw new NotAdminException($this->l10n->t('Logged in user must be a subadmin'));
71 71
 			}
72 72
 		}
@@ -81,7 +81,7 @@  discard block
 block discarded – undo
81 81
 	 * @throws \Exception
82 82
 	 */
83 83
 	public function afterException($controller, $methodName, \Exception $exception) {
84
-		if($exception instanceof NotAdminException) {
84
+		if ($exception instanceof NotAdminException) {
85 85
 			$response = new TemplateResponse('core', '403', [], 'guest');
86 86
 			$response->setStatus(Http::STATUS_FORBIDDEN);
87 87
 			return $response;
Please login to merge, or discard this patch.
apps/settings/lib/Controller/AppSettingsController.php 1 patch
Indentation   +502 added lines, -502 removed lines patch added patch discarded remove patch
@@ -54,507 +54,507 @@
 block discarded – undo
54 54
 
55 55
 class AppSettingsController extends Controller {
56 56
 
57
-	/** @var \OCP\IL10N */
58
-	private $l10n;
59
-	/** @var IConfig */
60
-	private $config;
61
-	/** @var INavigationManager */
62
-	private $navigationManager;
63
-	/** @var IAppManager */
64
-	private $appManager;
65
-	/** @var CategoryFetcher */
66
-	private $categoryFetcher;
67
-	/** @var AppFetcher */
68
-	private $appFetcher;
69
-	/** @var IFactory */
70
-	private $l10nFactory;
71
-	/** @var BundleFetcher */
72
-	private $bundleFetcher;
73
-	/** @var Installer */
74
-	private $installer;
75
-	/** @var IURLGenerator */
76
-	private $urlGenerator;
77
-	/** @var ILogger */
78
-	private $logger;
79
-
80
-	/** @var array */
81
-	private $allApps = [];
82
-
83
-	/**
84
-	 * @param string $appName
85
-	 * @param IRequest $request
86
-	 * @param IL10N $l10n
87
-	 * @param IConfig $config
88
-	 * @param INavigationManager $navigationManager
89
-	 * @param IAppManager $appManager
90
-	 * @param CategoryFetcher $categoryFetcher
91
-	 * @param AppFetcher $appFetcher
92
-	 * @param IFactory $l10nFactory
93
-	 * @param BundleFetcher $bundleFetcher
94
-	 * @param Installer $installer
95
-	 * @param IURLGenerator $urlGenerator
96
-	 * @param ILogger $logger
97
-	 */
98
-	public function __construct(string $appName,
99
-								IRequest $request,
100
-								IL10N $l10n,
101
-								IConfig $config,
102
-								INavigationManager $navigationManager,
103
-								IAppManager $appManager,
104
-								CategoryFetcher $categoryFetcher,
105
-								AppFetcher $appFetcher,
106
-								IFactory $l10nFactory,
107
-								BundleFetcher $bundleFetcher,
108
-								Installer $installer,
109
-								IURLGenerator $urlGenerator,
110
-								ILogger $logger) {
111
-		parent::__construct($appName, $request);
112
-		$this->l10n = $l10n;
113
-		$this->config = $config;
114
-		$this->navigationManager = $navigationManager;
115
-		$this->appManager = $appManager;
116
-		$this->categoryFetcher = $categoryFetcher;
117
-		$this->appFetcher = $appFetcher;
118
-		$this->l10nFactory = $l10nFactory;
119
-		$this->bundleFetcher = $bundleFetcher;
120
-		$this->installer = $installer;
121
-		$this->urlGenerator = $urlGenerator;
122
-		$this->logger = $logger;
123
-	}
124
-
125
-	/**
126
-	 * @NoCSRFRequired
127
-	 *
128
-	 * @return TemplateResponse
129
-	 */
130
-	public function viewApps(): TemplateResponse {
131
-		\OC_Util::addScript('settings', 'apps');
132
-		$params = [];
133
-		$params['appstoreEnabled'] = $this->config->getSystemValue('appstoreenabled', true) === true;
134
-		$params['updateCount'] = count($this->getAppsWithUpdates());
135
-		$params['developerDocumentation'] = $this->urlGenerator->linkToDocs('developer-manual');
136
-		$params['bundles'] = $this->getBundles();
137
-		$this->navigationManager->setActiveEntry('core_apps');
138
-
139
-		$templateResponse = new TemplateResponse('settings', 'settings-vue', ['serverData' => $params]);
140
-		$policy = new ContentSecurityPolicy();
141
-		$policy->addAllowedImageDomain('https://usercontent.apps.nextcloud.com');
142
-		$templateResponse->setContentSecurityPolicy($policy);
143
-
144
-		return $templateResponse;
145
-	}
146
-
147
-	private function getAppsWithUpdates() {
148
-		$appClass = new \OC_App();
149
-		$apps = $appClass->listAllApps();
150
-		foreach($apps as $key => $app) {
151
-			$newVersion = $this->installer->isUpdateAvailable($app['id']);
152
-			if($newVersion === false) {
153
-				unset($apps[$key]);
154
-			}
155
-		}
156
-		return $apps;
157
-	}
158
-
159
-	private function getBundles() {
160
-		$result = [];
161
-		$bundles = $this->bundleFetcher->getBundles();
162
-		foreach ($bundles as $bundle) {
163
-			$result[] = [
164
-				'name' => $bundle->getName(),
165
-				'id' => $bundle->getIdentifier(),
166
-				'appIdentifiers' => $bundle->getAppIdentifiers()
167
-			];
168
-		}
169
-		return $result;
170
-
171
-	}
172
-
173
-	/**
174
-	 * Get all available categories
175
-	 *
176
-	 * @return JSONResponse
177
-	 */
178
-	public function listCategories(): JSONResponse {
179
-		return new JSONResponse($this->getAllCategories());
180
-	}
181
-
182
-	private function getAllCategories() {
183
-		$currentLanguage = substr($this->l10nFactory->findLanguage(), 0, 2);
184
-
185
-		$formattedCategories = [];
186
-		$categories = $this->categoryFetcher->get();
187
-		foreach($categories as $category) {
188
-			$formattedCategories[] = [
189
-				'id' => $category['id'],
190
-				'ident' => $category['id'],
191
-				'displayName' => isset($category['translations'][$currentLanguage]['name']) ? $category['translations'][$currentLanguage]['name'] : $category['translations']['en']['name'],
192
-			];
193
-		}
194
-
195
-		return $formattedCategories;
196
-	}
197
-
198
-	private function fetchApps() {
199
-		$appClass = new \OC_App();
200
-		$apps = $appClass->listAllApps();
201
-		foreach ($apps as $app) {
202
-			$app['installed'] = true;
203
-			$this->allApps[$app['id']] = $app;
204
-		}
205
-
206
-		$apps = $this->getAppsForCategory('');
207
-		foreach ($apps as $app) {
208
-			$app['appstore'] = true;
209
-			if (!array_key_exists($app['id'], $this->allApps)) {
210
-				$this->allApps[$app['id']] = $app;
211
-			} else {
212
-				$this->allApps[$app['id']] = array_merge($app, $this->allApps[$app['id']]);
213
-			}
214
-		}
215
-
216
-		// add bundle information
217
-		$bundles = $this->bundleFetcher->getBundles();
218
-		foreach($bundles as $bundle) {
219
-			foreach($bundle->getAppIdentifiers() as $identifier) {
220
-				foreach($this->allApps as &$app) {
221
-					if($app['id'] === $identifier) {
222
-						$app['bundleIds'][] = $bundle->getIdentifier();
223
-						continue;
224
-					}
225
-				}
226
-			}
227
-		}
228
-	}
229
-
230
-	private function getAllApps() {
231
-		return $this->allApps;
232
-	}
233
-	/**
234
-	 * Get all available apps in a category
235
-	 *
236
-	 * @param string $category
237
-	 * @return JSONResponse
238
-	 * @throws \Exception
239
-	 */
240
-	public function listApps(): JSONResponse {
241
-
242
-		$this->fetchApps();
243
-		$apps = $this->getAllApps();
244
-
245
-		$dependencyAnalyzer = new DependencyAnalyzer(new Platform($this->config), $this->l10n);
246
-
247
-		// Extend existing app details
248
-		$apps = array_map(function($appData) use ($dependencyAnalyzer) {
249
-			if (isset($appData['appstoreData'])) {
250
-				$appstoreData = $appData['appstoreData'];
251
-				$appData['screenshot'] = isset($appstoreData['screenshots'][0]['url']) ? 'https://usercontent.apps.nextcloud.com/' . base64_encode($appstoreData['screenshots'][0]['url']) : '';
252
-				$appData['category'] = $appstoreData['categories'];
253
-			}
254
-
255
-			$newVersion = $this->installer->isUpdateAvailable($appData['id']);
256
-			if($newVersion) {
257
-				$appData['update'] = $newVersion;
258
-			}
259
-
260
-			// fix groups to be an array
261
-			$groups = [];
262
-			if (is_string($appData['groups'])) {
263
-				$groups = json_decode($appData['groups']);
264
-			}
265
-			$appData['groups'] = $groups;
266
-			$appData['canUnInstall'] = !$appData['active'] && $appData['removable'];
267
-
268
-			// fix licence vs license
269
-			if (isset($appData['license']) && !isset($appData['licence'])) {
270
-				$appData['licence'] = $appData['license'];
271
-			}
272
-
273
-			$ignoreMaxApps = $this->config->getSystemValue('app_install_overwrite', []);
274
-			if (!is_array($ignoreMaxApps)) {
275
-				$this->logger->warning('The value given for app_install_overwrite is not an array. Ignoring...');
276
-				$ignoreMaxApps = [];
277
-			}
278
-			$ignoreMax = in_array($appData['id'], $ignoreMaxApps);
279
-
280
-			// analyse dependencies
281
-			$missing = $dependencyAnalyzer->analyze($appData, $ignoreMax);
282
-			$appData['canInstall'] = empty($missing);
283
-			$appData['missingDependencies'] = $missing;
284
-
285
-			$appData['missingMinOwnCloudVersion'] = !isset($appData['dependencies']['nextcloud']['@attributes']['min-version']);
286
-			$appData['missingMaxOwnCloudVersion'] = !isset($appData['dependencies']['nextcloud']['@attributes']['max-version']);
287
-			$appData['isCompatible'] = $dependencyAnalyzer->isMarkedCompatible($appData);
288
-
289
-			return $appData;
290
-		}, $apps);
291
-
292
-		usort($apps, [$this, 'sortApps']);
293
-
294
-		return new JSONResponse(['apps' => $apps, 'status' => 'success']);
295
-	}
296
-
297
-	/**
298
-	 * Get all apps for a category from the app store
299
-	 *
300
-	 * @param string $requestedCategory
301
-	 * @return array
302
-	 * @throws \Exception
303
-	 */
304
-	private function getAppsForCategory($requestedCategory = ''): array {
305
-		$versionParser = new VersionParser();
306
-		$formattedApps = [];
307
-		$apps = $this->appFetcher->get();
308
-		foreach($apps as $app) {
309
-			// Skip all apps not in the requested category
310
-			if ($requestedCategory !== '') {
311
-				$isInCategory = false;
312
-				foreach($app['categories'] as $category) {
313
-					if($category === $requestedCategory) {
314
-						$isInCategory = true;
315
-					}
316
-				}
317
-				if(!$isInCategory) {
318
-					continue;
319
-				}
320
-			}
321
-
322
-			if (!isset($app['releases'][0]['rawPlatformVersionSpec'])) {
323
-				continue;
324
-			}
325
-			$nextCloudVersion = $versionParser->getVersion($app['releases'][0]['rawPlatformVersionSpec']);
326
-			$nextCloudVersionDependencies = [];
327
-			if($nextCloudVersion->getMinimumVersion() !== '') {
328
-				$nextCloudVersionDependencies['nextcloud']['@attributes']['min-version'] = $nextCloudVersion->getMinimumVersion();
329
-			}
330
-			if($nextCloudVersion->getMaximumVersion() !== '') {
331
-				$nextCloudVersionDependencies['nextcloud']['@attributes']['max-version'] = $nextCloudVersion->getMaximumVersion();
332
-			}
333
-			$phpVersion = $versionParser->getVersion($app['releases'][0]['rawPhpVersionSpec']);
334
-			$existsLocally = \OC_App::getAppPath($app['id']) !== false;
335
-			$phpDependencies = [];
336
-			if($phpVersion->getMinimumVersion() !== '') {
337
-				$phpDependencies['php']['@attributes']['min-version'] = $phpVersion->getMinimumVersion();
338
-			}
339
-			if($phpVersion->getMaximumVersion() !== '') {
340
-				$phpDependencies['php']['@attributes']['max-version'] = $phpVersion->getMaximumVersion();
341
-			}
342
-			if(isset($app['releases'][0]['minIntSize'])) {
343
-				$phpDependencies['php']['@attributes']['min-int-size'] = $app['releases'][0]['minIntSize'];
344
-			}
345
-			$authors = '';
346
-			foreach($app['authors'] as $key => $author) {
347
-				$authors .= $author['name'];
348
-				if($key !== count($app['authors']) - 1) {
349
-					$authors .= ', ';
350
-				}
351
-			}
352
-
353
-			$currentLanguage = substr(\OC::$server->getL10NFactory()->findLanguage(), 0, 2);
354
-			$enabledValue = $this->config->getAppValue($app['id'], 'enabled', 'no');
355
-			$groups = null;
356
-			if($enabledValue !== 'no' && $enabledValue !== 'yes') {
357
-				$groups = $enabledValue;
358
-			}
359
-
360
-			$currentVersion = '';
361
-			if($this->appManager->isInstalled($app['id'])) {
362
-				$currentVersion = $this->appManager->getAppVersion($app['id']);
363
-			} else {
364
-				$currentLanguage = $app['releases'][0]['version'];
365
-			}
366
-
367
-			$formattedApps[] = [
368
-				'id' => $app['id'],
369
-				'name' => isset($app['translations'][$currentLanguage]['name']) ? $app['translations'][$currentLanguage]['name'] : $app['translations']['en']['name'],
370
-				'description' => isset($app['translations'][$currentLanguage]['description']) ? $app['translations'][$currentLanguage]['description'] : $app['translations']['en']['description'],
371
-				'summary' => isset($app['translations'][$currentLanguage]['summary']) ? $app['translations'][$currentLanguage]['summary'] : $app['translations']['en']['summary'],
372
-				'license' => $app['releases'][0]['licenses'],
373
-				'author' => $authors,
374
-				'shipped' => false,
375
-				'version' => $currentVersion,
376
-				'default_enable' => '',
377
-				'types' => [],
378
-				'documentation' => [
379
-					'admin' => $app['adminDocs'],
380
-					'user' => $app['userDocs'],
381
-					'developer' => $app['developerDocs']
382
-				],
383
-				'website' => $app['website'],
384
-				'bugs' => $app['issueTracker'],
385
-				'detailpage' => $app['website'],
386
-				'dependencies' => array_merge(
387
-					$nextCloudVersionDependencies,
388
-					$phpDependencies
389
-				),
390
-				'level' => ($app['isFeatured'] === true) ? 200 : 100,
391
-				'missingMaxOwnCloudVersion' => false,
392
-				'missingMinOwnCloudVersion' => false,
393
-				'canInstall' => true,
394
-				'screenshot' => isset($app['screenshots'][0]['url']) ? 'https://usercontent.apps.nextcloud.com/'.base64_encode($app['screenshots'][0]['url']) : '',
395
-				'score' => $app['ratingOverall'],
396
-				'ratingNumOverall' => $app['ratingNumOverall'],
397
-				'ratingNumThresholdReached' => $app['ratingNumOverall'] > 5,
398
-				'removable' => $existsLocally,
399
-				'active' => $this->appManager->isEnabledForUser($app['id']),
400
-				'needsDownload' => !$existsLocally,
401
-				'groups' => $groups,
402
-				'fromAppStore' => true,
403
-				'appstoreData' => $app,
404
-			];
405
-		}
406
-
407
-		return $formattedApps;
408
-	}
409
-
410
-	/**
411
-	 * @PasswordConfirmationRequired
412
-	 *
413
-	 * @param string $appId
414
-	 * @param array $groups
415
-	 * @return JSONResponse
416
-	 */
417
-	public function enableApp(string $appId, array $groups = []): JSONResponse {
418
-		return $this->enableApps([$appId], $groups);
419
-	}
420
-
421
-	/**
422
-	 * Enable one or more apps
423
-	 *
424
-	 * apps will be enabled for specific groups only if $groups is defined
425
-	 *
426
-	 * @PasswordConfirmationRequired
427
-	 * @param array $appIds
428
-	 * @param array $groups
429
-	 * @return JSONResponse
430
-	 */
431
-	public function enableApps(array $appIds, array $groups = []): JSONResponse {
432
-		try {
433
-			$updateRequired = false;
434
-
435
-			foreach ($appIds as $appId) {
436
-				$appId = OC_App::cleanAppId($appId);
437
-
438
-				// Check if app is already downloaded
439
-				/** @var Installer $installer */
440
-				$installer = \OC::$server->query(Installer::class);
441
-				$isDownloaded = $installer->isDownloaded($appId);
442
-
443
-				if(!$isDownloaded) {
444
-					$installer->downloadApp($appId);
445
-				}
446
-
447
-				$installer->installApp($appId);
448
-
449
-				if (count($groups) > 0) {
450
-					$this->appManager->enableAppForGroups($appId, $this->getGroupList($groups));
451
-				} else {
452
-					$this->appManager->enableApp($appId);
453
-				}
454
-				if (\OC_App::shouldUpgrade($appId)) {
455
-					$updateRequired = true;
456
-				}
457
-			}
458
-			return new JSONResponse(['data' => ['update_required' => $updateRequired]]);
459
-
460
-		} catch (\Exception $e) {
461
-			$this->logger->logException($e);
462
-			return new JSONResponse(['data' => ['message' => $e->getMessage()]], Http::STATUS_INTERNAL_SERVER_ERROR);
463
-		}
464
-	}
465
-
466
-	private function getGroupList(array $groups) {
467
-		$groupManager = \OC::$server->getGroupManager();
468
-		$groupsList = [];
469
-		foreach ($groups as $group) {
470
-			$groupItem = $groupManager->get($group);
471
-			if ($groupItem instanceof \OCP\IGroup) {
472
-				$groupsList[] = $groupManager->get($group);
473
-			}
474
-		}
475
-		return $groupsList;
476
-	}
477
-
478
-	/**
479
-	 * @PasswordConfirmationRequired
480
-	 *
481
-	 * @param string $appId
482
-	 * @return JSONResponse
483
-	 */
484
-	public function disableApp(string $appId): JSONResponse {
485
-		return $this->disableApps([$appId]);
486
-	}
487
-
488
-	/**
489
-	 * @PasswordConfirmationRequired
490
-	 *
491
-	 * @param array $appIds
492
-	 * @return JSONResponse
493
-	 */
494
-	public function disableApps(array $appIds): JSONResponse {
495
-		try {
496
-			foreach ($appIds as $appId) {
497
-				$appId = OC_App::cleanAppId($appId);
498
-				$this->appManager->disableApp($appId);
499
-			}
500
-			return new JSONResponse([]);
501
-		} catch (\Exception $e) {
502
-			$this->logger->logException($e);
503
-			return new JSONResponse(['data' => ['message' => $e->getMessage()]], Http::STATUS_INTERNAL_SERVER_ERROR);
504
-		}
505
-	}
506
-
507
-	/**
508
-	 * @PasswordConfirmationRequired
509
-	 *
510
-	 * @param string $appId
511
-	 * @return JSONResponse
512
-	 */
513
-	public function uninstallApp(string $appId): JSONResponse {
514
-		$appId = OC_App::cleanAppId($appId);
515
-		$result = $this->installer->removeApp($appId);
516
-		if($result !== false) {
517
-			$this->appManager->clearAppsCache();
518
-			return new JSONResponse(['data' => ['appid' => $appId]]);
519
-		}
520
-		return new JSONResponse(['data' => ['message' => $this->l10n->t('Couldn\'t remove app.')]], Http::STATUS_INTERNAL_SERVER_ERROR);
521
-	}
522
-
523
-	/**
524
-	 * @param string $appId
525
-	 * @return JSONResponse
526
-	 */
527
-	public function updateApp(string $appId): JSONResponse {
528
-		$appId = OC_App::cleanAppId($appId);
529
-
530
-		$this->config->setSystemValue('maintenance', true);
531
-		try {
532
-			$result = $this->installer->updateAppstoreApp($appId);
533
-			$this->config->setSystemValue('maintenance', false);
534
-		} catch (\Exception $ex) {
535
-			$this->config->setSystemValue('maintenance', false);
536
-			return new JSONResponse(['data' => ['message' => $ex->getMessage()]], Http::STATUS_INTERNAL_SERVER_ERROR);
537
-		}
538
-
539
-		if ($result !== false) {
540
-			return new JSONResponse(['data' => ['appid' => $appId]]);
541
-		}
542
-		return new JSONResponse(['data' => ['message' => $this->l10n->t('Couldn\'t update app.')]], Http::STATUS_INTERNAL_SERVER_ERROR);
543
-	}
544
-
545
-	private function sortApps($a, $b) {
546
-		$a = (string)$a['name'];
547
-		$b = (string)$b['name'];
548
-		if ($a === $b) {
549
-			return 0;
550
-		}
551
-		return ($a < $b) ? -1 : 1;
552
-	}
553
-
554
-	public function force(string $appId): JSONResponse {
555
-		$appId = OC_App::cleanAppId($appId);
556
-		$this->appManager->ignoreNextcloudRequirementForApp($appId);
557
-		return new JSONResponse();
558
-	}
57
+    /** @var \OCP\IL10N */
58
+    private $l10n;
59
+    /** @var IConfig */
60
+    private $config;
61
+    /** @var INavigationManager */
62
+    private $navigationManager;
63
+    /** @var IAppManager */
64
+    private $appManager;
65
+    /** @var CategoryFetcher */
66
+    private $categoryFetcher;
67
+    /** @var AppFetcher */
68
+    private $appFetcher;
69
+    /** @var IFactory */
70
+    private $l10nFactory;
71
+    /** @var BundleFetcher */
72
+    private $bundleFetcher;
73
+    /** @var Installer */
74
+    private $installer;
75
+    /** @var IURLGenerator */
76
+    private $urlGenerator;
77
+    /** @var ILogger */
78
+    private $logger;
79
+
80
+    /** @var array */
81
+    private $allApps = [];
82
+
83
+    /**
84
+     * @param string $appName
85
+     * @param IRequest $request
86
+     * @param IL10N $l10n
87
+     * @param IConfig $config
88
+     * @param INavigationManager $navigationManager
89
+     * @param IAppManager $appManager
90
+     * @param CategoryFetcher $categoryFetcher
91
+     * @param AppFetcher $appFetcher
92
+     * @param IFactory $l10nFactory
93
+     * @param BundleFetcher $bundleFetcher
94
+     * @param Installer $installer
95
+     * @param IURLGenerator $urlGenerator
96
+     * @param ILogger $logger
97
+     */
98
+    public function __construct(string $appName,
99
+                                IRequest $request,
100
+                                IL10N $l10n,
101
+                                IConfig $config,
102
+                                INavigationManager $navigationManager,
103
+                                IAppManager $appManager,
104
+                                CategoryFetcher $categoryFetcher,
105
+                                AppFetcher $appFetcher,
106
+                                IFactory $l10nFactory,
107
+                                BundleFetcher $bundleFetcher,
108
+                                Installer $installer,
109
+                                IURLGenerator $urlGenerator,
110
+                                ILogger $logger) {
111
+        parent::__construct($appName, $request);
112
+        $this->l10n = $l10n;
113
+        $this->config = $config;
114
+        $this->navigationManager = $navigationManager;
115
+        $this->appManager = $appManager;
116
+        $this->categoryFetcher = $categoryFetcher;
117
+        $this->appFetcher = $appFetcher;
118
+        $this->l10nFactory = $l10nFactory;
119
+        $this->bundleFetcher = $bundleFetcher;
120
+        $this->installer = $installer;
121
+        $this->urlGenerator = $urlGenerator;
122
+        $this->logger = $logger;
123
+    }
124
+
125
+    /**
126
+     * @NoCSRFRequired
127
+     *
128
+     * @return TemplateResponse
129
+     */
130
+    public function viewApps(): TemplateResponse {
131
+        \OC_Util::addScript('settings', 'apps');
132
+        $params = [];
133
+        $params['appstoreEnabled'] = $this->config->getSystemValue('appstoreenabled', true) === true;
134
+        $params['updateCount'] = count($this->getAppsWithUpdates());
135
+        $params['developerDocumentation'] = $this->urlGenerator->linkToDocs('developer-manual');
136
+        $params['bundles'] = $this->getBundles();
137
+        $this->navigationManager->setActiveEntry('core_apps');
138
+
139
+        $templateResponse = new TemplateResponse('settings', 'settings-vue', ['serverData' => $params]);
140
+        $policy = new ContentSecurityPolicy();
141
+        $policy->addAllowedImageDomain('https://usercontent.apps.nextcloud.com');
142
+        $templateResponse->setContentSecurityPolicy($policy);
143
+
144
+        return $templateResponse;
145
+    }
146
+
147
+    private function getAppsWithUpdates() {
148
+        $appClass = new \OC_App();
149
+        $apps = $appClass->listAllApps();
150
+        foreach($apps as $key => $app) {
151
+            $newVersion = $this->installer->isUpdateAvailable($app['id']);
152
+            if($newVersion === false) {
153
+                unset($apps[$key]);
154
+            }
155
+        }
156
+        return $apps;
157
+    }
158
+
159
+    private function getBundles() {
160
+        $result = [];
161
+        $bundles = $this->bundleFetcher->getBundles();
162
+        foreach ($bundles as $bundle) {
163
+            $result[] = [
164
+                'name' => $bundle->getName(),
165
+                'id' => $bundle->getIdentifier(),
166
+                'appIdentifiers' => $bundle->getAppIdentifiers()
167
+            ];
168
+        }
169
+        return $result;
170
+
171
+    }
172
+
173
+    /**
174
+     * Get all available categories
175
+     *
176
+     * @return JSONResponse
177
+     */
178
+    public function listCategories(): JSONResponse {
179
+        return new JSONResponse($this->getAllCategories());
180
+    }
181
+
182
+    private function getAllCategories() {
183
+        $currentLanguage = substr($this->l10nFactory->findLanguage(), 0, 2);
184
+
185
+        $formattedCategories = [];
186
+        $categories = $this->categoryFetcher->get();
187
+        foreach($categories as $category) {
188
+            $formattedCategories[] = [
189
+                'id' => $category['id'],
190
+                'ident' => $category['id'],
191
+                'displayName' => isset($category['translations'][$currentLanguage]['name']) ? $category['translations'][$currentLanguage]['name'] : $category['translations']['en']['name'],
192
+            ];
193
+        }
194
+
195
+        return $formattedCategories;
196
+    }
197
+
198
+    private function fetchApps() {
199
+        $appClass = new \OC_App();
200
+        $apps = $appClass->listAllApps();
201
+        foreach ($apps as $app) {
202
+            $app['installed'] = true;
203
+            $this->allApps[$app['id']] = $app;
204
+        }
205
+
206
+        $apps = $this->getAppsForCategory('');
207
+        foreach ($apps as $app) {
208
+            $app['appstore'] = true;
209
+            if (!array_key_exists($app['id'], $this->allApps)) {
210
+                $this->allApps[$app['id']] = $app;
211
+            } else {
212
+                $this->allApps[$app['id']] = array_merge($app, $this->allApps[$app['id']]);
213
+            }
214
+        }
215
+
216
+        // add bundle information
217
+        $bundles = $this->bundleFetcher->getBundles();
218
+        foreach($bundles as $bundle) {
219
+            foreach($bundle->getAppIdentifiers() as $identifier) {
220
+                foreach($this->allApps as &$app) {
221
+                    if($app['id'] === $identifier) {
222
+                        $app['bundleIds'][] = $bundle->getIdentifier();
223
+                        continue;
224
+                    }
225
+                }
226
+            }
227
+        }
228
+    }
229
+
230
+    private function getAllApps() {
231
+        return $this->allApps;
232
+    }
233
+    /**
234
+     * Get all available apps in a category
235
+     *
236
+     * @param string $category
237
+     * @return JSONResponse
238
+     * @throws \Exception
239
+     */
240
+    public function listApps(): JSONResponse {
241
+
242
+        $this->fetchApps();
243
+        $apps = $this->getAllApps();
244
+
245
+        $dependencyAnalyzer = new DependencyAnalyzer(new Platform($this->config), $this->l10n);
246
+
247
+        // Extend existing app details
248
+        $apps = array_map(function($appData) use ($dependencyAnalyzer) {
249
+            if (isset($appData['appstoreData'])) {
250
+                $appstoreData = $appData['appstoreData'];
251
+                $appData['screenshot'] = isset($appstoreData['screenshots'][0]['url']) ? 'https://usercontent.apps.nextcloud.com/' . base64_encode($appstoreData['screenshots'][0]['url']) : '';
252
+                $appData['category'] = $appstoreData['categories'];
253
+            }
254
+
255
+            $newVersion = $this->installer->isUpdateAvailable($appData['id']);
256
+            if($newVersion) {
257
+                $appData['update'] = $newVersion;
258
+            }
259
+
260
+            // fix groups to be an array
261
+            $groups = [];
262
+            if (is_string($appData['groups'])) {
263
+                $groups = json_decode($appData['groups']);
264
+            }
265
+            $appData['groups'] = $groups;
266
+            $appData['canUnInstall'] = !$appData['active'] && $appData['removable'];
267
+
268
+            // fix licence vs license
269
+            if (isset($appData['license']) && !isset($appData['licence'])) {
270
+                $appData['licence'] = $appData['license'];
271
+            }
272
+
273
+            $ignoreMaxApps = $this->config->getSystemValue('app_install_overwrite', []);
274
+            if (!is_array($ignoreMaxApps)) {
275
+                $this->logger->warning('The value given for app_install_overwrite is not an array. Ignoring...');
276
+                $ignoreMaxApps = [];
277
+            }
278
+            $ignoreMax = in_array($appData['id'], $ignoreMaxApps);
279
+
280
+            // analyse dependencies
281
+            $missing = $dependencyAnalyzer->analyze($appData, $ignoreMax);
282
+            $appData['canInstall'] = empty($missing);
283
+            $appData['missingDependencies'] = $missing;
284
+
285
+            $appData['missingMinOwnCloudVersion'] = !isset($appData['dependencies']['nextcloud']['@attributes']['min-version']);
286
+            $appData['missingMaxOwnCloudVersion'] = !isset($appData['dependencies']['nextcloud']['@attributes']['max-version']);
287
+            $appData['isCompatible'] = $dependencyAnalyzer->isMarkedCompatible($appData);
288
+
289
+            return $appData;
290
+        }, $apps);
291
+
292
+        usort($apps, [$this, 'sortApps']);
293
+
294
+        return new JSONResponse(['apps' => $apps, 'status' => 'success']);
295
+    }
296
+
297
+    /**
298
+     * Get all apps for a category from the app store
299
+     *
300
+     * @param string $requestedCategory
301
+     * @return array
302
+     * @throws \Exception
303
+     */
304
+    private function getAppsForCategory($requestedCategory = ''): array {
305
+        $versionParser = new VersionParser();
306
+        $formattedApps = [];
307
+        $apps = $this->appFetcher->get();
308
+        foreach($apps as $app) {
309
+            // Skip all apps not in the requested category
310
+            if ($requestedCategory !== '') {
311
+                $isInCategory = false;
312
+                foreach($app['categories'] as $category) {
313
+                    if($category === $requestedCategory) {
314
+                        $isInCategory = true;
315
+                    }
316
+                }
317
+                if(!$isInCategory) {
318
+                    continue;
319
+                }
320
+            }
321
+
322
+            if (!isset($app['releases'][0]['rawPlatformVersionSpec'])) {
323
+                continue;
324
+            }
325
+            $nextCloudVersion = $versionParser->getVersion($app['releases'][0]['rawPlatformVersionSpec']);
326
+            $nextCloudVersionDependencies = [];
327
+            if($nextCloudVersion->getMinimumVersion() !== '') {
328
+                $nextCloudVersionDependencies['nextcloud']['@attributes']['min-version'] = $nextCloudVersion->getMinimumVersion();
329
+            }
330
+            if($nextCloudVersion->getMaximumVersion() !== '') {
331
+                $nextCloudVersionDependencies['nextcloud']['@attributes']['max-version'] = $nextCloudVersion->getMaximumVersion();
332
+            }
333
+            $phpVersion = $versionParser->getVersion($app['releases'][0]['rawPhpVersionSpec']);
334
+            $existsLocally = \OC_App::getAppPath($app['id']) !== false;
335
+            $phpDependencies = [];
336
+            if($phpVersion->getMinimumVersion() !== '') {
337
+                $phpDependencies['php']['@attributes']['min-version'] = $phpVersion->getMinimumVersion();
338
+            }
339
+            if($phpVersion->getMaximumVersion() !== '') {
340
+                $phpDependencies['php']['@attributes']['max-version'] = $phpVersion->getMaximumVersion();
341
+            }
342
+            if(isset($app['releases'][0]['minIntSize'])) {
343
+                $phpDependencies['php']['@attributes']['min-int-size'] = $app['releases'][0]['minIntSize'];
344
+            }
345
+            $authors = '';
346
+            foreach($app['authors'] as $key => $author) {
347
+                $authors .= $author['name'];
348
+                if($key !== count($app['authors']) - 1) {
349
+                    $authors .= ', ';
350
+                }
351
+            }
352
+
353
+            $currentLanguage = substr(\OC::$server->getL10NFactory()->findLanguage(), 0, 2);
354
+            $enabledValue = $this->config->getAppValue($app['id'], 'enabled', 'no');
355
+            $groups = null;
356
+            if($enabledValue !== 'no' && $enabledValue !== 'yes') {
357
+                $groups = $enabledValue;
358
+            }
359
+
360
+            $currentVersion = '';
361
+            if($this->appManager->isInstalled($app['id'])) {
362
+                $currentVersion = $this->appManager->getAppVersion($app['id']);
363
+            } else {
364
+                $currentLanguage = $app['releases'][0]['version'];
365
+            }
366
+
367
+            $formattedApps[] = [
368
+                'id' => $app['id'],
369
+                'name' => isset($app['translations'][$currentLanguage]['name']) ? $app['translations'][$currentLanguage]['name'] : $app['translations']['en']['name'],
370
+                'description' => isset($app['translations'][$currentLanguage]['description']) ? $app['translations'][$currentLanguage]['description'] : $app['translations']['en']['description'],
371
+                'summary' => isset($app['translations'][$currentLanguage]['summary']) ? $app['translations'][$currentLanguage]['summary'] : $app['translations']['en']['summary'],
372
+                'license' => $app['releases'][0]['licenses'],
373
+                'author' => $authors,
374
+                'shipped' => false,
375
+                'version' => $currentVersion,
376
+                'default_enable' => '',
377
+                'types' => [],
378
+                'documentation' => [
379
+                    'admin' => $app['adminDocs'],
380
+                    'user' => $app['userDocs'],
381
+                    'developer' => $app['developerDocs']
382
+                ],
383
+                'website' => $app['website'],
384
+                'bugs' => $app['issueTracker'],
385
+                'detailpage' => $app['website'],
386
+                'dependencies' => array_merge(
387
+                    $nextCloudVersionDependencies,
388
+                    $phpDependencies
389
+                ),
390
+                'level' => ($app['isFeatured'] === true) ? 200 : 100,
391
+                'missingMaxOwnCloudVersion' => false,
392
+                'missingMinOwnCloudVersion' => false,
393
+                'canInstall' => true,
394
+                'screenshot' => isset($app['screenshots'][0]['url']) ? 'https://usercontent.apps.nextcloud.com/'.base64_encode($app['screenshots'][0]['url']) : '',
395
+                'score' => $app['ratingOverall'],
396
+                'ratingNumOverall' => $app['ratingNumOverall'],
397
+                'ratingNumThresholdReached' => $app['ratingNumOverall'] > 5,
398
+                'removable' => $existsLocally,
399
+                'active' => $this->appManager->isEnabledForUser($app['id']),
400
+                'needsDownload' => !$existsLocally,
401
+                'groups' => $groups,
402
+                'fromAppStore' => true,
403
+                'appstoreData' => $app,
404
+            ];
405
+        }
406
+
407
+        return $formattedApps;
408
+    }
409
+
410
+    /**
411
+     * @PasswordConfirmationRequired
412
+     *
413
+     * @param string $appId
414
+     * @param array $groups
415
+     * @return JSONResponse
416
+     */
417
+    public function enableApp(string $appId, array $groups = []): JSONResponse {
418
+        return $this->enableApps([$appId], $groups);
419
+    }
420
+
421
+    /**
422
+     * Enable one or more apps
423
+     *
424
+     * apps will be enabled for specific groups only if $groups is defined
425
+     *
426
+     * @PasswordConfirmationRequired
427
+     * @param array $appIds
428
+     * @param array $groups
429
+     * @return JSONResponse
430
+     */
431
+    public function enableApps(array $appIds, array $groups = []): JSONResponse {
432
+        try {
433
+            $updateRequired = false;
434
+
435
+            foreach ($appIds as $appId) {
436
+                $appId = OC_App::cleanAppId($appId);
437
+
438
+                // Check if app is already downloaded
439
+                /** @var Installer $installer */
440
+                $installer = \OC::$server->query(Installer::class);
441
+                $isDownloaded = $installer->isDownloaded($appId);
442
+
443
+                if(!$isDownloaded) {
444
+                    $installer->downloadApp($appId);
445
+                }
446
+
447
+                $installer->installApp($appId);
448
+
449
+                if (count($groups) > 0) {
450
+                    $this->appManager->enableAppForGroups($appId, $this->getGroupList($groups));
451
+                } else {
452
+                    $this->appManager->enableApp($appId);
453
+                }
454
+                if (\OC_App::shouldUpgrade($appId)) {
455
+                    $updateRequired = true;
456
+                }
457
+            }
458
+            return new JSONResponse(['data' => ['update_required' => $updateRequired]]);
459
+
460
+        } catch (\Exception $e) {
461
+            $this->logger->logException($e);
462
+            return new JSONResponse(['data' => ['message' => $e->getMessage()]], Http::STATUS_INTERNAL_SERVER_ERROR);
463
+        }
464
+    }
465
+
466
+    private function getGroupList(array $groups) {
467
+        $groupManager = \OC::$server->getGroupManager();
468
+        $groupsList = [];
469
+        foreach ($groups as $group) {
470
+            $groupItem = $groupManager->get($group);
471
+            if ($groupItem instanceof \OCP\IGroup) {
472
+                $groupsList[] = $groupManager->get($group);
473
+            }
474
+        }
475
+        return $groupsList;
476
+    }
477
+
478
+    /**
479
+     * @PasswordConfirmationRequired
480
+     *
481
+     * @param string $appId
482
+     * @return JSONResponse
483
+     */
484
+    public function disableApp(string $appId): JSONResponse {
485
+        return $this->disableApps([$appId]);
486
+    }
487
+
488
+    /**
489
+     * @PasswordConfirmationRequired
490
+     *
491
+     * @param array $appIds
492
+     * @return JSONResponse
493
+     */
494
+    public function disableApps(array $appIds): JSONResponse {
495
+        try {
496
+            foreach ($appIds as $appId) {
497
+                $appId = OC_App::cleanAppId($appId);
498
+                $this->appManager->disableApp($appId);
499
+            }
500
+            return new JSONResponse([]);
501
+        } catch (\Exception $e) {
502
+            $this->logger->logException($e);
503
+            return new JSONResponse(['data' => ['message' => $e->getMessage()]], Http::STATUS_INTERNAL_SERVER_ERROR);
504
+        }
505
+    }
506
+
507
+    /**
508
+     * @PasswordConfirmationRequired
509
+     *
510
+     * @param string $appId
511
+     * @return JSONResponse
512
+     */
513
+    public function uninstallApp(string $appId): JSONResponse {
514
+        $appId = OC_App::cleanAppId($appId);
515
+        $result = $this->installer->removeApp($appId);
516
+        if($result !== false) {
517
+            $this->appManager->clearAppsCache();
518
+            return new JSONResponse(['data' => ['appid' => $appId]]);
519
+        }
520
+        return new JSONResponse(['data' => ['message' => $this->l10n->t('Couldn\'t remove app.')]], Http::STATUS_INTERNAL_SERVER_ERROR);
521
+    }
522
+
523
+    /**
524
+     * @param string $appId
525
+     * @return JSONResponse
526
+     */
527
+    public function updateApp(string $appId): JSONResponse {
528
+        $appId = OC_App::cleanAppId($appId);
529
+
530
+        $this->config->setSystemValue('maintenance', true);
531
+        try {
532
+            $result = $this->installer->updateAppstoreApp($appId);
533
+            $this->config->setSystemValue('maintenance', false);
534
+        } catch (\Exception $ex) {
535
+            $this->config->setSystemValue('maintenance', false);
536
+            return new JSONResponse(['data' => ['message' => $ex->getMessage()]], Http::STATUS_INTERNAL_SERVER_ERROR);
537
+        }
538
+
539
+        if ($result !== false) {
540
+            return new JSONResponse(['data' => ['appid' => $appId]]);
541
+        }
542
+        return new JSONResponse(['data' => ['message' => $this->l10n->t('Couldn\'t update app.')]], Http::STATUS_INTERNAL_SERVER_ERROR);
543
+    }
544
+
545
+    private function sortApps($a, $b) {
546
+        $a = (string)$a['name'];
547
+        $b = (string)$b['name'];
548
+        if ($a === $b) {
549
+            return 0;
550
+        }
551
+        return ($a < $b) ? -1 : 1;
552
+    }
553
+
554
+    public function force(string $appId): JSONResponse {
555
+        $appId = OC_App::cleanAppId($appId);
556
+        $this->appManager->ignoreNextcloudRequirementForApp($appId);
557
+        return new JSONResponse();
558
+    }
559 559
 
560 560
 }
Please login to merge, or discard this patch.