Completed
Push — master ( 96ed5e...b2d2f0 )
by Simon
01:52
created

User   F

Complexity

Total Complexity 125

Size/Duplication

Total Lines 888
Duplicated Lines 13.96 %

Coupling/Cohesion

Components 2
Dependencies 7

Importance

Changes 0
Metric Value
dl 124
loc 888
rs 1.712
c 0
b 0
f 0
wmc 125
lcom 2
cbo 7

72 Methods

Rating   Name   Duplication   Size   Complexity  
A getCurrent() 0 20 4
A getCommunity() 0 4 1
A getByUsername() 0 21 3
B getByOnWikiUsername() 22 51 6
A getByRequestToken() 16 16 2
A getAllWithStatus() 15 15 2
A getAllCheckusers() 0 23 3
A getAllInactive() 0 27 2
A getAllUsernames() 0 18 3
B save() 0 87 4
A authenticate() 0 14 3
A touchLastLogin() 0 5 1
A getUsername() 0 4 1
A setUsername() 0 5 1
A getEmail() 0 4 1
A setEmail() 0 4 1
A setPassword() 0 4 1
A getOnWikiName() 0 14 3
A getStoredOnWikiName() 0 4 1
A setOnWikiName() 0 4 1
A getWelcomeSig() 0 4 1
A setWelcomeSig() 0 4 1
A getLastActive() 0 4 1
A setLastActive() 0 4 1
A getForcelogout() 0 4 1
A setForcelogout() 0 4 2
A getSecure() 0 4 1
A getCheckuser() 0 4 1
A setCheckuser() 0 4 1
A getIdentified() 0 4 1
A setIdentified() 0 4 1
A getWelcomeTemplate() 0 4 1
A setWelcomeTemplate() 0 4 1
A getAbortPref() 0 4 1
A setAbortPref() 0 4 1
A getConfirmationDiff() 0 4 1
A setConfirmationDiff() 0 4 1
A getEmailSig() 0 4 1
A setEmailSig() 0 4 1
A getOAuthRequestToken() 0 4 1
A setOAuthRequestToken() 0 4 1
A getOAuthRequestSecret() 0 4 1
A setOAuthRequestSecret() 0 4 1
A getOAuthAccessToken() 0 4 1
A setOAuthAccessToken() 0 4 1
A getOAuthAccessSecret() 0 4 1
A setOAuthAccessSecret() 0 4 1
A approve() 0 9 1
A suspend() 9 9 1
A decline() 9 9 1
A promote() 0 9 1
A demote() 9 9 1
A isAdmin() 0 4 1
A isCheckuser() 0 8 3
A isSuspended() 0 4 1
A isNew() 0 4 1
A isUser() 0 4 1
A isDeclined() 0 4 1
A isCommunityUser() 0 4 1
B getOAuthIdentity() 0 42 9
A getOAuthOnWikiName() 0 9 2
A isOAuthLinked() 0 8 2
A clearOAuthData() 0 9 1
A getIdentityCache() 0 22 2
A detachAccount() 0 12 1
A oauthCanUse() 0 9 2
A oauthCanEdit() 12 12 6
A oauthCanCreateAccount() 12 12 5
A oauthCanCheckUser() 0 14 3
A getForgottenPasswordHash() 0 4 1
A getApprovalDate() 19 19 1
A getObjectDescription() 0 4 1

How to fix   Duplicated Code    Complexity   

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:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like User often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use User, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * User data object
5
 */
