Completed
Push — stable9 ( 485cb1...e094cf )
by Lukas
26:41 queued 26:23
created

lib/private/allconfig.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Bart Visscher <[email protected]>
6
 * @author Joas Schilling <[email protected]>
7
 * @author Jörn Friedrich Dreyer <[email protected]>
8
 * @author Lukas Reschke <[email protected]>
9
 * @author Morris Jobke <[email protected]>
10
 * @author Robin Appelman <[email protected]>
11
 * @author Robin McCorkell <[email protected]>
12
 * @author Thomas Müller <[email protected]>
13
 * @author Vincent Petry <[email protected]>
14
 *
15
 * @license AGPL-3.0
16
 *
17
 * This code is free software: you can redistribute it and/or modify
18
 * it under the terms of the GNU Affero General Public License, version 3,
19
 * as published by the Free Software Foundation.
20
 *
21
 * This program is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24
 * GNU Affero General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU Affero General Public License, version 3,
27
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
28
 *
29
 */
30
31
namespace OC;
32
use OC\Cache\CappedMemoryCache;
33
use OCP\IDBConnection;
34
use OCP\PreConditionNotMetException;
35
36
/**
37
 * Class to combine all the configuration options ownCloud offers
38
 */
39
class AllConfig implements \OCP\IConfig {
40
	/** @var SystemConfig */
41
	private $systemConfig;
42
43
	/** @var IDBConnection */
44
	private $connection;
45
46
	/**
47
	 * 3 dimensional array with the following structure:
48
	 * [ $userId =>
49
	 *     [ $appId =>
50
	 *         [ $key => $value ]
51
	 *     ]
52
	 * ]
53
	 *
54
	 * database table: preferences
55
	 *
56
	 * methods that use this:
57
	 *   - setUserValue
58
	 *   - getUserValue
59
	 *   - getUserKeys
60
	 *   - deleteUserValue
61
	 *   - deleteAllUserValues
62
	 *   - deleteAppFromAllUsers
63
	 *
64
	 * @var CappedMemoryCache $userCache
65
	 */
66
	private $userCache;
67
68
	/**
69
	 * @param SystemConfig $systemConfig
70
	 */
71
	function __construct(SystemConfig $systemConfig) {
72
		$this->userCache = new CappedMemoryCache();
73
		$this->systemConfig = $systemConfig;
74
	}
75
76
	/**
77
	 * TODO - FIXME This fixes an issue with base.php that cause cyclic
78
	 * dependencies, especially with autoconfig setup
79
	 *
80
	 * Replace this by properly injected database connection. Currently the
81
	 * base.php triggers the getDatabaseConnection too early which causes in
82
	 * autoconfig setup case a too early distributed database connection and
83
	 * the autoconfig then needs to reinit all already initialized dependencies
84
	 * that use the database connection.
85
	 *
86
	 * otherwise a SQLite database is created in the wrong directory
87
	 * because the database connection was created with an uninitialized config
88
	 */
89
	private function fixDIInit() {
90
		if($this->connection === null) {
91
			$this->connection = \OC::$server->getDatabaseConnection();
92
		}
93
	}
94
95
	/**
96
	 * Sets and deletes system wide values
97
	 *
98
	 * @param array $configs Associative array with `key => value` pairs
99
	 *                       If value is null, the config key will be deleted
100
	 */
101
	public function setSystemValues(array $configs) {
102
		$this->systemConfig->setValues($configs);
103
	}
104
105
	/**
106
	 * Sets a new system wide value
107
	 *
108
	 * @param string $key the key of the value, under which will be saved
109
	 * @param mixed $value the value that should be stored
110
	 */
111
	public function setSystemValue($key, $value) {
112
		$this->systemConfig->setValue($key, $value);
113
	}
114
115
	/**
116
	 * Looks up a system wide defined value
117
	 *
118
	 * @param string $key the key of the value, under which it was saved
119
	 * @param mixed $default the default value to be returned if the value isn't set
120
	 * @return mixed the value or $default
121
	 */
122
	public function getSystemValue($key, $default = '') {
123
		return $this->systemConfig->getValue($key, $default);
124
	}
125
126
	/**
127
	 * Looks up a system wide defined value and filters out sensitive data
128
	 *
129
	 * @param string $key the key of the value, under which it was saved
130
	 * @param mixed $default the default value to be returned if the value isn't set
131
	 * @return mixed the value or $default
132
	 */
133
	public function getFilteredSystemValue($key, $default = '') {
134
		return $this->systemConfig->getFilteredValue($key, $default);
135
	}
136
137
	/**
138
	 * Delete a system wide defined value
139
	 *
140
	 * @param string $key the key of the value, under which it was saved
141
	 */
142
	public function deleteSystemValue($key) {
143
		$this->systemConfig->deleteValue($key);
144
	}
145
146
	/**
147
	 * Get all keys stored for an app
148
	 *
149
	 * @param string $appName the appName that we stored the value under
150
	 * @return string[] the keys stored for the app
151
	 */
152
	public function getAppKeys($appName) {
153
		return \OC::$server->getAppConfig()->getKeys($appName);
154
	}
155
156
	/**
157
	 * Writes a new app wide value
158
	 *
159
	 * @param string $appName the appName that we want to store the value under
160
	 * @param string $key the key of the value, under which will be saved
161
	 * @param string $value the value that should be stored
162
	 */
163
	public function setAppValue($appName, $key, $value) {
164
		\OC::$server->getAppConfig()->setValue($appName, $key, $value);
165
	}
166
167
	/**
168
	 * Looks up an app wide defined value
169
	 *
170
	 * @param string $appName the appName that we stored the value under
171
	 * @param string $key the key of the value, under which it was saved
172
	 * @param string $default the default value to be returned if the value isn't set
173
	 * @return string the saved value
174
	 */
175
	public function getAppValue($appName, $key, $default = '') {
176
		return \OC::$server->getAppConfig()->getValue($appName, $key, $default);
177
	}
178
179
	/**
180
	 * Delete an app wide defined value
181
	 *
182
	 * @param string $appName the appName that we stored the value under
183
	 * @param string $key the key of the value, under which it was saved
184
	 */
185
	public function deleteAppValue($appName, $key) {
186
		\OC::$server->getAppConfig()->deleteKey($appName, $key);
187
	}
188
189
	/**
190
	 * Removes all keys in appconfig belonging to the app
191
	 *
192
	 * @param string $appName the appName the configs are stored under
193
	 */
194
	public function deleteAppValues($appName) {
195
		\OC::$server->getAppConfig()->deleteApp($appName);
196
	}
197
198
199
	/**
200
	 * Set a user defined value
201
	 *
202
	 * @param string $userId the userId of the user that we want to store the value under
203
	 * @param string $appName the appName that we want to store the value under
204
	 * @param string $key the key under which the value is being stored
205
	 * @param string $value the value that you want to store
206
	 * @param string $preCondition only update if the config value was previously the value passed as $preCondition
207
	 * @throws \OCP\PreConditionNotMetException if a precondition is specified and is not met
208
	 */
209
	public function setUserValue($userId, $appName, $key, $value, $preCondition = null) {
210
		// TODO - FIXME
211
		$this->fixDIInit();
212
213
		$preconditionArray = [];
214
		if (isset($preCondition)) {
215
			$preconditionArray = [
216
				'configvalue' => $preCondition,
217
			];
218
		}
219
220
		$this->connection->setValues('preferences', [
221
			'userid' => $userId,
222
			'appid' => $appName,
223
			'configkey' => $key,
224
		], [
225
			'configvalue' => $value,
226
		], $preconditionArray);
227
228
		// only add to the cache if we already loaded data for the user
229
		if (isset($this->userCache[$userId])) {
230
			if (!isset($this->userCache[$userId][$appName])) {
231
				$this->userCache[$userId][$appName] = array();
232
			}
233
			$this->userCache[$userId][$appName][$key] = $value;
234
		}
235
	}
236
237
	/**
238
	 * Getting a user defined value
239
	 *
240
	 * @param string $userId the userId of the user that we want to store the value under
241
	 * @param string $appName the appName that we stored the value under
242
	 * @param string $key the key under which the value is being stored
243
	 * @param mixed $default the default value to be returned if the value isn't set
244
	 * @return string
245
	 */
246
	public function getUserValue($userId, $appName, $key, $default = '') {
247
		$data = $this->getUserValues($userId);
248
		if (isset($data[$appName]) and isset($data[$appName][$key])) {
249
			return $data[$appName][$key];
250
		} else {
251
			return $default;
252
		}
253
	}
254
255
	/**
256
	 * Get the keys of all stored by an app for the user
257
	 *
258
	 * @param string $userId the userId of the user that we want to store the value under
259
	 * @param string $appName the appName that we stored the value under
260
	 * @return string[]
261
	 */
262
	public function getUserKeys($userId, $appName) {
263
		$data = $this->getUserValues($userId);
264
		if (isset($data[$appName])) {
265
			return array_keys($data[$appName]);
266
		} else {
267
			return array();
268
		}
269
	}
270
271
	/**
272
	 * Delete a user value
273
	 *
274
	 * @param string $userId the userId of the user that we want to store the value under
275
	 * @param string $appName the appName that we stored the value under
276
	 * @param string $key the key under which the value is being stored
277
	 */
278
	public function deleteUserValue($userId, $appName, $key) {
279
		// TODO - FIXME
280
		$this->fixDIInit();
281
282
		$sql  = 'DELETE FROM `*PREFIX*preferences` '.
283
				'WHERE `userid` = ? AND `appid` = ? AND `configkey` = ?';
284
		$this->connection->executeUpdate($sql, array($userId, $appName, $key));
285
286
		if (isset($this->userCache[$userId]) and isset($this->userCache[$userId][$appName])) {
287
			unset($this->userCache[$userId][$appName][$key]);
288
		}
289
	}
290
291
	/**
292
	 * Delete all user values
293
	 *
294
	 * @param string $userId the userId of the user that we want to remove all values from
295
	 */
296
	public function deleteAllUserValues($userId) {
297
		// TODO - FIXME
298
		$this->fixDIInit();
299
300
		$sql  = 'DELETE FROM `*PREFIX*preferences` '.
301
			'WHERE `userid` = ?';
302
		$this->connection->executeUpdate($sql, array($userId));
303
304
		unset($this->userCache[$userId]);
305
	}
306
307
	/**
308
	 * Delete all user related values of one app
309
	 *
310
	 * @param string $appName the appName of the app that we want to remove all values from
311
	 */
312
	public function deleteAppFromAllUsers($appName) {
313
		// TODO - FIXME
314
		$this->fixDIInit();
315
316
		$sql  = 'DELETE FROM `*PREFIX*preferences` '.
317
				'WHERE `appid` = ?';
318
		$this->connection->executeUpdate($sql, array($appName));
319
320
		foreach ($this->userCache as &$userCache) {
0 ignored issues
show
The expression $this->userCache of type object<OC\Cache\CappedMemoryCache> is not traversable.
Loading history...
321
			unset($userCache[$appName]);
322
		}
323
	}
324
325
	/**
326
	 * Returns all user configs sorted by app of one user
327
	 *
328
	 * @param string $userId the user ID to get the app configs from
329
	 * @return array[] - 2 dimensional array with the following structure:
330
	 *     [ $appId =>
331
	 *         [ $key => $value ]
332
	 *     ]
333
	 */
334
	private function getUserValues($userId) {
335
		// TODO - FIXME
336
		$this->fixDIInit();
337
338
		if (isset($this->userCache[$userId])) {
339
			return $this->userCache[$userId];
340
		}
341
		$data = array();
342
		$query = 'SELECT `appid`, `configkey`, `configvalue` FROM `*PREFIX*preferences` WHERE `userid` = ?';
343
		$result = $this->connection->executeQuery($query, array($userId));
344
		while ($row = $result->fetch()) {
345
			$appId = $row['appid'];
346
			if (!isset($data[$appId])) {
347
				$data[$appId] = array();
348
			}
349
			$data[$appId][$row['configkey']] = $row['configvalue'];
350
		}
351
		$this->userCache[$userId] = $data;
352
		return $data;
353
	}
354
355
	/**
356
	 * Fetches a mapped list of userId -> value, for a specified app and key and a list of user IDs.
357
	 *
358
	 * @param string $appName app to get the value for
359
	 * @param string $key the key to get the value for
360
	 * @param array $userIds the user IDs to fetch the values for
361
	 * @return array Mapped values: userId => value
362
	 */
363
	public function getUserValueForUsers($appName, $key, $userIds) {
364
		// TODO - FIXME
365
		$this->fixDIInit();
366
367
		if (empty($userIds) || !is_array($userIds)) {
368
			return array();
369
		}
370
371
		$chunkedUsers = array_chunk($userIds, 50, true);
372
		$placeholders50 = implode(',', array_fill(0, 50, '?'));
373
374
		$userValues = array();
375
		foreach ($chunkedUsers as $chunk) {
376
			$queryParams = $chunk;
377
			// create [$app, $key, $chunkedUsers]
378
			array_unshift($queryParams, $key);
379
			array_unshift($queryParams, $appName);
380
381
			$placeholders = (sizeof($chunk) == 50) ? $placeholders50 :  implode(',', array_fill(0, sizeof($chunk), '?'));
382
383
			$query    = 'SELECT `userid`, `configvalue` ' .
384
						'FROM `*PREFIX*preferences` ' .
385
						'WHERE `appid` = ? AND `configkey` = ? ' .
386
						'AND `userid` IN (' . $placeholders . ')';
387
			$result = $this->connection->executeQuery($query, $queryParams);
388
389
			while ($row = $result->fetch()) {
390
				$userValues[$row['userid']] = $row['configvalue'];
391
			}
392
		}
393
394
		return $userValues;
395
	}
396
397
	/**
398
	 * Determines the users that have the given value set for a specific app-key-pair
399
	 *
400
	 * @param string $appName the app to get the user for
401
	 * @param string $key the key to get the user for
402
	 * @param string $value the value to get the user for
403
	 * @return array of user IDs
404
	 */
405
	public function getUsersForUserValue($appName, $key, $value) {
406
		// TODO - FIXME
407
		$this->fixDIInit();
408
409
		$sql  = 'SELECT `userid` FROM `*PREFIX*preferences` ' .
410
				'WHERE `appid` = ? AND `configkey` = ? ';
411
412
		if($this->getSystemValue('dbtype', 'sqlite') === 'oci') {
413
			//oracle hack: need to explicitly cast CLOB to CHAR for comparison
414
			$sql .= 'AND to_char(`configvalue`) = ?';
415
		} else {
416
			$sql .= 'AND `configvalue` = ?';
417
		}
418
419
		$result = $this->connection->executeQuery($sql, array($appName, $key, $value));
420
421
		$userIDs = array();
422
		while ($row = $result->fetch()) {
423
			$userIDs[] = $row['userid'];
424
		}
425
426
		return $userIDs;
427
	}
428
}
429