Completed
Pull Request — master (#526)
by Michael
02:11
created

User::getObjectDescription()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 3
cp 0
crap 2
rs 10
c 0
b 0
f 0
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 = "1000-01-01 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
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
		foreach ($resultSet as $user) {
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
		foreach ($resultSet as $user) {
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
	public static function getByRequestToken($requestToken, PdoDatabase $database)
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
	public static function getAllWithStatus($status, PdoDatabase $database)
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());
0 ignored issues
show
Bug introduced by
$statement->errorInfo() of type array is incompatible with the type string expected by parameter $message of Exception::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

319
				throw new Exception(/** @scrutinizer ignore-type */ $statement->errorInfo());
Loading history...
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()
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()
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()
552
	{
553
		return $this->oauthrequesttoken;
554
	}
555
556
	public function setOAuthRequestToken($oAuthRequestToken)
557
	{
558
		$this->oauthrequesttoken = $oAuthRequestToken;
559
	}
560
561
	public function getOAuthRequestSecret()
562
	{
563
		return $this->oauthrequestsecret;
564
	}
565
566
	public function setOAuthRequestSecret($oAuthRequestSecret)
567
	{
568
		$this->oauthrequestsecret = $oAuthRequestSecret;
569
	}
570
571
	public function getOAuthAccessToken()
572
	{
573
		return $this->oauthaccesstoken;
574
	}
575
576
	public function setOAuthAccessToken($oAuthAccessToken)
577
	{
578
		$this->oauthaccesstoken = $oAuthAccessToken;
579
	}
580
581
	public function getOAuthAccessSecret()
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
	public function suspend($comment)
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
	public function decline($comment)
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
	public function demote($comment)
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()
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)
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
	public function oauthCanEdit()
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
	public function oauthCanCreateAccount()
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
	public function getApprovalDate()
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