6
class User extends DataObject
7
{
8
	private $username;
9
	private $email;
10
	private $password;
11
	private $status = "New";
12
	private $onwikiname = "##OAUTH##";
13
	private $welcome_sig = "";
14
	private $lastactive = "0000-00-00 00:00:00";
15
	private $forcelogout = 0;
16
	private $checkuser = 0;
17
	private $identified = 0;
18
	private $welcome_template = 0;
19
	private $abortpref = 0;
20
	private $confirmationdiff = 0;
21
	private $emailsig = "";
22
	private $oauthrequesttoken = null;
23
	private $oauthrequestsecret = null;
24
	private $oauthaccesstoken = null;
25
	private $oauthaccesssecret = null;
26
	private $oauthidentitycache = null;
27
28
	// cache variable of the current user - it's never going to change in the middle of a request.
29
	private static $currentUser;
30
31
	private $identityCache = null;
32
33
	private $isCheckuserCache = null;
34
35
	/**
36
	 * Summary of getCurrent
37
	 * @param PdoDatabase $database
0 ignored issues
show
Documentation introduced by
Should the type for parameter $database not be null|PdoDatabase?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
38
	 * @return User The currently logged in user, or an anonymous coward with userid -1.
39
	 */
40
	public static function getCurrent(PdoDatabase $database = null)
41
	{
42
		if ($database === null) {
43
			$database = gGetDb();   
44
		}
45
46
		if (self::$currentUser === null) {
47
			if (isset($_SESSION['userID'])) {
48
				self::$currentUser = self::getById($_SESSION['userID'], $database);
49
			}
50
			else {
51
				$anonymousCoward = new CommunityUser();
52
53
				self::$currentUser = $anonymousCoward;
54
			}
55
		}
56
57
58
		return self::$currentUser;
59
	}
60
    
61
	public static function getById($id, PdoDatabase $database)
62
	{
63
		if ($id == "-1") {
64
			return new CommunityUser();
65
		}
66
67
		return parent::getById($id, $database);
68
	}
69
70
	public static function getCommunity()
71
	{
72
		return new CommunityUser();   
73
	}
74
75
	public static function getByUsername($username, PdoDatabase $database)
76
	{
77
		global $communityUsername;
78
		if ($username == $communityUsername) {
79
			return new CommunityUser();
80
		}
81
82
		$statement = $database->prepare("SELECT * FROM user WHERE username = :id LIMIT 1;");
83
		$statement->bindValue(":id", $username);
84
85
		$statement->execute();
86
87
		$resultObject = $statement->fetchObject(get_called_class());
88
89
		if ($resultObject != false) {
90
			$resultObject->isNew = false;
91
			$resultObject->setDatabase($database); 
92
		}
93
94
		return $resultObject;
95
	}
96
97
	/**
98
	 * Gets a user by their on-wiki username.
99
	 * 
100
	 * Don't use without asking me first. It's really inefficient in it's current implementation.
101
	 * We need to restructure the user table again to make this more efficient.
102
	 * We don't actually store the on-wiki name in the table any more, instead we
103
	 * are storing JSON in a column (!!). Yep, my fault. Code review is an awesome thing.
104
	 *            -- stw 2015-10-20
105
	 * @param string $username 
106
	 * @param PdoDatabase $database 
107
	 * @return User|false
108
	 */
109
	public static function getByOnWikiUsername($username, PdoDatabase $database)
110
	{
111
		// Firstly, try to search by the efficient database lookup.
112
		$statement = $database->prepare("SELECT * FROM user WHERE onwikiname = :id LIMIT 1;");
113
		$statement->bindValue(":id", $username);
114
		$statement->execute();
115
116
		$resultObject = $statement->fetchObject(get_called_class());
117
118
		if ($resultObject != false) {
119
			$resultObject->isNew = false;
120
			$resultObject->setDatabase($database); 
121
122
			return $resultObject;
123
		}
124
125
		// For active users, the above has failed. Let's do it the hard way.
126
		$sqlStatement = "SELECT * FROM user WHERE onwikiname = '##OAUTH##' AND oauthaccesstoken IS NOT NULL;";
127
		$statement = $database->prepare($sqlStatement);
128
		$statement->execute();
129
		$resultSet = $statement->fetchAll(PDO::FETCH_CLASS, get_called_class());
130
131
		/** @var User $user */
132 View Code Duplication
		foreach ($resultSet as $user) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
133
			// We have to set this before doing OAuth queries. :(
134
			$user->isNew = false;
135
			$user->setDatabase($database); 
136
137
			// Using cached data here!
138
			if ($user->getOAuthOnWikiName(true) == $username) {
139
				// Success.
140
				return $user;
141
			}
142
		}
143
144
		// Cached data failed. Let's do it the *REALLY* hard way.
145 View Code Duplication
		foreach ($resultSet as $user) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
146
			// We have to set this before doing OAuth queries. :(
147
			$user->isNew = false;
148
			$user->setDatabase($database); 
149
150
			// Don't use the cached data, but instead query the API.
151
			if ($user->getOAuthOnWikiName(false) == $username) {
152
				// Success.
153
				return $user;
154
			}
155
		}
