Completed
Push — master ( ad0d0b...75c437 )
by Morris
26:55 queued 13:45
created

AccountManager   A

Complexity

Total Complexity 35

Size/Duplication

Total Lines 304
Duplicated Lines 15.13 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 46
loc 304
rs 9
wmc 35
lcom 1
cbo 5

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A updateUser() 0 21 4
A deleteUser() 7 7 1
A getUser() 0 21 2
A checkEmailVerification() 0 17 2
A addMissingDefaultValues() 0 10 3
F updateVerifyStatus() 30 48 19
A insertNewUser() 0 13 1
A updateExistingUser() 9 9 1
B buildDefaultUserRecord() 0 44 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
/**
3
 * @author Björn Schießle <[email protected]>
4
 *
5
 * @copyright Copyright (c) 2016, ownCloud, Inc.
6
 * @copyright Copyright (c) 2016, Björn Schießle
7
 * @license AGPL-3.0
8
 *
9
 * This code is free software: you can redistribute it and/or modify
10
 * it under the terms of the GNU Affero General Public License, version 3,
11
 * as published by the Free Software Foundation.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
 * GNU Affero General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Affero General Public License, version 3,
19
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
20
 *
21
 */
22
23
24
namespace OC\Accounts;
25
26
use OCP\BackgroundJob\IJobList;
27
use OCP\IDBConnection;
28
use OCP\IUser;
29
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
30
use Symfony\Component\EventDispatcher\GenericEvent;
31
32
/**
33
 * Class AccountManager
34
 *
35
 * Manage system accounts table
36
 *
37
 * @group DB
38
 * @package OC\Accounts
39
 */
40
class AccountManager {
41
42
	/** nobody can see my account details */
43
	const VISIBILITY_PRIVATE = 'private';
44
	/** only contacts, especially trusted servers can see my contact details */
45
	const VISIBILITY_CONTACTS_ONLY = 'contacts';
46
	/** every body ca see my contact detail, will be published to the lookup server */
47
	const VISIBILITY_PUBLIC = 'public';
48
49
	const PROPERTY_AVATAR = 'avatar';
50
	const PROPERTY_DISPLAYNAME = 'displayname';
51
	const PROPERTY_PHONE = 'phone';
52
	const PROPERTY_EMAIL = 'email';
53
	const PROPERTY_WEBSITE = 'website';
54
	const PROPERTY_ADDRESS = 'address';
55
	const PROPERTY_TWITTER = 'twitter';
56
57
	const NOT_VERIFIED = '0';
58
	const VERIFICATION_IN_PROGRESS = '1';
59
	const VERIFIED = '2';
60
61
	/** @var  IDBConnection database connection */
62
	private $connection;
63
64
	/** @var string table name */
65
	private $table = 'accounts';
66
67
	/** @var EventDispatcherInterface */
68
	private $eventDispatcher;
69
70
	/** @var IJobList */
71
	private $jobList;
72
73
	/**
74
	 * AccountManager constructor.
75
	 *
76
	 * @param IDBConnection $connection
77
	 * @param EventDispatcherInterface $eventDispatcher
78
	 * @param IJobList $jobList
79
	 */
80
	public function __construct(IDBConnection $connection,
81
								EventDispatcherInterface $eventDispatcher,
82
								IJobList $jobList) {
83
		$this->connection = $connection;
84
		$this->eventDispatcher = $eventDispatcher;
85
		$this->jobList = $jobList;
86
	}
87
88
	/**
89
	 * update user record
90
	 *
91
	 * @param IUser $user
92
	 * @param $data
93
	 */
94
	public function updateUser(IUser $user, $data) {
95
		$userData = $this->getUser($user);
96
		$updated = true;
97
		if (empty($userData)) {
98
			$this->insertNewUser($user, $data);
99
		} elseif ($userData !== $data) {
100
			$data = $this->checkEmailVerification($userData, $data, $user);
101
			$data = $this->updateVerifyStatus($userData, $data);
102
			$this->updateExistingUser($user, $data);
103
		} else {
104
			// nothing needs to be done if new and old data set are the same
105
			$updated = false;
106
		}
107
108
		if ($updated) {
109
			$this->eventDispatcher->dispatch(
110
				'OC\AccountManager::userUpdated',
111
				new GenericEvent($user, $data)
112
			);
113
		}
114
	}
115
116
	/**
117
	 * delete user from accounts table
118
	 *
119
	 * @param IUser $user
120
	 */
121 View Code Duplication
	public function deleteUser(IUser $user) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
122
		$uid = $user->getUID();
123
		$query = $this->connection->getQueryBuilder();
124
		$query->delete($this->table)
125
			->where($query->expr()->eq('uid', $query->createNamedParameter($uid)))
126
			->execute();
127
	}
