Completed
Pull Request — master (#32)
by Blizzz
09:50
created

AllConfig::setUserValue()   B

Complexity

Conditions 4
Paths 6

Size

Total Lines 27
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 4
eloc 16
c 2
b 0
f 0
nc 6
nop 5
dl 0
loc 27
rs 8.5806
1
<?php
2
/**
3
 * @author Bart Visscher <[email protected]>
4
 * @author Joas Schilling <[email protected]>
5
 * @author Lukas Reschke <[email protected]>
6
 * @author Morris Jobke <[email protected]>
7
 * @author Robin Appelman <[email protected]>
8
 * @author Robin McCorkell <[email protected]>
9
 * @author Thomas Müller <[email protected]>
10
 * @author Vincent Petry <[email protected]>
11
 *
12
 * @copyright Copyright (c) 2016, ownCloud, Inc.
13
 * @license AGPL-3.0
14
 *
15
 * This code is free software: you can redistribute it and/or modify
16
 * it under the terms of the GNU Affero General Public License, version 3,
17
 * as published by the Free Software Foundation.
18
 *
19
 * This program is distributed in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
 * GNU Affero General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU Affero General Public License, version 3,
25
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
26
 *
27
 */
28
29
namespace OC;
30
use OCP\IDBConnection;
31
use OCP\PreConditionNotMetException;
32
33
/**
34
 * Class to combine all the configuration options ownCloud offers
35
 */
36
class AllConfig implements \OCP\IConfig {
37
	/** @var SystemConfig */
38
	private $systemConfig;
39
40
	/** @var IDBConnection */
41
	private $connection;
42
43
	/**
44
	 * 3 dimensional array with the following structure:
45
	 * [ $userId =>
46
	 *     [ $appId =>
47
	 *         [ $key => $value ]
48
	 *     ]
49
	 * ]
50
	 *
51
	 * database table: preferences
52
	 *
53
	 * methods that use this:
54
	 *   - setUserValue
55
	 *   - getUserValue
56
	 *   - getUserKeys
57
	 *   - deleteUserValue
58
	 *   - deleteAllUserValues
59
	 *   - deleteAppFromAllUsers
60
	 *
61
	 * @var array $userCache
62
	 */
63
	private $userCache = array();
64
65
	/**
66
	 * @param SystemConfig $systemConfig
67
	 */
68
	function __construct(SystemConfig $systemConfig) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
69
		$this->systemConfig = $systemConfig;
70
	}
71
72
	/**
73
	 * TODO - FIXME This fixes an issue with base.php that cause cyclic
74
	 * dependencies, especially with autoconfig setup
75
	 *
76
	 * Replace this by properly injected database connection. Currently the
77
	 * base.php triggers the getDatabaseConnection too early which causes in
78
	 * autoconfig setup case a too early distributed database connection and
79
	 * the autoconfig then needs to reinit all already initialized dependencies
80
	 * that use the database connection.
81
	 *
82
	 * otherwise a SQLite database is created in the wrong directory
83
	 * because the database connection was created with an uninitialized config
84
	 */
85
	private function fixDIInit() {
86
		if($this->connection === null) {
87
			$this->connection = \OC::$server->getDatabaseConnection();
88
		}
89
	}
90
91
	/**
92
	 * Sets and deletes system wide values
93
	 *
94
	 * @param array $configs Associative array with `key => value` pairs
95
	 *                       If value is null, the config key will be deleted
96
	 */
97
	public function setSystemValues(array $configs) {
98
		$this->systemConfig->setValues($configs);
99
	}
100
101
	/**
102
	 * Sets a new system wide value
103
	 *
104
	 * @param string $key the key of the value, under which will be saved
105
	 * @param mixed $value the value that should be stored
106
	 */
107
	public function setSystemValue($key, $value) {
108
		$this->systemConfig->setValue($key, $value);
109
	}
110
111
	/**
112
	 * Looks up a system wide defined value
113
	 *
114
	 * @param string $key the key of the value, under which it was saved
115
	 * @param mixed $default the default value to be returned if the value isn't set
116
	 * @return mixed the value or $default
117
	 */
118
	public function getSystemValue($key, $default = '') {
119
		return $this->systemConfig->getValue($key, $default);
120
	}
121
122
	/**
123
	 * Looks up a system wide defined value and filters out sensitive data
124
	 *
125
	 * @param string $key the key of the value, under which it was saved
126
	 * @param mixed $default the default value to be returned if the value isn't set
127
	 * @return mixed the value or $default
128
	 */
129
	public function getFilteredSystemValue($key, $default = '') {
130
		return $this->systemConfig->getFilteredValue($key, $default);
131
	}
132
133
	/**
134
	 * Delete a system wide defined value
135
	 *
136
	 * @param string $key the key of the value, under which it was saved
137
	 */
138
	public function deleteSystemValue($key) {
139
		$this->systemConfig->deleteValue($key);
140
	}
141
142
	/**
143
	 * Get all keys stored for an app
144
	 *
145
	 * @param string $appName the appName that we stored the value under
146
	 * @return string[] the keys stored for the app
147
	 */
148
	public function getAppKeys($appName) {
149
		return \OC::$server->getAppConfig()->getKeys($appName);
0 ignored issues
show
Deprecated Code introduced by
The method OCP\IAppConfig::getKeys() has been deprecated with message: 8.0.0 use method getAppKeys of \OCP\IConfig This function gets all keys of an app. Please note that the values are
not returned.

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

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

Loading history...
150
	}
151
152
	/**
153
	 * Writes a new app wide value
154
	 *
155
	 * @param string $appName the appName that we want to store the value under
156
	 * @param string $key the key of the value, under which will be saved
157
	 * @param string $value the value that should be stored
158
	 */
159
	public function setAppValue($appName, $key, $value) {
160
		\OC::$server->getAppConfig()->setValue($appName, $key, $value);
0 ignored issues
show
Deprecated Code introduced by
The method OCP\IAppConfig::setValue() has been deprecated with message: 8.0.0 use method setAppValue of \OCP\IConfig Sets a value. If the key did not exist before it will be created.

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

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

Loading history...
161
	}
162
163
	/**
164
	 * Looks up an app wide defined value
165
	 *
166
	 * @param string $appName the appName that we stored the value under
167
	 * @param string $key the key of the value, under which it was saved
168
	 * @param string $default the default value to be returned if the value isn't set
169
	 * @return string the saved value
170
	 */
171
	public function getAppValue($appName, $key, $default = '') {
172
		return \OC::$server->getAppConfig()->getValue($appName, $key, $default);
0 ignored issues
show
Deprecated Code introduced by
The method OCP\IAppConfig::getValue() has been deprecated with message: 8.0.0 use method getAppValue of \OCP\IConfig This function gets a value from the appconfig table. If the key does
not exist the default value will be returned

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

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

Loading history...
173
	}
174
175
	/**
176
	 * Delete an app wide defined value
177
	 *
178
	 * @param string $appName the appName that we stored the value under
179
	 * @param string $key the key of the value, under which it was saved
180
	 */
181
	public function deleteAppValue($appName, $key) {
182
		\OC::$server->getAppConfig()->deleteKey($appName, $key);
0 ignored issues
show
Deprecated Code introduced by
The method OCP\IAppConfig::deleteKey() has been deprecated with message: 8.0.0 use method deleteAppValue of \OCP\IConfig

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

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

Loading history...
183
	}
184
185
	/**
186
	 * Removes all keys in appconfig belonging to the app
187
	 *
188
	 * @param string $appName the appName the configs are stored under
189
	 */
190
	public function deleteAppValues($appName) {
191
		\OC::$server->getAppConfig()->deleteApp($appName);
0 ignored issues
show
Deprecated Code introduced by
The method OCP\IAppConfig::deleteApp() has been deprecated with message: 8.0.0 use method deleteAppValue of \OCP\IConfig Removes all keys in appconfig belonging to the app.

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

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

Loading history...
192
	}
193
194
195
	/**
196
	 * Set a user defined value
197
	 *
198
	 * @param string $userId the userId of the user that we want to store the value under
199
	 * @param string $appName the appName that we want to store the value under
200
	 * @param string $key the key under which the value is being stored
201
	 * @param string $value the value that you want to store
202
	 * @param string $preCondition only update if the config value was previously the value passed as $preCondition
203
	 * @throws \OCP\PreConditionNotMetException if a precondition is specified and is not met
204
	 */
205
	public function setUserValue($userId, $appName, $key, $value, $preCondition = null) {
206
		// TODO - FIXME
207
		$this->fixDIInit();
208
209
		$preconditionArray = [];
210
		if (isset($preCondition)) {
211
			$preconditionArray = [
212
				'configvalue' => $preCondition,
213
			];
214
		}
215
216
		$this->connection->setValues('preferences', [
217
			'userid' => $userId,
218
			'appid' => $appName,
219
			'configkey' => $key,
220
		], [
221
			'configvalue' => $value,
222
		], $preconditionArray);
223
224
		// only add to the cache if we already loaded data for the user
225
		if (isset($this->userCache[$userId])) {
226
			if (!isset($this->userCache[$userId][$appName])) {
227
				$this->userCache[$userId][$appName] = array();
228
			}
229
			$this->userCache[$userId][$appName][$key] = $value;
230
		}
231
	}
232
233
	/**
234
	 * Getting a user defined value
235
	 *
236
	 * @param string $userId the userId of the user that we want to store the value under
237
	 * @param string $appName the appName that we stored the value under
238
	 * @param string $key the key under which the value is being stored
239
	 * @param mixed $default the default value to be returned if the value isn't set
240
	 * @return string
241
	 */
242
	public function getUserValue($userId, $appName, $key, $default = '') {
243
		$data = $this->getUserValues($userId);
244
		if (isset($data[$appName]) and isset($data[$appName][$key])) {
245
			return $data[$appName][$key];
246
		} else {
247
			return $default;
248
		}
249
	}
250
251
	/**
252
	 * Get the keys of all stored by an app for the user
253
	 *
254
	 * @param string $userId the userId of the user that we want to store the value under
255
	 * @param string $appName the appName that we stored the value under
256
	 * @return string[]
257
	 */
258
	public function getUserKeys($userId, $appName) {
259
		$data = $this->getUserValues($userId);
260
		if (isset($data[$appName])) {
261
			return array_keys($data[$appName]);
262
		} else {
263
			return array();
264
		}
265
	}
266
267
	/**
268
	 * Delete a user value
269
	 *
270
	 * @param string $userId the userId of the user that we want to store the value under
271
	 * @param string $appName the appName that we stored the value under
272
	 * @param string $key the key under which the value is being stored
273
	 */
274
	public function deleteUserValue($userId, $appName, $key) {
275
		// TODO - FIXME
276
		$this->fixDIInit();
277
278
		$sql  = 'DELETE FROM `*PREFIX*preferences` '.
279
				'WHERE `userid` = ? AND `appid` = ? AND `configkey` = ?';
280
		$this->connection->executeUpdate($sql, array($userId, $appName, $key));
281
282
		if (isset($this->userCache[$userId]) and isset($this->userCache[$userId][$appName])) {
283
			unset($this->userCache[$userId][$appName][$key]);
284
		}
285
	}
286
287
	/**
288
	 * Delete all user values
289
	 *
290
	 * @param string $userId the userId of the user that we want to remove all values from
291
	 */
292
	public function deleteAllUserValues($userId) {
293
		// TODO - FIXME
294
		$this->fixDIInit();
295
296
		$sql  = 'DELETE FROM `*PREFIX*preferences` '.
297
			'WHERE `userid` = ?';
298
		$this->connection->executeUpdate($sql, array($userId));
299
300
		unset($this->userCache[$userId]);
301
	}
302
303
	/**
304
	 * Delete all user related values of one app
305
	 *
306
	 * @param string $appName the appName of the app that we want to remove all values from
307
	 */
308
	public function deleteAppFromAllUsers($appName) {
309
		// TODO - FIXME
310
		$this->fixDIInit();
311
312
		$sql  = 'DELETE FROM `*PREFIX*preferences` '.
313
				'WHERE `appid` = ?';
314
		$this->connection->executeUpdate($sql, array($appName));
315
316
		foreach ($this->userCache as &$userCache) {
317
			unset($userCache[$appName]);
318
		}
319
	}
320
321
	/**
322
	 * Returns all user configs sorted by app of one user
323
	 *
324
	 * @param string $userId the user ID to get the app configs from
325
	 * @return array[] - 2 dimensional array with the following structure:
326
	 *     [ $appId =>
327
	 *         [ $key => $value ]
328
	 *     ]
329
	 */
330
	private function getUserValues($userId) {
331
		// TODO - FIXME
332
		$this->fixDIInit();
333
334
		if (isset($this->userCache[$userId])) {
335
			return $this->userCache[$userId];
336
		}
337
		$data = array();
338
		$query = 'SELECT `appid`, `configkey`, `configvalue` FROM `*PREFIX*preferences` WHERE `userid` = ?';
339
		$result = $this->connection->executeQuery($query, array($userId));
340
		while ($row = $result->fetch()) {
341
			$appId = $row['appid'];
342
			if (!isset($data[$appId])) {
343
				$data[$appId] = array();
344
			}
345
			$data[$appId][$row['configkey']] = $row['configvalue'];
346
		}
347
		$this->userCache[$userId] = $data;
348
		return $data;
349
	}
350
351
	/**
352
	 * Fetches a mapped list of userId -> value, for a specified app and key and a list of user IDs.
353
	 *
354
	 * @param string $appName app to get the value for
355
	 * @param string $key the key to get the value for
356
	 * @param array $userIds the user IDs to fetch the values for
357
	 * @return array Mapped values: userId => value
358
	 */
359
	public function getUserValueForUsers($appName, $key, $userIds) {
360
		// TODO - FIXME
361
		$this->fixDIInit();
362
363
		if (empty($userIds) || !is_array($userIds)) {
364
			return array();
365
		}
366
367
		$chunkedUsers = array_chunk($userIds, 50, true);
368
		$placeholders50 = implode(',', array_fill(0, 50, '?'));
369
370
		$userValues = array();
371
		foreach ($chunkedUsers as $chunk) {
372
			$queryParams = $chunk;
373
			// create [$app, $key, $chunkedUsers]
374
			array_unshift($queryParams, $key);
375
			array_unshift($queryParams, $appName);
376
377
			$placeholders = (sizeof($chunk) == 50) ? $placeholders50 :  implode(',', array_fill(0, sizeof($chunk), '?'));
378
379
			$query    = 'SELECT `userid`, `configvalue` ' .
380
						'FROM `*PREFIX*preferences` ' .
381
						'WHERE `appid` = ? AND `configkey` = ? ' .
382
						'AND `userid` IN (' . $placeholders . ')';
383
			$result = $this->connection->executeQuery($query, $queryParams);
384
385
			while ($row = $result->fetch()) {
386
				$userValues[$row['userid']] = $row['configvalue'];
387
			}
388
		}
389
390
		return $userValues;
391
	}
392
393
	/**
394
	 * Determines the users that have the given value set for a specific app-key-pair
395
	 *
396
	 * @param string $appName the app to get the user for
397
	 * @param string $key the key to get the user for
398
	 * @param string $value the value to get the user for
399
	 * @return array of user IDs
400
	 */
401
	public function getUsersForUserValue($appName, $key, $value) {
402
		// TODO - FIXME
403
		$this->fixDIInit();
404
405
		$sql  = 'SELECT `userid` FROM `*PREFIX*preferences` ' .
406
				'WHERE `appid` = ? AND `configkey` = ? ';
407
408
		if($this->getSystemValue('dbtype', 'sqlite') === 'oci') {
409
			//oracle hack: need to explicitly cast CLOB to CHAR for comparison
410
			$sql .= 'AND to_char(`configvalue`) = ?';
411
		} else {
412
			$sql .= 'AND `configvalue` = ?';
413
		}
414
415
		$result = $this->connection->executeQuery($sql, array($appName, $key, $value));
416
417
		$userIDs = array();
418
		while ($row = $result->fetch()) {
419
			$userIDs[] = $row['userid'];
420
		}
421
422
		return $userIDs;
423
	}
424
}
425