156
157
		// Nope. Sorry.
158
		return false;
159
	}
160
161 View Code Duplication
	public static function getByRequestToken($requestToken, PdoDatabase $database)
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...
162
	{
163
		$statement = $database->prepare("SELECT * FROM user WHERE oauthrequesttoken = :id LIMIT 1;");
164
		$statement->bindValue(":id", $requestToken);
165
166
		$statement->execute();
167
168
		$resultObject = $statement->fetchObject(get_called_class());
169
170
		if ($resultObject != false) {
171
			$resultObject->isNew = false;
172
			$resultObject->setDatabase($database); 
173
		}
174
175
		return $resultObject;
176
	}
177
178
	/**
179
	 * @param string $status
180
	 * @param PdoDatabase $database
181
	 * @return User[]
182
	 */
183 View Code Duplication
	public static function getAllWithStatus($status, PdoDatabase $database)
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...
184
	{
185
		$statement = $database->prepare("SELECT * FROM user WHERE status = :status");
186
		$statement->execute(array(":status" => $status));
187
188
		$resultObject = $statement->fetchAll(PDO::FETCH_CLASS, get_called_class());
189
190
		/** @var User $u */
191
		foreach ($resultObject as $u) {
192
			$u->setDatabase($database);
193
			$u->isNew = false;
194
		}
195
196
		return $resultObject;
197
	}
198
199
	public static function getAllCheckusers(PdoDatabase $database)
200
	{
201
		$statement = $database->prepare("SELECT * FROM user WHERE checkuser = 1;");
202
		$statement->execute();
203
204
		$resultObject = $statement->fetchAll(PDO::FETCH_CLASS, get_called_class());
205
206
		$resultsCollection = array();
207
208
		/** @var User $u */
209
		foreach ($resultObject as $u) {
210
			$u->setDatabase($database);
211
			$u->isNew = false;
212
213
			if (!$u->isCheckuser()) {
214
				continue;
215
			}
216
217
			$resultsCollection[] = $u;
218
		}
219
220
		return $resultsCollection;
221
	}
222
223
	public static function getAllInactive(PdoDatabase $database)
224
	{
225
		$date = new DateTime();
226
		$date->modify("-90 days");
227
228
		$statement = $database->prepare(<<<SQL
229
			SELECT * 
230
			FROM user 
231
			WHERE lastactive < :lastactivelimit 
232
				AND status != 'Suspended' 
233
				AND status != 'Declined' 
234
				AND status != 'New' 
235
			ORDER BY lastactive ASC;
236
SQL
237
		);
238
		$statement->execute(array(":lastactivelimit" => $date->format("Y-m-d H:i:s")));
239
240
		$resultObject = $statement->fetchAll(PDO::FETCH_CLASS, get_called_class());
241
242
		/** @var User $u */
243
		foreach ($resultObject as $u) {
244
			$u->setDatabase($database);
245
			$u->isNew = false;
246
		}
247
248
		return $resultObject;
249
	}
250
251
	/**
252
	 * Gets all the usernames in the system
253
	 * @param PdoDatabase $database
254
	 * @param null|bool|string $filter If null, no filter. If true, active users only, otherwise provided status.
255
	 * @return string[]
256
	 */
257
	public static function getAllUsernames(PdoDatabase $database, $filter = null)