128
129
	/**
130
	 * get stored data from a given user
131
	 *
132
	 * @param IUser $user
133
	 * @return array
134
	 */
135
	public function getUser(IUser $user) {
136
		$uid = $user->getUID();
137
		$query = $this->connection->getQueryBuilder();
138
		$query->select('data')->from($this->table)
139
			->where($query->expr()->eq('uid', $query->createParameter('uid')))
140
			->setParameter('uid', $uid);
141
		$query->execute();
142
		$result = $query->execute()->fetchAll();
143
144
		if (empty($result)) {
145
			$userData = $this->buildDefaultUserRecord($user);
146
			$this->insertNewUser($user, $userData);
147
			return $userData;
148
		}
149
150
		$userDataArray = json_decode($result[0]['data'], true);
151
152
		$userDataArray = $this->addMissingDefaultValues($userDataArray);
153
154
		return $userDataArray;
155
	}
156
157
	/**
158
	 * check if we need to ask the server for email verification, if yes we create a cronjob
159
	 *
160
	 * @param $oldData
161
	 * @param $newData
162
	 * @param IUser $user
163
	 * @return array
164
	 */
165
	protected function checkEmailVerification($oldData, $newData, IUser $user) {
166
		if ($oldData[self::PROPERTY_EMAIL]['value'] !== $newData[self::PROPERTY_EMAIL]['value']) {
167
			$this->jobList->add('OC\Settings\BackgroundJobs\VerifyUserData',
168
				[
169
					'verificationCode' => '',
170
					'data' => $newData[self::PROPERTY_EMAIL]['value'],
171
					'type' => self::PROPERTY_EMAIL,
172
					'uid' => $user->getUID(),
173
					'try' => 0,
174
					'lastRun' => time()
175
				]
176
			);
177
			$newData[AccountManager::PROPERTY_EMAIL]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
178
		}
179
180
		return $newData;
181
	}
182
183
	/**
184
	 * make sure that all expected data are set
185
	 *
186
	 * @param array $userData
187
	 * @return array
188
	 */
189
	protected function addMissingDefaultValues(array $userData) {
190
191
		foreach ($userData as $key => $value) {
192
			if (!isset($userData[$key]['verified'])) {
193
				$userData[$key]['verified'] = self::NOT_VERIFIED;
194
			}
195
		}
196
197
		return $userData;
198
	}
199
200
	/**
201
	 * reset verification status if personal data changed
202
	 *
203
	 * @param array $oldData
204
	 * @param array $newData
205
	 * @return array
206
	 */
207
	protected function updateVerifyStatus($oldData, $newData) {
208
209
		// which account was already verified successfully?
210
		$twitterVerified = isset($oldData[self::PROPERTY_TWITTER]['verified']) && $oldData[self::PROPERTY_TWITTER]['verified'] === self::VERIFIED;
211
		$websiteVerified = isset($oldData[self::PROPERTY_WEBSITE]['verified']) && $oldData[self::PROPERTY_WEBSITE]['verified'] === self::VERIFIED;
212
		$emailVerified = isset($oldData[self::PROPERTY_EMAIL]['verified']) && $oldData[self::PROPERTY_EMAIL]['verified'] === self::VERIFIED;
213
214
		// keep old verification status if we don't have a new one
215 View Code Duplication
		if(!isset($newData[self::PROPERTY_TWITTER]['verified'])) {
216
			// keep old verification status if value didn't changed and an old value exists
217
			$keepOldStatus = $newData[self::PROPERTY_TWITTER]['value'] === $oldData[self::PROPERTY_TWITTER]['value'] && isset($oldData[self::PROPERTY_TWITTER]['verified']);
218
			$newData[self::PROPERTY_TWITTER]['verified'] = $keepOldStatus ? $oldData[self::PROPERTY_TWITTER]['verified'] : self::NOT_VERIFIED;
219
		}
220
221 View Code Duplication
		if(!isset($newData[self::PROPERTY_WEBSITE]['verified'])) {
222
			// keep old verification status if value didn't changed and an old value exists
223
			$keepOldStatus = $newData[self::PROPERTY_WEBSITE]['value'] === $oldData[self::PROPERTY_WEBSITE]['value'] && isset($oldData[self::PROPERTY_WEBSITE]['verified']);
224
			$newData[self::PROPERTY_WEBSITE]['verified'] = $keepOldStatus ? $oldData[self::PROPERTY_WEBSITE]['verified'] : self::NOT_VERIFIED;
225
		}
226
227 View Code Duplication
		if(!isset($newData[self::PROPERTY_EMAIL]['verified'])) {
228
			// keep old verification status if value didn't changed and an old value exists
229
			$keepOldStatus = $newData[self::PROPERTY_EMAIL]['value'] === $oldData[self::PROPERTY_EMAIL]['value'] && isset($oldData[self::PROPERTY_EMAIL]['verified']);
230
			$newData[self::PROPERTY_EMAIL]['verified'] = $keepOldStatus ? $oldData[self::PROPERTY_EMAIL]['verified'] : self::VERIFICATION_IN_PROGRESS;
231
		}
232
233
		// reset verification status if a value from a previously verified data was changed
234 View Code Duplication
		if($twitterVerified &&
235
			$oldData[self::PROPERTY_TWITTER]['value'] !== $newData[self::PROPERTY_TWITTER]['value']
236
		) {
237
			$newData[self::PROPERTY_TWITTER]['verified'] = self::NOT_VERIFIED;
238
		}
239
240 View Code Duplication
		if($websiteVerified &&
241
			$oldData[self::PROPERTY_WEBSITE]['value'] !== $newData[self::PROPERTY_WEBSITE]['value']
242
		) {
243
			$newData[self::PROPERTY_WEBSITE]['verified'] = self::NOT_VERIFIED;
244
		}
245
246 View Code Duplication
		if($emailVerified &&
247
			$oldData[self::PROPERTY_EMAIL]['value'] !== $newData[self::PROPERTY_EMAIL]['value']
248
		) {
249
			$newData[self::PROPERTY_EMAIL]['verified'] = self::NOT_VERIFIED;
250
		}
251
252
		return $newData;
253
254
	}