258
	{
259
		if ($filter === null) {
260
			$userListQuery = "SELECT username FROM user;";
261
			$userListResult = $database->query($userListQuery);
262
		}
263
		elseif ($filter === true) {
264
			$userListQuery = "SELECT username FROM user WHERE status IN ('User', 'Admin');";
265
			$userListResult = $database->query($userListQuery);
266
		}
267
		else {
268
			$userListQuery = "SELECT username FROM user WHERE status = :status;";
269
			$userListResult = $database->prepare($userListQuery);
270
			$userListResult->execute(array(":status" => $filter));
271
		}
272
		
273
		return $userListResult->fetchAll(PDO::FETCH_COLUMN);
274
	}
275
	
276
	public function save()
277
	{
278
		if ($this->isNew) {
279
// insert
280
			$statement = $this->dbObject->prepare(<<<SQL
281
				INSERT INTO `user` ( 
282
					username, email, password, status, onwikiname, welcome_sig, 
283
					lastactive, forcelogout, checkuser, identified, 
284
					welcome_template, abortpref, confirmationdiff, emailsig, 
285
					oauthrequesttoken, oauthrequestsecret, 
286
					oauthaccesstoken, oauthaccesssecret
287
				) VALUES (
288
					:username, :email, :password, :status, :onwikiname, :welcome_sig,
289
					:lastactive, :forcelogout, :checkuser, :identified, 
290
					:welcome_template, :abortpref, :confirmationdiff, :emailsig, 
291
					:ort, :ors, :oat, :oas
292
				);
293
SQL
294
			);
295
			$statement->bindValue(":username", $this->username);
296
			$statement->bindValue(":email", $this->email);
297
			$statement->bindValue(":password", $this->password);
298
			$statement->bindValue(":status", $this->status);
299
			$statement->bindValue(":onwikiname", $this->onwikiname);
300
			$statement->bindValue(":welcome_sig", $this->welcome_sig);
301
			$statement->bindValue(":lastactive", $this->lastactive);
302
			$statement->bindValue(":forcelogout", $this->forcelogout);
303
			$statement->bindValue(":checkuser", $this->checkuser);
304
			$statement->bindValue(":identified", $this->identified);
305
			$statement->bindValue(":welcome_template", $this->welcome_template);
306
			$statement->bindValue(":abortpref", $this->abortpref);
307
			$statement->bindValue(":confirmationdiff", $this->confirmationdiff);
308
			$statement->bindValue(":emailsig", $this->emailsig);
309
			$statement->bindValue(":ort", $this->oauthrequesttoken);
310
			$statement->bindValue(":ors", $this->oauthrequestsecret);
311
			$statement->bindValue(":oat", $this->oauthaccesstoken);
312
			$statement->bindValue(":oas", $this->oauthaccesssecret);
313
            
314
			if ($statement->execute()) {
315
				$this->isNew = false;
316
				$this->id = (int)$this->dbObject->lastInsertId();
317
			}
318
			else {
319
				throw new Exception($statement->errorInfo());
320
			}
321
		}
322
		else {
323
// update
324
			$statement = $this->dbObject->prepare(<<<SQL
325
				UPDATE `user` SET 
326
					username = :username, email = :email, 
327
					password = :password, status = :status,
328
					onwikiname = :onwikiname, welcome_sig = :welcome_sig, 
329
					lastactive = :lastactive, forcelogout = :forcelogout, 
330
					checkuser = :checkuser, identified = :identified,
331
					welcome_template = :welcome_template, abortpref = :abortpref, 
332
					confirmationdiff = :confirmationdiff, emailsig = :emailsig, 
333
					oauthrequesttoken = :ort, oauthrequestsecret = :ors, 
334
					oauthaccesstoken = :oat, oauthaccesssecret = :oas 
335
				WHERE id = :id;
336
SQL
337
			);
338
			$statement->bindValue(":id", $this->id);
339
			$statement->bindValue(":username", $this->username);
340
			$statement->bindValue(":email", $this->email);
341
			$statement->bindValue(":password", $this->password);
342
			$statement->bindValue(":status", $this->status);
343
			$statement->bindValue(":onwikiname", $this->onwikiname);
344
			$statement->bindValue(":welcome_sig", $this->welcome_sig);
345
			$statement->bindValue(":lastactive", $this->lastactive);
346
			$statement->bindValue(":forcelogout", $this->forcelogout);
347
			$statement->bindValue(":checkuser", $this->checkuser);
348
			$statement->bindValue(":identified", $this->identified);
349
			$statement->bindValue(":welcome_template", $this->welcome_template);
350
			$statement->bindValue(":abortpref", $this->abortpref);
351
			$statement->bindValue(":confirmationdiff", $this->confirmationdiff);
352
			$statement->bindValue(":emailsig", $this->emailsig);
353
			$statement->bindValue(":ort", $this->oauthrequesttoken);
354
			$statement->bindValue(":ors", $this->oauthrequestsecret);
355
			$statement->bindValue(":oat", $this->oauthaccesstoken);
356
			$statement->bindValue(":oas", $this->oauthaccesssecret);
357
            
358
			if (!$statement->execute()) {
359
				throw new Exception($statement->errorInfo());
360
			}
361
		} 
362
	}
363
364
	public function authenticate($password)
365
	{
366
		$result = AuthUtility::testCredentials($password, $this->password);
367
        
368
		if ($result === true) {
369
			// password version is out of date, update it.
370
			if (!AuthUtility::isCredentialVersionLatest($this->password)) {
371
				$this->password = AuthUtility::encryptPassword($password);
372
				$this->save();
373
			}
374
		}
375
        
376
		return $result;
377
	}
378
    
379
	public function touchLastLogin()
380
	{
381
		$query = "UPDATE user SET lastactive = CURRENT_TIMESTAMP() WHERE id = :id;";
382
		$this->dbObject->prepare($query)->execute(array(":id" => $this->id));
383
	}
384
    
385
	#region properties
386
    
387
	public function getUsername()
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
388
	{
389
		return $this->username;
390
	}
391
392
	public function setUsername($username)
393
	{
394
		$this->username = $username;
395
		$this->forcelogout = 1;
396
	}
397
398
	public function getEmail()
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
399
	{
400
		return $this->email;
401
	}
402
403
	public function setEmail($email)
404
	{
405
		$this->email = $email;
406
	}
407
408
	public function setPassword($password)
409
	{
410
		$this->password = AuthUtility::encryptPassword($password);
411
	}
412
413
	public function getStatus()
414
	{
415
		return $this->status;
416
	}
417
418
	/**
419
	 * Gets the user's on-wiki name
420
	 * @return mixed
421
	 */
422
	public function getOnWikiName()
423
	{
424
		if ($this->oauthaccesstoken != null) {
425
			try {
426
				return $this->getOAuthOnWikiName();   
427
			}
428
			catch (Exception $ex) {
429
				// urm.. log this?
430
				return $this->onwikiname;
431
			}
432
		}
433
        
434
		return $this->onwikiname;
435
	}
436
    
437
	/**
438
	 * This is probably NOT the function you want!
439
	 * 
440
	 * Take a look at getOnWikiName() instead.
441
	 * @return string
442
	 */
443
	public function getStoredOnWikiName()
444
	{
445
		return $this->onwikiname;
446
	}
447
448
	public function setOnWikiName($onWikiName)
449
	{
450
		$this->onwikiname = $onWikiName;
451
	}
452
453
	public function getWelcomeSig()
454
	{
455
		return $this->welcome_sig;
456
	}
457
458
	public function setWelcomeSig($welcomeSig)
459
	{
460
		$this->welcome_sig = $welcomeSig;
461
	}
462
463
	public function getLastActive()
464
	{
465
		return $this->lastactive;
466
	}
467
468
	public function setLastActive($lastActive)
469
	{
470
		$this->lastactive = $lastActive;
471
	}
472
473
	public function getForcelogout()
474
	{
475
		return $this->forcelogout;
476
	}
477
478
	public function setForcelogout($forceLogout)
479
	{
480
		$this->forcelogout = $forceLogout ? 1 : 0;
481
	}
482
    
483
	public function getSecure()
484
	{
485
		return true;
486
	}
487
488
	public function getCheckuser()