255
256
	/**
257
	 * add new user to accounts table
258
	 *
259
	 * @param IUser $user
260
	 * @param array $data
261
	 */
262
	protected function insertNewUser(IUser $user, $data) {
263
		$uid = $user->getUID();
264
		$jsonEncodedData = json_encode($data);
265
		$query = $this->connection->getQueryBuilder();
266
		$query->insert($this->table)
267
			->values(
268
				[
269
					'uid' => $query->createNamedParameter($uid),
270
					'data' => $query->createNamedParameter($jsonEncodedData),
271
				]
272
			)
273
			->execute();
274
	}
275
276
	/**
277
	 * update existing user in accounts table
278
	 *
279
	 * @param IUser $user
280
	 * @param array $data
281
	 */
282 View Code Duplication
	protected function updateExistingUser(IUser $user, $data) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
283
		$uid = $user->getUID();
284
		$jsonEncodedData = json_encode($data);
285
		$query = $this->connection->getQueryBuilder();
286
		$query->update($this->table)
287
			->set('data', $query->createNamedParameter($jsonEncodedData))
288
			->where($query->expr()->eq('uid', $query->createNamedParameter($uid)))
289
			->execute();
290
	}
291
292
	/**
293
	 * build default user record in case not data set exists yet
294
	 *
295
	 * @param IUser $user
296
	 * @return array
297
	 */
298
	protected function buildDefaultUserRecord(IUser $user) {
299
		return [
300
			self::PROPERTY_DISPLAYNAME =>
301
				[
302
					'value' => $user->getDisplayName(),
303
					'scope' => self::VISIBILITY_CONTACTS_ONLY,
304
					'verified' => self::NOT_VERIFIED,
305
				],
306
			self::PROPERTY_ADDRESS =>
307
				[
308
					'value' => '',
309
					'scope' => self::VISIBILITY_PRIVATE,
310
					'verified' => self::NOT_VERIFIED,
311
				],
312
			self::PROPERTY_WEBSITE =>
313
				[
314
					'value' => '',
315
					'scope' => self::VISIBILITY_PRIVATE,
316
					'verified' => self::NOT_VERIFIED,
317
				],
318
			self::PROPERTY_EMAIL =>
319
				[
320
					'value' => $user->getEMailAddress(),
321
					'scope' => self::VISIBILITY_CONTACTS_ONLY,
322
					'verified' => self::NOT_VERIFIED,
323
				],
324
			self::PROPERTY_AVATAR =>
325
				[
326
					'scope' => self::VISIBILITY_CONTACTS_ONLY
327
				],
328
			self::PROPERTY_PHONE =>
329
				[
330
					'value' => '',
331
					'scope' => self::VISIBILITY_PRIVATE,
332
					'verified' => self::NOT_VERIFIED,
333
				],
334
			self::PROPERTY_TWITTER =>
335
				[
336
					'value' => '',
337
					'scope' => self::VISIBILITY_PRIVATE,
338
					'verified' => self::NOT_VERIFIED,
339
				],
340
		];
341
	}
342
343
}
344