489
	{
490
		return $this->checkuser;
491
	}
492
493
	public function setCheckuser($checkuser)
494
	{
495
		$this->checkuser = $checkuser;
496
	}
497
498
	public function getIdentified()
499
	{
500
		return $this->identified;
501
	}
502
503
	public function setIdentified($identified)
504
	{
505
		$this->identified = $identified;
506
	}
507
508
	public function getWelcomeTemplate()
509
	{
510
		return $this->welcome_template;
511
	}
512
513
	public function setWelcomeTemplate($welcomeTemplate)
514
	{
515
		$this->welcome_template = $welcomeTemplate;
516
	}
517
518
	public function getAbortPref()
519
	{
520
		return $this->abortpref;
521
	}
522
523
	public function setAbortPref($abortPreference)
524
	{
525
		$this->abortpref = $abortPreference;
526
	}
527
528
	public function getConfirmationDiff()
529
	{
530
		return $this->confirmationdiff;
531
	}
532
533
	public function setConfirmationDiff($confirmationDiff)
534
	{
535
		$this->confirmationdiff = $confirmationDiff;
536
	}
537
538
	/**
539
	 * @return string
540
	 */
541
	public function getEmailSig()
542
	{
543
		return $this->emailsig;
544
	}
545
546
	public function setEmailSig($emailSignature)
547
	{
548
		$this->emailsig = $emailSignature;
549
	}
550
    
551
	public function getOAuthRequestToken()
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
552
	{
553
		return $this->oauthrequesttoken;
554
	}
555
556
	public function setOAuthRequestToken($oAuthRequestToken)
557
	{
558
		$this->oauthrequesttoken = $oAuthRequestToken;
559
	}
560
561
	public function getOAuthRequestSecret()
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
562
	{
563
		return $this->oauthrequestsecret;
564
	}
565
566
	public function setOAuthRequestSecret($oAuthRequestSecret)
567
	{
568
		$this->oauthrequestsecret = $oAuthRequestSecret;
569
	}
570
571
	public function getOAuthAccessToken()
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
572
	{
573
		return $this->oauthaccesstoken;
574
	}
575
576
	public function setOAuthAccessToken($oAuthAccessToken)
577
	{
578
		$this->oauthaccesstoken = $oAuthAccessToken;
579
	}
580
581
	public function getOAuthAccessSecret()
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
582
	{
583
		return $this->oauthaccesssecret;
584
	}
585
586
	public function setOAuthAccessSecret($oAuthAccessSecret)
587
	{
588
		$this->oauthaccesssecret = $oAuthAccessSecret;
589
	}
590
591
	#endregion
592
    
593
	#region changing access level
594
    
595
	public function approve()
596
	{
597
		$this->dbObject->transactionally(function()
598
		{
599
			$this->status = "User";
600
			$this->save();
601
			Logger::approvedUser($this->dbObject, $this);
602
		});
603
	}
604
    
605 View Code Duplication
	public function suspend($comment)
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...
606
	{
607
		$this->dbObject->transactionally(function() use ($comment)
608
		{
609
			$this->status = "Suspended";
610
			$this->save();
611
			Logger::suspendedUser($this->dbObject, $this, $comment);
612
		});
613
	}
614
    
615 View Code Duplication
	public function decline($comment)
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...
616
	{
617
		$this->dbObject->transactionally(function() use ($comment)
618
		{
619
			$this->status = "Declined";
620
			$this->save();
621
			Logger::declinedUser($this->dbObject, $this, $comment);
622
		});
623
	}
624
    
625
	public function promote()
626
	{
627
		$this->dbObject->transactionally(function()
628
		{
629
			$this->status = "Admin";
630
			$this->save();
631
			Logger::promotedUser($this->dbObject, $this);
632
		});
633
	}
634
    
635 View Code Duplication
	public function demote($comment)
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...
636
	{
637
		$this->dbObject->transactionally(function() use ($comment)
638
		{
639
			$this->status = "User";
640
			$this->save();
641
			Logger::demotedUser($this->dbObject, $this, $comment);
642
		});
643
	}
644
645
	#endregion
646
    
647
	#region user access checks
648
    
649
	public function isAdmin()
650
	{
651
		return $this->status == "Admin";
652
	}
653
    
654
	public function isCheckuser()
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
655
	{
656
	    if($this->isCheckuserCache === null) {
657
	        $this->isCheckuserCache = $this->checkuser == 1 || $this->oauthCanCheckUser();
658
        }
659
660
		return $this->isCheckuserCache;
661
	}
662
    
663
	public function isSuspended()
664
	{
665
		return $this->status == "Suspended";
666
	}
667
    
668
	public function isNew()
669
	{
670
		return $this->status == "New";
671
	}
672
    
673
	public function isUser()
674
	{
675
		return $this->status == "User";
676
	}
677
    
678
	public function isDeclined()
679
	{
680
		return $this->status == "Declined";
681
	}
682
    
683
	public function isCommunityUser()
684
	{
685
		return false;   
686
	}
687
    
688
	#endregion 
689
690
	#region OAuth
691
    
692
	public function getOAuthIdentity($useCached = false)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
693
	{
694
		if ($this->oauthaccesstoken == null) {
695
			$this->clearOAuthData();
696
		}
697
        
698
		global $oauthConsumerToken, $oauthMediaWikiCanonicalServer;
699
700
		if ($this->oauthidentitycache == null) {
701
			$this->identityCache = null;
702
		}
703
		else {
704
			$this->identityCache = unserialize($this->oauthidentitycache);
705
		}
706
        
707
		// check the cache
708
		if (
709
			$this->identityCache != null &&
710
			$this->identityCache->aud == $oauthConsumerToken &&
711
			$this->identityCache->iss == $oauthMediaWikiCanonicalServer
712
			) {
713
			if (
714
				$useCached || (
715
					DateTime::createFromFormat("U", $this->identityCache->iat) < new DateTime() &&
716
					DateTime::createFromFormat("U", $this->identityCache->exp) > new DateTime()
717
					)
718
				) {
719
				// Use cached value - it's either valid or we don't care.
720
				return $this->identityCache;
721
			}
722
			else {
723
				// Cache expired and not forcing use of cached value
724
				$this->getIdentityCache();
725
				return $this->identityCache;
726
			}
727
		}
728
		else {
729
			// Cache isn't ours or doesn't exist
730
			$this->getIdentityCache();
731
			return $this->identityCache;
732
		}
733
	}
734
    
735
	/**
736
	 * Summary of getOAuthOnWikiName
737
	 * @param mixed $useCached Set to false for everything where up-to-date data is important.
738
	 * @return mixed
739
	 */
740
	private function getOAuthOnWikiName($useCached = false)
741
	{
742
		$identity = $this->getOAuthIdentity($useCached);
743
		if ($identity !== null) {
744
			return $identity->username;
745
		}
746
747
		return false;
748
	}
749
750
	/**
751
	 * @return bool
752
	 */
753
	public function isOAuthLinked()
754
	{
755
		if ($this->onwikiname === "##OAUTH##") {
756
			return true; // special value. If an account must be oauth linked, this is true.
757
		}
758
        
759
		return $this->oauthaccesstoken !== null;
760
	}
761
762
	private function clearOAuthData()
763
	{
764
		$this->identityCache = null;
765
		$this->oauthidentitycache = null;
766
		$clearCacheQuery = "UPDATE user SET oauthidentitycache = null WHERE id = :id;";
767
		$this->dbObject->prepare($clearCacheQuery)->execute(array(":id" => $this->id));
768
        
769
		return null;
770
	}
771
    
772
	private function getIdentityCache()
773
	{
774
		global $oauthConsumerToken, $oauthSecretToken, $oauthBaseUrl, $oauthBaseUrlInternal;
775
        
776
		try {
777
			$util = new OAuthUtility($oauthConsumerToken, $oauthSecretToken, $oauthBaseUrl, $oauthBaseUrlInternal);
778
			$this->identityCache = $util->getIdentity($this->oauthaccesstoken, $this->oauthaccesssecret);
779
			$this->oauthidentitycache = serialize($this->identityCache);
780
			$this->dbObject->
781
				prepare("UPDATE user SET oauthidentitycache = :identity WHERE id = :id;")->
782
				execute(array(":id" => $this->id, ":identity" => $this->oauthidentitycache));
783
		}
784
		catch (UnexpectedValueException $ex) {
785
			$this->identityCache = null;
786
			$this->oauthidentitycache = null;
787
			$this->dbObject->
788
				prepare("UPDATE user SET oauthidentitycache = null WHERE id = :id;")->
789
				execute(array(":id" => $this->id));
790
791
			SessionAlert::warning("OAuth error getting identity from MediaWiki: " . $ex->getMessage());
792
		}   
793
	}
794
    
795
	public function detachAccount()
796
	{
797
		$this->setOnWikiName($this->getOAuthOnWikiName());
798
		$this->setOAuthAccessSecret(null);
799
		$this->setOAuthAccessToken(null);
800
		$this->setOAuthRequestSecret(null);
801
		$this->setOAuthRequestToken(null);
802
803
		$this->clearOAuthData();
804
        
805
		$this->save();
806
	}
807
    
808
	public function oauthCanUse()
809
	{
810
		try {
811
			return in_array('useoauth', $this->getOAuthIdentity()->grants); 
812
		}
813
		catch (Exception $ex) {
814
			return false;
815
		}
816
	}
817
    
818 View Code Duplication
	public function oauthCanEdit()
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...
819
	{
820
		try {
821
			return in_array('useoauth', $this->getOAuthIdentity()->grants)
822
				&& in_array('createeditmovepage', $this->getOAuthIdentity()->grants)
823
				&& in_array('createtalk', $this->getOAuthIdentity()->rights)
824
				&& in_array('edit', $this->getOAuthIdentity()->rights)
825
				&& in_array('writeapi', $this->getOAuthIdentity()->rights); }
826
				catch (Exception $ex) {
827
			return false;
828
		}
829
	}
830
    
831 View Code Duplication
	public function oauthCanCreateAccount()
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...
832
	{
833
		try {
834
			return in_array('useoauth', $this->getOAuthIdentity()->grants)
835
				&& in_array('createaccount', $this->getOAuthIdentity()->grants)
836
				&& in_array('createaccount', $this->getOAuthIdentity()->rights)
837
				&& in_array('writeapi', $this->getOAuthIdentity()->rights);
838
		}
839
		catch (Exception $ex) {
840
			return false;
841
		}
842
	}
843
844
	/**
845
	 * @return bool
846
	 */
847
	protected function oauthCanCheckUser()
848
	{
849
		if (!$this->isOAuthLinked()) {
850
			return false;
851
		}
852
853
		try {
854
			$identity = $this->getOAuthIdentity();
855
			return in_array('checkuser', $identity->rights);
856
		}
857
		catch (Exception $ex) {
858
			return false;
859
		}
860
	}
861
    
862
	#endregion
863
    
864
	public function getForgottenPasswordHash()
865
	{
866
		return md5($this->username . $this->email . $this->welcome_template . $this->id . $this->password);
867
	}
868
869 View Code Duplication
	public function getApprovalDate()
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...
870
	{
871
		$query = $this->dbObject->prepare(<<<SQL
872
			SELECT timestamp 
873
			FROM log 
874
			WHERE objectid = :userid
875
				AND objecttype = 'User'
876
				AND action = 'Approved' 
877
			ORDER BY id DESC 
878
			LIMIT 1;
879
SQL
880
		);
881
		$query->execute(array(":userid" => $this->id));
882
        
883
		$data = DateTime::createFromFormat("Y-m-d H:i:s", $query->fetchColumn());
884
		$query->closeCursor();
885
        
886
		return $data;
887
	}
888
	
889
	public function getObjectDescription()
890
	{
891
		return '<a href="statistics.php?page=Users&amp;user=' . $this->getId() . '">' . htmlentities($this->username) . "</a>";
892
	}
893
}
894