Completed
Push — master ( 18cdc2...7b9bde )
by Simon
03:22
created

acc.php (10 issues)

Upgrade to new PHP Analysis Engine

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

1
<?php
2
/**************************************************************************
3
**********      English Wikipedia Account Request Interface      **********
4
***************************************************************************
5
** Wikipedia Account Request Graphic Design by Charles Melbye,           **
6
** which is licensed under a Creative Commons                            **
7
** Attribution-Noncommercial-Share Alike 3.0 United States License.      **
8
**                                                                       **
9
** All other code are released under the Public Domain                   **
10
** by the ACC Development Team.                                          **
11
**                                                                       **
12
** See CREDITS for the list of developers.                               **
13
***************************************************************************/
14
15
// stop all output until we want it
16
ob_start();
17
18
// load the configuration
19
require_once 'config.inc.php';
20
21
// Initialize the session data.
22
session_start();
23
24
// Get all the classes.
25
require_once 'functions.php';
26
require_once 'includes/PdoDatabase.php';
27
require_once 'includes/SmartyInit.php'; // this needs to be high up, but below config, functions, and database
28
require_once 'includes/session.php';
29
30
// Check to see if the database is unavailable.
31
// Uses the false variable as its the internal interface.
32
if (Offline::isOffline()) {
33
	echo Offline::getOfflineMessage(false);
34
	die();
35
}
36
37
// Initialize the class objects.
38
$session = new session();
39
$date = new DateTime();
40
41
// initialise providers
42
global $squidIpList;
43
/** @var ILocationProvider $locationProvider */
44
$locationProvider = new $locationProviderClass(gGetDb('acc'), $locationProviderApiKey);
45
/** @var IRDnsProvider $rdnsProvider */
46
$rdnsProvider = new $rdnsProviderClass(gGetDb('acc'));
47
/** @var IAntiSpoofProvider $antispoofProvider */
48
$antispoofProvider = new $antispoofProviderClass();
49
/** @var IXffTrustProvider $xffTrustProvider */
50
$xffTrustProvider = new $xffTrustProviderClass($squidIpList);
51
52
// Clears the action variable.
53
$action = '';
54
55
// Assign the correct value to the action variable.
56
// The value is retrieved from the $GET variable.
57
if (isset($_GET['action'])) {
58
	$action = $_GET['action'];
59
}
60
61
// Clear session before banner and logged in as message is generated on logout attempt - Prom3th3an
62
if ($action == "logout") {
63
	session_unset();
64
    
65
	BootstrapSkin::displayInternalHeader();
66
	echo showlogin();
67
	BootstrapSkin::displayInternalFooter();
68
	die();
69
}
70
71
// Checks whether the user is set - the user should first login.
72
if (!isset($_SESSION['user'])) {
73
	$suser = '';
74
	BootstrapSkin::displayInternalHeader();
75
76
	// Checks whether the user want to reset his password or register a new account.
77
	// Performs the clause when the action is not one of the above options.
78
	if ($action != 'register' && $action != 'forgotpw' && $action != 'sreg' && $action != "registercomplete" && $action != "login") {
79
		echo showlogin();
80
		BootstrapSkin::displayInternalFooter();
81
		die();
82
	}
83
	else {
84
		// A content block is created if the action is none of the above.
85
		// This block would later be used to keep all the HTML except the header and footer.
86
		$out = "<div id=\"content\">";
87
		echo $out;
88
	}
89
}
90
91
// Forces the current user to logout if necessary.
92
if (isset($_SESSION['userID'])) {
93
	$session->forceLogout($_SESSION['userID']);
94
}
95
96
BootstrapSkin::displayInternalHeader();
97
$session->checksecurity();
98
99
100
// When no action is specified the default Internal ACC are displayed.
101
// TODO: Improve way the method is called.
102
if ($action == '') {
103
	echo defaultpage();
104
	BootstrapSkin::displayInternalFooter();
105
	die();
106
}
107
elseif ($action == "sreg") {
108
	global $useOauthSignup, $smarty;
109
        
110
	// TODO: check blocked
111
	// TODO: check age.
112
    
113
	// check if user checked the "I have read and understand the interface guidelines" checkbox
114
	if (!isset($_REQUEST['guidelines'])) {
115
		$smarty->display("registration/alert-interfaceguidelines.tpl");
116
		BootstrapSkin::displayInternalFooter();
117
		die();
118
	}
119
	
120
	if (!filter_var($_REQUEST['email'], FILTER_VALIDATE_EMAIL)) {
121
		$smarty->display("registration/alert-invalidemail.tpl");
122
		BootstrapSkin::displayInternalFooter();
123
		die();
124
	}
125
    
126
	if ($_REQUEST['pass'] !== $_REQUEST['pass2']) {
127
		$smarty->display("registration/alert-passwordmismatch.tpl");
128
		BootstrapSkin::displayInternalFooter();
129
		die();
130
	}
131
    
132
	if (!$useOauthSignup) {
133
		if (!((string)(int)$_REQUEST['conf_revid'] === (string)$_REQUEST['conf_revid']) || $_REQUEST['conf_revid'] == "") {
134
			$smarty->display("registration/alert-confrevid.tpl");
135
			BootstrapSkin::displayInternalFooter();
136
			die();		
137
		}
138
	}
139
    
140
	if (User::getByUsername($_REQUEST['name'], gGetDb()) != false) {
141
		$smarty->display("registration/alert-usernametaken.tpl");
142
		BootstrapSkin::displayInternalFooter();
143
		die();
144
	}
145
    
146
	$query = gGetDb()->prepare("SELECT * FROM user WHERE email = :email LIMIT 1;");
147
	$query->execute(array(":email" => $_REQUEST['email']));
148
	if ($query->fetchObject("User") != false) {
149
		$smarty->display("registration/alert-emailtaken.tpl");
150
		BootstrapSkin::displayInternalFooter();
151
		die();
152
	}
153
	$query->closeCursor();
154
155
	$database = gGetDb();
156
    
157
	$database->transactionally(function() use ($database, $useOauthSignup)
158
	{
159
    
160
		$newUser = new User();
161
		$newUser->setDatabase($database);
162
    
163
		$newUser->setUsername($_REQUEST['name']);
164
		$newUser->setPassword($_REQUEST['pass']);
165
		$newUser->setEmail($_REQUEST['email']);
166
        
167
		if (!$useOauthSignup) {
168
			$newUser->setOnWikiName($_REQUEST['wname']);
169
			$newUser->setConfirmationDiff($_REQUEST['conf_revid']);
170
		}
171
        
172
		$newUser->save();
173
    
174
		global $oauthConsumerToken, $oauthSecretToken, $oauthBaseUrl, $oauthBaseUrlInternal, $useOauthSignup;
175
    
176
		if ($useOauthSignup) {
177
			try {
178
				// Get a request token for OAuth
179
				$util = new OAuthUtility($oauthConsumerToken, $oauthSecretToken, $oauthBaseUrl, $oauthBaseUrlInternal);
180
				$requestToken = $util->getRequestToken();
181
    
182
				// save the request token for later
183
				$newUser->setOAuthRequestToken($requestToken->key);
184
				$newUser->setOAuthRequestSecret($requestToken->secret);
185
				$newUser->save();
186
            
187
				Notification::userNew($newUser);
188
        
189
				$redirectUrl = $util->getAuthoriseUrl($requestToken);
190
            
191
				header("Location: {$redirectUrl}");
192
			}
193
			catch (Exception $ex) {
194
				throw new TransactionException(
195
					$ex->getMessage(), 
196
					"Connection to Wikipedia failed.", 
197
					"alert-error", 
198
					0, 
199
					$ex);
200
			}
201
		}
202
		else {
203
			global $baseurl;
204
			Notification::userNew($newUser);
205
			header("Location: {$baseurl}/acc.php?action=registercomplete");
206
		}
207
	});
208
    
209
	die();
210
}
211
elseif ($action == "register") {
212
	global $useOauthSignup, $smarty;
213
	$smarty->assign("useOauthSignup", $useOauthSignup);
214
	$smarty->display("registration/register.tpl");
215
	BootstrapSkin::displayInternalFooter();
216
	die();
217
}
218
elseif ($action == "registercomplete") {
219
	$smarty->display("registration/alert-registrationcomplete.tpl");
220
	BootstrapSkin::displayInternalFooter();
221
}
222
elseif ($action == "forgotpw") {
223
	global $baseurl, $smarty;
224
    
225
	if (isset ($_GET['si']) && isset ($_GET['id'])) {
226
		$user = User::getById($_GET['id'], gGetDb());
227
        
228
		if ($user === false) {
229
			BootstrapSkin::displayAlertBox("User not found.", "alert-error");
230
			BootstrapSkin::displayInternalFooter();
231
			die();
232
		}
233
        
234
		if (isset ($_POST['pw']) && isset ($_POST['pw2'])) {
235
			$hash = $user->getForgottenPasswordHash();
236
            
237
			if ($hash == $_GET['si']) {
238
				if ($_POST['pw'] == $_POST['pw2']) {
239
					$user->setPassword($_POST['pw2']);
240
					$user->save();
241
                    
242
					BootstrapSkin::displayAlertBox(
243
						"You may now <a href=\"$baseurl/acc.php\">Login</a>", 
244
						"alert-error", 
245
						"Password reset!", 
246
						true, 
247
						false);
248
                    
249
					BootstrapSkin::displayInternalFooter();
250
					die();
251
				}
252
				else {
253
					BootstrapSkin::displayAlertBox("Passwords did not match!", "alert-error", "Error", true, false);
254
					BootstrapSkin::displayInternalFooter();
255
					die();
256
				}
257
			}
258
			else {
259
				BootstrapSkin::displayAlertBox("Invalid request<!-- 1 -->", "alert-error", "Error", true, false);
260
				BootstrapSkin::displayInternalFooter();
261
				die();
262
			}
263
		}
264
        
265
		$hash = $user->getForgottenPasswordHash();
266
        
267
		if ($hash == $_GET['si']) {
268
			$smarty->assign('user', $user);
269
			$smarty->assign('si', $_GET['si']);
270
			$smarty->assign('id', $_GET['id']);
271
			$smarty->display('forgot-password/forgotpwreset.tpl');
272
		}
273
		else {
274
			BootstrapSkin::displayAlertBox(
275
				"The hash supplied in the link did not match the hash in the database!", 
276
				"alert-error", 
277
				"Invalid request", 
278
				true, 
279
				false);
280
		}
281
        
282
		BootstrapSkin::displayInternalFooter();
283
		die();
284
	}
285
    
286
	if (isset ($_POST['username'])) {
287
		$user = User::getByUsername($_POST['username'], gGetDb());
288
289
		if ($user == false) {
290
			BootstrapSkin::displayAlertBox(
291
				"Could not find user with that username and email address!", 
292
				"alert-error", 
293
				"Error", 
294
				true, 
295
				false);
296
            
297
			BootstrapSkin::displayInternalFooter();
298
			die();
299
		}
300
		elseif (strtolower($_POST['email']) != strtolower($user->getEmail())) {
301
			BootstrapSkin::displayAlertBox("Could not find user with that username and email address!", 
302
				"alert-error", 
303
				"Error", 
304
				true, 
305
				false);
306
            
307
			BootstrapSkin::displayInternalFooter();
308
			die();
309
		}
310
		else {
311
			$hash = $user->getForgottenPasswordHash();
312
                       
313
			$smarty->assign("user", $user);
314
			$smarty->assign("hash", $hash);
315
			$smarty->assign("remoteAddress", $_SERVER['REMOTE_ADDR']);
316
            
317
			$mailtxt = $smarty->fetch("forgot-password/reset-mail.tpl");
318
			$headers = 'From: [email protected]';
319
            
320
			mail(
321
				$user->getEmail(), 
322
				"English Wikipedia Account Request System - Forgotten password", 
323
				$mailtxt, 
324
				$headers);
325
            
326
			BootstrapSkin::displayAlertBox(
327
				"<strong>Your password reset request has been completed.</strong> Please check your e-mail.", 
328
				"alert-success", 
329
				"", 
330
				false, 
331
				false);
332
            
333
			BootstrapSkin::displayInternalFooter();
334
			die();
335
		}
336
	}
337
    
338
	$smarty->display('forgot-password/forgotpw.tpl');
339
340
	BootstrapSkin::displayInternalFooter();
341
	die();
342
}
343
elseif ($action == "login") {
344
	global $baseurl, $smarty;
345
    
346
	if (!isset($_POST['username'])) {
347
		header("Location: $baseurl/acc.php?error=authfail&tplUsername=");
348
		die();
349
	}
350
351
	$user = User::getByUsername($_POST['username'], gGetDb());
352
    
353
	if ($user == false || !$user->authenticate($_POST['password'])) {
354
		header("Location: $baseurl/acc.php?error=authfail&tplUsername=" . urlencode($_POST['username']));
355
		die();
356
	}
357
    
358
	if ($user->getStoredOnWikiName() == "##OAUTH##" && $user->getOAuthAccessToken() == null) {
359
		reattachOAuthAccount($user);   
360
	}
361
    
362
	if ($user->isOAuthLinked()) {
363
		try {
364
			// test retrieval of the identity
365
			$user->getOAuthIdentity();
366
		}
367
		catch (TransactionException $ex) {
368
			$user->setOAuthAccessToken(null);
369
			$user->setOAuthAccessSecret(null);
370
			$user->save();
371
            
372
			reattachOAuthAccount($user);
373
		}
374
	}
375
	else {
376
		global $enforceOAuth;
377
        
378
		if ($enforceOAuth) {
379
			reattachOAuthAccount($user);
380
		}
381
	}
382
    
383
	// At this point, the user has successfully authenticated themselves.
384
	// We now proceed to perform login-specific actions, and check the user actually has
385
	// the correct permissions to continue with the login.
386
    
387
	if ($user->getForcelogout()) {
388
		$user->setForcelogout(false);
389
		$user->save();
390
	}
391
    
392
	if ($user->isNew()) {
393
		header("Location: $baseurl/acc.php?error=newacct");
394
		die();
395
	}
396
    
397
	$database = gGetDb();
398
    
399
	$sqlText = <<<SQL
400
SELECT comment FROM log
401
WHERE action = :action AND objectid = :userid AND objecttype = 'User'
402
ORDER BY timestamp DESC LIMIT 1;
403
SQL;
404
    
405
	$suspendstatement = $database->prepare($sqlText);
406
    
407
	if ($user->isDeclined()) {
408
		$suspendAction = "Declined";
409
		$userid = $user->getId();
410
		$suspendstatement->bindValue(":action", $suspendAction);
411
		$suspendstatement->bindValue(":userid", $userid);
412
		$suspendstatement->execute();
413
        
414
		$suspendreason = $suspendstatement->fetchColumn();
415
        
416
		$suspendstatement->closeCursor();
417
        
418
		BootstrapSkin::displayInternalHeader();
419
		$smarty->assign("suspendreason", $suspendreason);
420
		$smarty->display("login/declined.tpl");
421
		BootstrapSkin::displayInternalFooter();
422
		die();
423
	}
424
    
425
	if ($user->isSuspended()) {
426
		$suspendAction = "Suspended";
427
		$userid = $user->getId();
428
		$suspendstatement->bindValue(":action", $suspendAction);
429
		$suspendstatement->bindValue(":userid", $userid);
430
		$suspendstatement->execute();
431
        
432
		$suspendreason = $suspendstatement->fetchColumn();
433
        
434
		$suspendstatement->closeCursor();
435
        
436
		BootstrapSkin::displayInternalHeader();
437
		$smarty->assign("suspendreason", $suspendreason);
438
		$smarty->display("login/suspended.tpl");
439
		BootstrapSkin::displayInternalFooter();
440
		die();
441
	}
442
    
443
	if (!$user->isIdentified() && $forceIdentification == 1) {
444
		header("Location: $baseurl/acc.php?error=noid");
445
		die();
446
	}
447
    
448
	// At this point, we've tested that the user is OK, so we set the login cookies.
449
    
450
	$_SESSION['user'] = $user->getUsername();
451
	$_SESSION['userID'] = $user->getId();
452
    
453
	if ($user->getOAuthAccessToken() == null && $user->getStoredOnWikiName() == "##OAUTH##") {
454
		reattachOAuthAccount($user);
455
	}
456
    
457
	header("Location: $baseurl/acc.php");
458
}
459
elseif ($action == "messagemgmt") {
460
	global $smarty;
461
    
462
	if (isset($_GET['view'])) {
463
		$message = InterfaceMessage::getById($_GET['view'], gGetDb());
464
                
465
		if ($message == false) {
466
			BootstrapSkin::displayAlertBox("Unable to find specified message", "alert-error", "Error", true, false);
467
			BootstrapSkin::displayInternalFooter();
468
			die();
469
		}
470
        
471
		$smarty->assign("message", $message);
472
		$smarty->assign("readonly", true);
473
		$smarty->display("message-management/editform.tpl");
474
		BootstrapSkin::displayInternalFooter();
475
		die();
476
	}
477
	if (isset($_GET['edit'])) {
478
		if (!(User::getCurrent()->isAdmin() || User::getCurrent()->isCheckuser())) {
479
			BootstrapSkin::displayAccessDenied();
480
			BootstrapSkin::displayInternalFooter();
481
			die();
482
		}
483
        
484
		$database = gGetDb();
485
        
486
		$database->transactionally(function() use ($database)
487
		{
488
			global $smarty;
489
            
490
			$message = InterfaceMessage::getById($_GET['edit'], $database);
491
            
492
			if ($message == false) {
493
				throw new TransactionException("Unable to find specified message", "Error");
494
			}
495
            
496
			if (isset($_GET['submit'])) {
497
				$message->setContent($_POST['mailtext']);
498
				$message->setDescription($_POST['maildesc']);
499
				$message->save();
500
            
501
				Logger::interfaceMessageEdited(gGetDb(), $message);
502
              
503
				$smarty->assign("message", $message);
504
				$smarty->display("message-management/alert-editsuccess.tpl");
505
                
506
				Notification::interfaceMessageEdited($message);
507
                
508
				BootstrapSkin::displayInternalFooter();
509
				return;
510
			}
511
            
512
			$smarty->assign("message", $message);
513
			$smarty->assign("readonly", false);
514
			$smarty->display("message-management/editform.tpl");
515
        
516
			BootstrapSkin::displayInternalFooter();
517
		});
518
        
519
		die();
520
	}
521
    
522
	$sqlText = <<<SQL
523
        SELECT * 
524
        FROM interfacemessage 
525
        WHERE type = :type 
526
            AND description NOT LIKE '%[deprecated]';
527
SQL;
528
    
529
	$fetchStatement = gGetDb()->prepare($sqlText);
530
	$data = array();
531
        
532
	//$fetchStatement->execute(array(":type" => "Interface"));
533
	//$data['Public Interface messages'] = $fetchStatement->fetchAll(PDO::FETCH_CLASS, 'InterfaceMessage');
534
    
535
	$fetchStatement->execute(array(":type" => "Internal"));
536
	$data['Internal Interface messages'] = $fetchStatement->fetchAll(PDO::FETCH_CLASS, 'InterfaceMessage');
537
    
538
	$smarty->assign("data", $data);
539
	$smarty->display('message-management/view.tpl');
540
   
541
	BootstrapSkin::displayInternalFooter();
542
	die();
543
}
544
elseif ($action == "templatemgmt") {
545
	global $baseurl, $smarty;
546
    
547
	if (isset($_GET['view'])) {
548
		$template = WelcomeTemplate::getById($_GET['view'], gGetDb());
549
        
550
		if ($template === false) {
551
			SessionAlert::success("Something went wrong, we can't find the template you asked for! Please try again.");
552
			header("Location: {$baseurl}/acc.php?action=templatemgmt");
553
			die();
554
		}
555
        
556
		$smarty->assign("template", $template);
557
		$smarty->display("welcometemplate/view.tpl");
558
		BootstrapSkin::displayInternalFooter();
559
		die();
560
	}
561
    
562
	if (isset($_GET['add'])) {
563
		if (!User::getCurrent()->isAdmin() && !User::getCurrent()->isCheckuser()) {
564
			BootstrapSkin::displayAccessDenied();
565
            
566
			BootstrapSkin::displayInternalFooter();
567
			die();
568
		}
569
        
570
		if (isset($_POST['submit'])) {
571
			global $baseurl;
572
            
573
			$database = gGetDb();
574
            
575
			$database->transactionally(function() use ($database, $baseurl)
576
			{
577
				$template = new WelcomeTemplate();
578
				$template->setDatabase($database);
579
				$template->setUserCode($_POST['usercode']);
580
				$template->setBotCode($_POST['botcode']);
581
				$template->save();
582
            
583
				Logger::welcomeTemplateCreated($database, $template);
584
                            
585
				Notification::welcomeTemplateCreated($template);
586
            
587
				SessionAlert::success("Template successfully created.");
588
				header("Location: $baseurl/acc.php?action=templatemgmt");
589
			});
590
		}
591
		else {
592
			
593
			if (isset($_POST['preview'])) {
594
				$usercode = $_POST['usercode'];
595
				$botcode = $_POST['botcode'];
596
				echo displayPreview($usercode);
597
			}
598
			else {
599
				$usercode = '';
600
				$botcode = '';
601
			}
602
603
			$smarty->assign("usercode", $usercode);
604
			$smarty->assign("botcode", $botcode);
605
            
606
			$smarty->display("welcometemplate/add.tpl");
607
			BootstrapSkin::displayInternalFooter();
608
			die();
609
		}
610
        
611
		die();
612
	}
613
    
614
	if (isset($_GET['select'])) {
615
		$user = User::getCurrent();
616
        
617
		if ($_GET['select'] == 0) {
618
			$user->setWelcomeTemplate(null);
619
			$user->save();
620
            
621
			SessionAlert::success("Disabled automatic user welcoming.");
622
			header("Location: {$baseurl}/acc.php?action=templatemgmt");
623
			die();
624
		}
625
		else {
626
			$template = WelcomeTemplate::getById($_GET['select'], gGetDb());
627
			if ($template !== false) {
628
				$user->setWelcomeTemplate($template->getId());
629
				$user->save();
630
                
631
				SessionAlert::success("Updated selected welcome template for automatic welcoming.");
632
				header("Location: {$baseurl}/acc.php?action=templatemgmt");
633
				die();
634
			}
635
			else {
636
				SessionAlert::error("Something went wrong, we can't find the template you asked for!");
637
				header("Location: {$baseurl}/acc.php?action=templatemgmt");
638
				die();
639
			}
640
		}
641
	}
642
    
643
	if (isset($_GET['del'])) {
644
		global $baseurl;
645
        
646
		if (!User::getCurrent()->isAdmin() && !User::getCurrent()->isCheckuser()) {
647
			BootstrapSkin::displayAccessDenied();
648
			BootstrapSkin::displayInternalFooter();
649
			die();
650
		}
651
652
		$database = gGetDb();
653
        
654
		$template = WelcomeTemplate::getById($_GET['del'], $database);
655
		if ($template == false) {
656
			SessionAlert::error("Something went wrong, we can't find the template you asked for!");
657
			header("Location: {$baseurl}/acc.php?action=templatemgmt");
658
			die();
659
		}
660
        
661
		$database->transactionally(function() use($database, $template)
662
		{
663
			$tid = $template->getId();
664
            
665
			$database
666
				->prepare("UPDATE user SET welcome_template = NULL WHERE welcome_template = :id;")
667
				->execute(array(":id" => $tid));
668
            
669
			Logger::welcomeTemplateDeleted($database, $template);
670
            
671
			$template->delete();
672
            
673
			SessionAlert::success("Template deleted. Any users who were using this template have had automatic welcoming disabled.");
674
			Notification::welcomeTemplateDeleted($tid);
675
		});
676
        
677
		header("Location: $baseurl/acc.php?action=templatemgmt");
678
		die();			
679
	}
680
    
681
	if (isset($_GET['edit'])) {
682
		if (!User::getCurrent()->isAdmin() && !User::getCurrent()->isCheckuser()) {
683
			BootstrapSkin::displayAccessDenied();
684
			BootstrapSkin::displayInternalFooter();
685
			die();
686
		}
687
688
		$database = gGetDb();
689
        
690
		$template = WelcomeTemplate::getById($_GET['edit'], $database);
691
		if ($template == false) {
692
			SessionAlert::success("Something went wrong, we can't find the template you asked for! Please try again.");
693
			header("Location: {$baseurl}/acc.php?action=templatemgmt");
694
			die();
695
		}
696
697
		if (isset($_POST['submit'])) {
698
			$database->transactionally(function() use($database, $template)
699
			{
700
				$template->setUserCode($_POST['usercode']);
701
				$template->setBotCode($_POST['botcode']);
702
				$template->save();
703
			
704
				Logger::welcomeTemplateEdited($database, $template);
705
                
706
				SessionAlert::success("Template updated.");
707
				Notification::welcomeTemplateEdited($template);
708
			});
709
            
710
			header("Location: $baseurl/acc.php?action=templatemgmt");
711
			die();
712
		}
713
		else {
714
			$smarty->assign("template", $template);
715
			$smarty->display("welcometemplate/edit.tpl");
716
            
717
			BootstrapSkin::displayInternalFooter();
718
			die();
719
		}
720
	}
721
    
722
	$templateList = WelcomeTemplate::getAll();
723
    
724
	$smarty->assign("templatelist", $templateList);
725
	$smarty->display("welcometemplate/list.tpl");
726
    
727
	BootstrapSkin::displayInternalFooter();
728
	die();
729
}
730
elseif ($action == "sban") {
731
	global $smarty;
732
    
733
	// Checks whether the current user is an admin.
734
	if (!User::getCurrent()->isAdmin() && !User::getCurrent()->isCheckuser()) {
735
		BootstrapSkin::displayAccessDenied();
736
		BootstrapSkin::displayInternalFooter();
737
		die();
738
	}
739
	
740
	// Checks whether there is a reason entered for ban.
741
	if (!isset($_POST['banreason']) || $_POST['banreason'] == "") {
742
		BootstrapSkin::displayAlertBox("You must specify a ban reason", "alert-error", "", false, false);
743
		BootstrapSkin::displayInternalFooter();
744
		die();
745
	}
746
	
747
	// Checks whether there is a target entered to ban.
748
	if (!isset($_POST['target']) || $_POST['target'] == "") {
749
		BootstrapSkin::displayAlertBox("You must specify a target to be banned", "alert-error", "", false, false);
750
		BootstrapSkin::displayInternalFooter();
751
		die();
752
	}
753
	
754
	$duration = $_POST['duration'];
755
    
756
	if ($duration == "-1") {
757
		$duration = -1;
758
	}
759
	elseif ($duration == "other") {
760
		$duration = strtotime($_POST['otherduration']);
761
		if (!$duration) {
762
			BootstrapSkin::displayAlertBox("Invalid ban time", "alert-error", "", false, false);
763
			BootstrapSkin::displayInternalFooter();
764
			die();
765
		}
766
		elseif (time() > $duration) {
767
			BootstrapSkin::displayAlertBox("Ban time has already expired!", "alert-error", "", false, false);
768
			BootstrapSkin::displayInternalFooter();
769
			die();
770
		}
771
	}
772
	else {
773
		$duration = $duration + time();
774
	}
775
    
776
	switch ($_POST['type']) {
777
		case 'IP':
778
			if (filter_var($_POST['target'], FILTER_VALIDATE_IP) === false) {
779
				BootstrapSkin::displayAlertBox("Invalid target - IP address expected.", "alert-error", "", false, false);
780
				BootstrapSkin::displayInternalFooter();
781
				die();
782
			}
783
            
784
			global $squidIpList;
785
			if (in_array($_POST['target'], $squidIpList)) {
786
				BootstrapSkin::displayAlertBox(
787
					"This IP address is on the protected list of proxies, and cannot be banned.", 
788
					"alert-error", 
789
					"", 
790
					false, 
791
					false);
792
				BootstrapSkin::displayInternalFooter();
793
				die();
794
			}
795
			break;
796
		case 'Name':
797
			break;
798
		case 'EMail':
799
			// TODO: cut this down to a bare-bones implementation so we don't accidentally reject a valid address.
800
			if (!preg_match(';^(?:[A-Za-z0-9!#$%&\'*+/=?^_`{|}~-]+(?:\.[A-Za-z0-9!#$%&\'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?\.)+[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[A-Za-z0-9-]*[A-Za-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$;', $_POST['target'])) {
801
				BootstrapSkin::displayAlertBox(
802
					"Invalid target - email address expected.", 
803
					"alert-error", 
804
					"", 
805
					false, 
806
					false);
807
                
808
				BootstrapSkin::displayInternalFooter();
809
				die();
810
			}
811
			break;
812
		default:
813
			BootstrapSkin::displayAlertBox("I don't know what type of target you want to ban! You'll need to choose from email address, IP, or requested name.", "alert-error", "", false, false);
814
			BootstrapSkin::displayInternalFooter();
815
			die();
816
	}
817
        
818
	if (count(Ban::getActiveBans($_POST['target'])) > 0) {
819
		BootstrapSkin::displayAlertBox("This target is already banned!", "alert-error", "", false, false);
820
		BootstrapSkin::displayInternalFooter();
821
		die();
822
	}
823
    
824
	$database = gGetDb();
825
    
826
	$ban = new Ban();
827
    
828
	$currentUsername = User::getCurrent()->getUsername();
829
    
830
	$database->transactionally(function() use ($database, $ban, $duration, $currentUsername)
831
	{
832
		$ban->setDatabase($database);
833
		$ban->setActive(1);
834
		$ban->setType($_POST['type']);
835
		$ban->setTarget($_POST['target']);
836
		$ban->setUser($currentUsername);
837
		$ban->setReason($_POST['banreason']);
838
		$ban->setDuration($duration);
839
    
840
		$ban->save();
841
        
842
		Logger::banned($database, $ban, $_POST['banreason']);
843
	});
844
    
845
	$smarty->assign("ban", $ban);
846
	BootstrapSkin::displayAlertBox($smarty->fetch("bans/bancomplete.tpl"), "alert-info", "", false, false);
847
        
848
	Notification::banned($ban);
849
    
850
	BootstrapSkin::displayInternalFooter();
851
	die();
852
}
853
elseif ($action == "unban") {
854
	global $smarty;
855
    
856
	if (!isset($_GET['id']) || $_GET['id'] == "") {
857
		BootstrapSkin::displayAlertBox(
858
			"The ID parameter appears to be missing! This is probably a bug.", 
859
			"alert-error", 
860
			"Ahoy There! Something's not right...", 
861
			true, 
862
			false);
863
		BootstrapSkin::displayInternalFooter();
864
		die();
865
	}
866
    
867
	if (!User::getCurrent()->isAdmin() && !User::getCurrent()->isCheckuser()) {
868
		BootstrapSkin::displayAccessDenied();
869
		BootstrapSkin::displayInternalFooter();
870
		die();
871
	}
872
    
873
	$ban = Ban::getActiveId($_GET['id']);
874
        
875
	if ($ban == false) {
876
		BootstrapSkin::displayAlertBox(
877
			"The specified ban ID is not currently active or doesn't exist!", 
878
			"alert-error", 
879
			"", 
880
			false, 
881
			false);
882
        
883
		BootstrapSkin::displayInternalFooter();
884
		die();
885
	}
886
887
	if (isset($_GET['confirmunban']) && $_GET['confirmunban'] == "true") {
888
		if (!isset($_POST['unbanreason']) || $_POST['unbanreason'] == "") {
889
			BootstrapSkin::displayAlertBox("You must enter an unban reason!", "alert-error", "", false, false);
890
			BootstrapSkin::displayInternalFooter();
891
			die();
892
		}
893
		else {
894
			$database = gGetDb();
895
            
896
			$database->transactionally(function() use ($database, $ban)
897
			{
898
				$ban->setActive(0);
899
				$ban->save();
900
                
901
				$banId = $ban->getId();
902
				$currentUser = User::getCurrent()->getUsername();
903
                
904
				Logger::unbanned($database, $ban, $_POST['unbanreason']);
905
			});
906
        
907
			BootstrapSkin::displayAlertBox("Unbanned " . $ban->getTarget(), "alert-info", "", false, false);
908
			BootstrapSkin::displayInternalFooter();
909
			Notification::unbanned($ban, $_POST['unbanreason']);
910
			die();
911
		}
912
	}
913
	else {
914
		$smarty->assign("ban", $ban);
915
		$smarty->display("bans/unban.tpl");
916
        
917
		BootstrapSkin::displayInternalFooter();
918
	}
919
}
920
elseif ($action == "ban") {
921
	global $smarty;
922
    
923
	if (isset ($_GET['ip']) || isset ($_GET['email']) || isset ($_GET['name'])) {
924
		if (!User::getCurrent()->isAdmin() && !User::getCurrent()->isCheckuser()) {
925
			BootstrapSkin::displayAlertBox("Only administrators or checkusers may ban users", "alert-error");
926
			BootstrapSkin::displayInternalFooter();
927
			die();
928
		}
929
        
930
		$database = gGetDb();
931
		// TODO: rewrite me!
932
		if (isset($_GET['ip'])) {
933
			$query = "SELECT ip, forwardedip FROM request WHERE id = :ip;";
934
			$statement = $database->prepare($query);
935
			$statement->bindValue(":ip", $_GET['ip']);
936
			$statement->execute();
937
			$row = $statement->fetch(PDO::FETCH_ASSOC);
938
			$target = getTrustedClientIP($row['ip'], $row['forwardedip']);
939
			$type = "IP";
940
		}
941
		elseif (isset($_GET['email'])) {
942
			$query = "SELECT email FROM request WHERE id = :ip;";
943
			$statement = $database->prepare($query);
944
			$statement->bindValue(":ip", $_GET['email']);
945
			$statement->execute();
946
			$row = $statement->fetch(PDO::FETCH_ASSOC);
947
			$target = $row['email'];
948
			$type = "EMail";
949
		}
950
		elseif (isset($_GET['name'])) {
951
			$query = "SELECT name FROM request WHERE id = :ip;";
952
			$statement = $database->prepare($query);
953
			$statement->bindValue(":ip", $_GET['name']);
954
			$statement->execute();
955
			$row = $statement->fetch(PDO::FETCH_ASSOC);
956
			$target = $row['name'];
957
			$type = "Name";
958
		}
959
		else {
960
			BootstrapSkin::displayAlertBox("Unknown ban type.", "alert-error");
961
			BootstrapSkin::displayInternalFooter();
962
			die();    
963
		}
964
        
965
		if (count(Ban::getActiveBans($target))) {
966
			BootstrapSkin::displayAlertBox("This target is already banned!", "alert-error");
967
			BootstrapSkin::displayInternalFooter();
968
			die();
969
		} 
970
        
971
		$smarty->assign("bantype", $type);
972
		$smarty->assign("bantarget", trim($target));
973
		$smarty->display("bans/banform.tpl");
974
	}
975
	else {
976
		$bans = Ban::getActiveBans();
977
  
978
		$smarty->assign("activebans", $bans);
979
		$smarty->display("bans/banlist.tpl");
980
	}
981
    
982
	BootstrapSkin::displayInternalFooter();
983
	die();
984
}
985
elseif ($action == "defer" && $_GET['id'] != "" && $_GET['sum'] != "") {
986
	global $availableRequestStates;
987
	
988
	if (array_key_exists($_GET['target'], $availableRequestStates)) {
989
		$request = Request::getById($_GET['id'], gGetDb());
990
		
991
		if ($request == false) {
992
			BootstrapSkin::displayAlertBox(
993
				"Could not find the specified request!", 
994
				"alert-error", 
995
				"Error!", 
996
				true, 
997
				false);
998
            
999
			BootstrapSkin::displayInternalFooter();
1000
			die();
1001
		}
1002
		
1003
		if ($request->getChecksum() != $_GET['sum']) {
1004
			SessionAlert::error(
1005
				"This is similar to an edit conflict on Wikipedia; it means that you have tried to perform an action "
1006
				. "on a request that someone else has performed an action on since you loaded the page",
1007
				"Invalid checksum");
1008
            
1009
			header("Location: acc.php?action=zoom&id={$request->getId()}");
1010
			die();
1011
		}
1012
        
1013
		$sqlText = <<<SQL
1014
SELECT timestamp FROM log
1015
WHERE objectid = :request and objecttype = 'Request' AND action LIKE 'Closed%'
1016
ORDER BY timestamp DESC LIMIT 1;
1017
SQL;
1018
        
1019
		$statement = gGetDb()->prepare($sqlText);
1020
		$statement->execute(array(":request" => $request->getId()));
1021
		$logTime = $statement->fetchColumn();
1022
		$statement->closeCursor();
1023
        
1024
		$date = new DateTime();
1025
		$date->modify("-7 days");
1026
		$oneweek = $date->format("Y-m-d H:i:s");
1027
        
1028
		if ($request->getStatus() == "Closed" 
1029
			&& $logTime < $oneweek 
1030
			&& !User::getCurrent()->isAdmin() 
1031
			&& !User::getCurrent()->isCheckuser()) {
1032
			SessionAlert::error("Only administrators and checkusers can reopen a request that has been closed for over a week.");
1033
			header("Location: acc.php?action=zoom&id={$request->getId()}");
1034
			die();
1035
		}
1036
        
1037
		if ($request->getStatus() == $_GET['target']) {
1038
			SessionAlert::error(
1039
				"Cannot set status, target already deferred to " . htmlentities($_GET['target']), 
1040
				"Error");
1041
			header("Location: acc.php?action=zoom&id={$request->getId()}");
1042
			die();
1043
		}
1044
        
1045
		$database = gGetDb();
1046
		$database->transactionally(function() use ($database, $request)
1047
		{
1048
			global $availableRequestStates;
1049
                
1050
			$request->setReserved(0);
1051
			$request->setStatus($_GET['target']);
1052
			$request->updateChecksum();
1053
			$request->save();
1054
            
1055
			$deto = $availableRequestStates[$_GET['target']]['deferto'];
1056
			$detolog = $availableRequestStates[$_GET['target']]['defertolog'];
1057
            
1058
			Logger::deferRequest($database, $request, $detolog);
1059
        
1060
			Notification::requestDeferred($request);
1061
			SessionAlert::success("Request {$request->getId()} deferred to $deto");
1062
			header("Location: acc.php");
1063
		});
1064
        
1065
		die();
1066
	}
1067
	else {
1068
		BootstrapSkin::displayAlertBox("Defer target not valid.", "alert-error", "Error", true, false);
1069
		BootstrapSkin::displayInternalFooter();
1070
		die();
1071
	}
1072
}
1073
elseif ($action == "prefs") {
1074
	global $smarty, $enforceOAuth;
1075
    
1076
	if (isset ($_POST['sig'])) {
1077
		$user = User::getCurrent();
1078
		$user->setWelcomeSig($_POST['sig']);
1079
		$user->setEmailSig($_POST['emailsig']);
1080
		$user->setAbortPref(isset($_POST['abortpref']) ? 1 : 0);
1081
        
1082
		if (isset($_POST['email'])) {
1083
			$mailisvalid = filter_var(trim($_POST['email']), FILTER_VALIDATE_EMAIL);
1084
            
1085
			if ($mailisvalid === false) {
1086
				BootstrapSkin::displayAlertBox("Invalid email address", "alert-error", "Error!");
1087
			}
1088
			else {
1089
				$user->setEmail(trim($_POST['email']));
1090
			}
1091
		}
1092
1093
		try {
1094
			$user->save();
1095
		}
1096
		catch (PDOException $ex) {
1097
			BootstrapSkin::displayAlertBox($ex->getMessage(), "alert-error", "Error saving Preferences", true, false);
1098
			BootstrapSkin::displayInternalFooter();
1099
			die();
1100
		}
1101
        
1102
		BootstrapSkin::displayAlertBox("Preferences updated!", "alert-info");
1103
	}
1104
    
1105
	$smarty->assign("enforceOAuth", $enforceOAuth);
1106
	$smarty->display("prefs.tpl");
1107
	BootstrapSkin::displayInternalFooter();
1108
	die();
1109
}
1110
elseif ($action == "done" && $_GET['id'] != "") {
1111
	// check for valid close reasons
1112
	global $messages, $baseurl, $smarty;
1113
	
1114
	if (isset($_GET['email'])) {
1115
		if ($_GET['email'] == 0 || $_GET['email'] == "custom") {
1116
			$validEmail = true;
1117
		}
1118
		else {
1119
			$validEmail = EmailTemplate::getById($_GET['email'], gGetDb()) != false;
1120
		}
1121
	}
1122
	else {
1123
		$validEmail = false;
1124
	}
1125
    
1126
	if ($validEmail == false) {
1127
		BootstrapSkin::displayAlertBox("Invalid close reason", "alert-error", "Error", true, false);
1128
		BootstrapSkin::displayInternalFooter();
1129
		die();
1130
	}
1131
	
1132
	// sanitise this input ready for inclusion in queries
1133
	$request = Request::getById($_GET['id'], gGetDb());
1134
    
1135
	if ($request == false) {
1136
		// Notifies the user and stops the script.
1137
		BootstrapSkin::displayAlertBox("The request ID supplied is invalid!", "alert-error", "Error", true, false);
1138
		BootstrapSkin::displayInternalFooter();
1139
		die();
1140
	}
1141
    
1142
	$gem = $_GET['email'];
1143
	
1144
	// check the checksum is valid
1145
	if ($request->getChecksum() != $_GET['sum']) {
1146
		BootstrapSkin::displayAlertBox("This is similar to an edit conflict on Wikipedia; it means that you have tried to perform an action on a request that someone else has performed an action on since you loaded the page.", "alert-error", "Invalid Checksum", true, false);
1147
		BootstrapSkin::displayInternalFooter();
1148
		die();
1149
	}
1150
	
1151
	// check if an email has already been sent
1152
	if ($request->getEmailSent() == "1" && !isset($_GET['override']) && $gem != 0) {
1153
		$alertContent = "<p>This request has already been closed in a manner that has generated an e-mail to the user, Proceed?</p><br />";
1154
		$alertContent .= "<div class=\"row-fluid\">";
1155
		$alertContent .= "<a class=\"btn btn-success offset3 span3\"  href=\"$baseurl/acc.php?sum=" . $_GET['sum'] . "&amp;action=done&amp;id=" . $_GET['id'] . "&amp;override=yes&amp;email=" . $_GET['email'] . "\">Yes</a>";
1156
		$alertContent .= "<a class=\"btn btn-danger span3\" href=\"$baseurl/acc.php\">No</a>";
1157
		$alertContent .= "</div>";
1158
        
1159
		BootstrapSkin::displayAlertBox($alertContent, "alert-info", "Warning!", true, false, false, true);
1160
		BootstrapSkin::displayInternalFooter();
1161
		die();
1162
	}
1163
	
1164
	// check the request is not reserved by someone else
1165
	if ($request->getReserved() != 0 && !isset($_GET['reserveoverride']) && $request->getReserved() != User::getCurrent()->getId()) {
1166
		$alertContent = "<p>This request is currently marked as being handled by " . $request->getReservedObject()->getUsername() . ", Proceed?</p><br />";
1167
		$alertContent .= "<div class=\"row-fluid\">";
1168
		$alertContent .= "<a class=\"btn btn-success offset3 span3\"  href=\"$baseurl/acc.php?" . $_SERVER["QUERY_STRING"] . "&reserveoverride=yes\">Yes</a>";
1169
		$alertContent .= "<a class=\"btn btn-danger span3\" href=\"$baseurl/acc.php\">No</a>";
1170
		$alertContent .= "</div>";
1171
        
1172
		BootstrapSkin::displayAlertBox($alertContent, "alert-info", "Warning!", true, false, false, true);
1173
		BootstrapSkin::displayInternalFooter();
1174
		die();
1175
	}
1176
	    
1177
	if ($request->getStatus() == "Closed") {
1178
		BootstrapSkin::displayAlertBox("Cannot close this request. Already closed.", "alert-error", "Error", true, false);
1179
		BootstrapSkin::displayInternalFooter();
1180
		die();
1181
	}
1182
	
1183
	// Checks whether the username is already in use on Wikipedia.
1184
	$userexist = file_get_contents("http://en.wikipedia.org/w/api.php?action=query&list=users&ususers=" . urlencode($request->getName()) . "&format=php");
1185
	$ue = unserialize($userexist);
1186
	if (!isset ($ue['query']['users']['0']['missing'])) {
1187
		$exists = true;
1188
	}
1189
	else {
1190
		$exists = false;
1191
	}
1192
	
1193
	// check if a request being created does not already exist. 
1194
	if ($gem == 1 && !$exists && !isset($_GET['createoverride'])) {
1195
		$alertContent = "<p>You have chosen to mark this request as \"created\", but the account does not exist on the English Wikipedia, proceed?</p><br />";
1196
		$alertContent .= "<div class=\"row-fluid\">";
1197
		$alertContent .= "<a class=\"btn btn-success offset3 span3\"  href=\"$baseurl/acc.php?" . $_SERVER["QUERY_STRING"] . "&amp;createoverride=yes\">Yes</a>";
1198
		$alertContent .= "<a class=\"btn btn-danger span3\" href=\"$baseurl/acc.php\">No</a>";
1199
		$alertContent .= "</div>";
1200
        
1201
		BootstrapSkin::displayAlertBox($alertContent, "alert-info", "Warning!", true, false, false, true);
1202
		BootstrapSkin::displayInternalFooter();
1203
		die();
1204
	}
1205
	
1206
	$messageBody = null;
1207
    
1208
	// custom close reasons
1209
	if ($gem == 'custom') {
1210
		if (!isset($_POST['msgbody']) or empty($_POST['msgbody'])) {
1211
			// Send it through htmlspecialchars so HTML validators don't complain. 
1212
			$querystring = htmlspecialchars($_SERVER["QUERY_STRING"], ENT_COMPAT, 'UTF-8'); 
1213
            
1214
			$template = false;
1215
			if (isset($_GET['preload'])) {
1216
				$template = EmailTemplate::getById($_GET['preload'], gGetDb());
1217
			}
1218
            
1219
			if ($template != false) {
1220
				$preloadTitle = $template->getName();
1221
				$preloadText = $template->getText();
1222
				$preloadAction = $template->getDefaultAction();
1223
			}
1224
			else {
1225
				$preloadText = "";
1226
				$preloadTitle = "";
1227
				$preloadAction = "";
1228
			}
1229
            
1230
			$smarty->assign("requeststates", $availableRequestStates);
1231
			$smarty->assign("defaultAction", $preloadAction);
1232
			$smarty->assign("preloadtext", $preloadText);
1233
			$smarty->assign("preloadtitle", $preloadTitle);
1234
			$smarty->assign("querystring", $querystring);
1235
			$smarty->assign("request", $request);
1236
			$smarty->assign("iplocation", $locationProvider->getIpLocation($request->getTrustedIp()));
1237
			$smarty->display("custom-close.tpl");
1238
			BootstrapSkin::displayInternalFooter();
1239
			die();
1240
		}
1241
1242
		$headers = 'From: [email protected]' . "\r\n";
1243
		if (!User::getCurrent()->isAdmin() || isset($_POST['ccmailist']) && $_POST['ccmailist'] == "on") {
1244
			$headers .= 'Cc: [email protected]' . "\r\n";
1245
		}
1246
1247
		$headers .= 'X-ACC-Request: ' . $request->getId() . "\r\n";
1248
		$headers .= 'X-ACC-UserID: ' . User::getCurrent()->getId() . "\r\n";
1249
1250
		// Get the closing user's Email signature and append it to the Email.
1251
		if (User::getCurrent()->getEmailSig() != "") {
1252
			$emailsig = html_entity_decode(User::getCurrent()->getEmailSig(), ENT_QUOTES, "UTF-8");
1253
			mail($request->getEmail(), "RE: [ACC #{$request->getId()}] English Wikipedia Account Request", $_POST['msgbody'] . "\n\n" . $emailsig, $headers);
1254
		}
1255
		else {
1256
			mail($request->getEmail(), "RE: [ACC #{$request->getId()}] English Wikipedia Account Request", $_POST['msgbody'], $headers);
1257
		}
1258
1259
		$request->setEmailSent(1);
1260
		$messageBody = $_POST['msgbody'];
1261
1262
		if ($_POST['action'] == EmailTemplate::CREATED || $_POST['action'] == EmailTemplate::NOT_CREATED) {
1263
			$request->setStatus('Closed');
1264
1265
			if ($_POST['action'] == EmailTemplate::CREATED) {
1266
				$gem  = 'custom-y';
1267
				$crea = "Custom, Created";
1268
			}
1269
			else {
1270
				$gem  = 'custom-n';
1271
				$crea = "Custom, Not Created";
1272
			}
1273
1274
			Logger::closeRequest(gGetDb(), $request, $gem, $messageBody);
0 ignored issues
show
$request is of type object<DataObject>|null, but the function expects a object<Request>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1275
			
1276
			Notification::requestClosed($request, $crea);
0 ignored issues
show
$request is of type object<DataObject>|null, but the function expects a object<Request>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1277
			BootstrapSkin::displayAlertBox(
1278
				"Request " . $request->getId() . " (" . htmlentities($request->getName(), ENT_COMPAT, 'UTF-8') . ") marked as 'Done'.", 
1279
				"alert-success");
1280
		}
1281
		else if ($_POST['action'] == "mail") {
1282
			// no action other than send mail!
1283
			Logger::sentMail(gGetDb(), $request, $messageBody);
0 ignored issues
show
$request is of type object<DataObject>|null, but the function expects a object<Request>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1284
			Logger::unreserve(gGetDb(), $request);
1285
1286
			Notification::sentMail($request);
0 ignored issues
show
$request is of type object<DataObject>|null, but the function expects a object<Request>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1287
			BootstrapSkin::displayAlertBox("Sent mail to Request {$request->getId()}", 
1288
				"alert-success");
1289
		}
1290
		else if (array_key_exists($_POST['action'], $availableRequestStates)) {
1291
			// Defer
1292
1293
			$request->setStatus($_POST['action']);
1294
			$deto = $availableRequestStates[$_POST['action']]['deferto'];
1295
			$detolog = $availableRequestStates[$_POST['action']]['defertolog'];
1296
1297
			Logger::sentMail(gGetDb(), $request, $messageBody);
0 ignored issues
show
$request is of type object<DataObject>|null, but the function expects a object<Request>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1298
			Logger::deferRequest(gGetDb(), $request, $detolog);
1299
			
1300
			Notification::requestDeferredWithMail($request);
1301
			BootstrapSkin::displayAlertBox("Request {$request->getId()} deferred to $deto, sending an email.", 
1302
				"alert-success");
1303
		}
1304
		else {
1305
			// hmm. not sure what happened. Log that we sent the mail anyway.
1306
			Logger::sentMail(gGetDb(), $request, $messageBody);
0 ignored issues
show
$request is of type object<DataObject>|null, but the function expects a object<Request>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1307
			Logger::unreserve(gGetDb(), $request);
0 ignored issues
show
$request is of type object<DataObject>|null, but the function expects a object<Request>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1308
1309
			Notification::sentMail($request);
0 ignored issues
show
$request is of type object<DataObject>|null, but the function expects a object<Request>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1310
			BootstrapSkin::displayAlertBox("Sent mail to Request {$request->getId()}", 
1311
				"alert-success");
1312
		}
1313
1314
		$request->setReserved(0);
1315
		$request->save();
1316
		
1317
		$request->updateChecksum();
1318
		$request->save();
1319
1320
		echo defaultpage();
1321
		BootstrapSkin::displayInternalFooter();
1322
		die();		
1323
	}
1324
	else {
1325
		// Not a custom close, just a normal close
1326
	    
1327
		$request->setStatus('Closed');
1328
		$request->setReserved(0);
1329
		
1330
		// TODO: make this transactional
1331
		$request->save();
1332
		
1333
		Logger::closeRequest(gGetDb(), $request, $gem, $messageBody);
0 ignored issues
show
$request is of type object<DataObject>|null, but the function expects a object<Request>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1334
		
1335
		if ($gem == '0') {
1336
			$crea = "Dropped";
1337
		}
1338
		else {
1339
			$template = EmailTemplate::getById($gem, gGetDb());
1340
			$crea = $template->getName();
1341
		}
1342
1343
		Notification::requestClosed($request, $crea);
0 ignored issues
show
$request is of type object<DataObject>|null, but the function expects a object<Request>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1344
		BootstrapSkin::displayAlertBox("Request " . $request->getId() . " (" . htmlentities($request->getName(), ENT_COMPAT, 'UTF-8') . ") marked as 'Done'.", "alert-success");
1345
		
1346
		$towhom = $request->getEmail();
1347
		if ($gem != "0") {
1348
			sendemail($gem, $towhom, $request->getId());
1349
			$request->setEmailSent(1);
1350
		}
1351
		
1352
		$request->updateChecksum();
1353
		$request->save();
1354
		
1355
		echo defaultpage();
1356
		BootstrapSkin::displayInternalFooter();
1357
		die();
1358
	}
1359
}
1360
elseif ($action == "zoom") {
1361
	if (!isset($_GET['id'])) {
1362
		BootstrapSkin::displayAlertBox("No request specified!", "alert-error", "Error!", true, false);
1363
		BootstrapSkin::displayInternalFooter();
1364
		die();
1365
	}
1366
    
1367
	if (isset($_GET['hash'])) {
1368
		$urlhash = $_GET['hash'];
1369
	}
1370
	else {
1371
		$urlhash = "";
1372
	}
1373
	echo zoomPage($_GET['id'], $urlhash);
1374
1375
	$tailscript = getTypeaheadSource(User::getAllUsernames(gGetDb()));
1376
	BootstrapSkin::displayInternalFooter($tailscript);
1377
	die();
1378
}
1379
elseif ($action == "logs") {
1380
	global $baseurl;
1381
	
1382
	$filterUser = isset($_GET['filterUser']) && $_GET['filterUser'] != "" ? $_GET['filterUser'] : false;
1383
	$filterAction = isset($_GET['filterAction']) && $_GET['filterAction'] != "" ? $_GET['filterAction'] : false;
1384
	
1385
	$limit = 100;
1386
	if (isset($_GET['limit'])) {
1387
		$limit = (int)$_GET['limit'];
1388
	}
1389
	
1390
	$offset = 0;
1391
	$page = 1;
1392
	if (isset($_GET['page'])) {
1393
		$page = (int)$_GET['page'];
1394
		$offset = ($page - 1) * $limit;
1395
	}
1396
	
1397
	$logs = Logger::getLogs($filterUser, $filterAction, $limit, $offset);
1398
	if ($logs === false) {
1399
		$smarty->assign("logs", array());
1400
		$smarty->display("logs/main.tpl");
1401
		BootstrapSkin::displayInternalFooter();
1402
		die();
1403
	}
1404
	
1405
	$count = $logs['count'];
1406
	unset($logs['count']);
1407
	
1408
	// The number of pages on the pager to show. Must be odd
1409
	$pageLimit = 9;
1410
	
1411
	$pageData = array( 
1412
		'canprev' => $page != 1,
1413
		'cannext' => ($page * $limit) < $count,
1414
		'maxpage' => ceil($count / $limit),
1415
		'pagelimit' => $pageLimit,
1416
	);
1417
	
1418
	$pageMargin = (($pageLimit - 1) / 2);
1419
	$pageData['lowpage'] = max(1, $page - $pageMargin);
1420
	$pageData['hipage'] = min($pageData['maxpage'], $page + $pageMargin);
1421
	
1422
	$pageCount = ($pageData['hipage'] - $pageData['lowpage']) + 1;
1423
	
1424
	if ($pageCount < $pageLimit) {
1425
		if ($pageData['lowpage'] == 1 && $pageData['hipage'] == $pageData['maxpage']) {
1426
			// nothing to do, we're already at max range.	
1427
		}
1428
		elseif ($pageData['lowpage'] == 1 && $pageData['hipage'] < $pageData['maxpage']) {
1429
			$pageData['hipage'] = min($pageLimit, $pageData['maxpage']);
1430
		}
1431
		elseif ($pageData['lowpage'] > 1 && $pageData['hipage'] == $pageData['maxpage']) {
1432
			$pageData['lowpage'] = max(1, $pageData['maxpage'] - $pageLimit + 1);
1433
		}
1434
	}
1435
	
1436
	$pageData['pages'] = range($pageData['lowpage'], $pageData['hipage']);
1437
		
1438
	$smarty->assign("pagedata", $pageData);
1439
	
1440
	$smarty->assign("limit", $limit);
1441
	$smarty->assign("page", $page);
1442
1443
	$smarty->assign("logs", $logs);
1444
	
1445
	
1446
	$smarty->assign("filterUser", $filterUser);
1447
	$smarty->assign("filterAction", $filterAction);
1448
	$smarty->display("logs/main.tpl");
1449
1450
	$tailscript = getTypeaheadSource(User::getAllUsernames(gGetDb(), true));
1451
	
1452
	BootstrapSkin::displayInternalFooter($tailscript);
1453
	die();
1454
}
1455
elseif ($action == "reserve") {
1456
	$database = gGetDb();
1457
    
1458
	$database->transactionally(function() use ($database)
1459
	{
1460
		$request = Request::getById($_GET['resid'], $database);
1461
        
1462
		if ($request == false) {
1463
			throw new TransactionException("Request not found", "Error");
1464
		}
1465
        
1466
		global $enableEmailConfirm, $baseurl;
1467
		if ($enableEmailConfirm == 1) {
1468
			if ($request->getEmailConfirm() != "Confirmed") {
1469
				throw new TransactionException("Email address not yet confirmed for this request.", "Error");
1470
			}
1471
		}
1472
1473
		$logQuery = $database->prepare(<<<SQL
1474
SELECT timestamp FROM log
1475
WHERE objectid = :request AND objecttype = 'Request' AND action LIKE 'Closed%'
1476
ORDER BY timestamp DESC LIMIT 1;
1477
SQL
1478
		);
1479
		$logQuery->bindValue(":request", $request->getId());
1480
		$logQuery->execute();
1481
		$logTime = $logQuery->fetchColumn();
1482
		$logQuery->closeCursor();
1483
        
1484
		$date = new DateTime();
1485
		$date->modify("-7 days");
1486
		$oneweek = $date->format("Y-m-d H:i:s");
1487
        
1488
		if ($request->getStatus() == "Closed" && $logTime < $oneweek && !User::getCurrent($database)->isAdmin()) {
1489
			throw new TransactionException("Only administrators and checkusers can reserve a request that has been closed for over a week.", "Error");
1490
		}
1491
        
1492
	   	if ($request->getReserved() != 0 && $request->getReserved() != User::getCurrent($database)->getId()) {
1493
			throw new TransactionException("Request is already reserved by {$request->getReservedObject()->getUsername()}.", "Error");
1494
		}
1495
           
1496
		if ($request->getReserved() == 0) {
1497
			// Check the number of requests a user has reserved already
1498
			$doubleReserveCountQuery = $database->prepare("SELECT COUNT(*) FROM request WHERE reserved = :userid;");
1499
			$doubleReserveCountQuery->bindValue(":userid", User::getCurrent($database)->getId());
1500
			$doubleReserveCountQuery->execute();
1501
			$doubleReserveCount = $doubleReserveCountQuery->fetchColumn();
1502
			$doubleReserveCountQuery->closeCursor();
1503
1504
			// User already has at least one reserved. 
1505
			if ($doubleReserveCount != 0) {
1506
				SessionAlert::warning("You have multiple requests reserved!");
1507
			}
1508
1509
			// Is the request closed?
1510
			if (!isset($_GET['confclosed'])) {
1511
				if ($request->getStatus() == "Closed") {
1512
					// FIXME: bootstrappify properly
1513
					throw new TransactionException('This request is currently closed. Are you sure you wish to reserve it?<br /><ul><li><a href="' . $_SERVER["REQUEST_URI"] . '&confclosed=yes">Yes, reserve this closed request</a></li><li><a href="' . $baseurl . '/acc.php">No, return to main request interface</a></li></ul>', "Request closed", "alert-info");
1514
				}
1515
			}	
1516
        
1517
			$request->setReserved(User::getCurrent($database)->getId());
1518
			$request->save();
1519
	
1520
			Logger::reserve($database, $request);
1521
                
1522
			Notification::requestReserved($request);
1523
                
1524
			SessionAlert::success("Reserved request {$request->getId()}.");
1525
		}
1526
        
1527
		header("Location: $baseurl/acc.php?action=zoom&id={$request->getId()}");
1528
	});
1529
	    
1530
	die();	
1531
}
1532
elseif ($action == "breakreserve") {
1533
	global $smarty;
1534
    
1535
	$database = gGetDb();
1536
    
1537
	$request = Request::getById($_GET['resid'], $database);
1538
        
1539
	if ($request == false) {
1540
		BootstrapSkin::displayAlertBox("Could not find request.", "alert-error", "Error", true, false);
1541
		BootstrapSkin::displayInternalFooter();
1542
		die();
1543
	}
1544
    
1545
	if ($request->getReserved() == 0) {
1546
		BootstrapSkin::displayAlertBox("Request is not reserved.", "alert-error", "Error", true, false);
1547
		BootstrapSkin::displayInternalFooter();
1548
		die();
1549
	}
1550
    
1551
	$reservedUser = $request->getReservedObject();
1552
    
1553
	if ($reservedUser == false) {
1554
		BootstrapSkin::displayAlertBox("Could not find user who reserved the request (!!).", "alert-error", "Error", true, false);
1555
		BootstrapSkin::displayInternalFooter();
1556
		die();
1557
	}
1558
    
1559
	if ($reservedUser->getId() != User::getCurrent()->getId()) {
1560
		if (User::getCurrent()->isAdmin()) {
1561
			if (isset($_GET['confirm']) && $_GET['confirm'] == 1) {
1562
				$database->transactionally(function() use($database, $request)
1563
				{
1564
					$request->setReserved(0);
1565
					$request->save();
1566
1567
					Logger::breakReserve($database, $request);
1568
                
1569
					Notification::requestReserveBroken($request);
1570
					header("Location: acc.php");
1571
				});
1572
                
1573
				die();
1574
			}
1575
			else {
1576
				global $baseurl;
1577
				$smarty->assign("reservedUser", $reservedUser);
1578
				$smarty->assign("request", $request);
1579
                
1580
				$smarty->display("confirmations/breakreserve.tpl");
1581
			}
1582
		}
1583
		else {
1584
			echo "You cannot break " . htmlentities($reservedUser->getUsername()) . "'s reservation";
1585
		}
1586
	}
1587
	else {
1588
		$database->transactionally(function() use ($database, $request)
1589
		{
1590
			$request->setReserved(0);
1591
			$request->save();
1592
1593
			Logger::unreserve($database, $request);
1594
        
1595
			Notification::requestUnreserved($request);
1596
			header("Location: acc.php");
1597
		});
1598
        
1599
		die();
1600
	}
1601
    
1602
	BootstrapSkin::displayInternalFooter();
1603
	die();		
1604
}
1605
elseif ($action == "comment") {
1606
	global $smarty;
1607
    
1608
	$request = Request::getById($_GET['id'], gGetDb());
1609
	$smarty->assign("request", $request);
1610
	$smarty->display("commentform.tpl");
1611
	BootstrapSkin::displayInternalFooter();
1612
	die();
1613
}
1614
elseif ($action == "comment-add") {
1615
	global $baseurl, $smarty;
1616
    
1617
	$request = Request::getById($_POST['id'], gGetDb());
1618
	if ($request == false) {
1619
		BootstrapSkin::displayAlertBox("Could not find request!", "alert-error", "Error", true, false);
1620
		BootstrapSkin::displayInternalFooter();
1621
		die();
1622
	}
1623
    
1624
	if (!isset($_POST['comment']) || $_POST['comment'] == "") {
1625
		BootstrapSkin::displayAlertBox("Comment must be supplied!", "alert-error", "Error", true, false);
1626
		BootstrapSkin::displayInternalFooter();
1627
		die(); 
1628
	}
1629
    
1630
	$visibility = 'user';
1631
	if (isset($_POST['visibility'])) {
1632
		// sanity check
1633
		$visibility = $_POST['visibility'] == 'user' ? 'user' : 'admin';
1634
	}
1635
    
1636
	//Look for and detect IPv4/IPv6 addresses in comment text, and warn the commenter.
1637
	if ((preg_match('/\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/', $_POST['comment']) || preg_match('/(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/', $_POST['comment'])) && $_POST['privpol-check-override'] != "override") {
1638
			BootstrapSkin::displayAlertBox("IP address detected in comment text.  Warning acknowledgement checkbox must be checked.", "alert-error", "Error", true, false);
1639
			$smarty->assign("request", $request);
1640
			$smarty->assign("comment", $_POST['comment']);
1641
			$smarty->assign("actionLocation", "comment-add");
1642
			$smarty->display("privpol-warning.tpl");
1643
			BootstrapSkin::displayInternalFooter();
1644
			die();
1645
		}
1646
    
1647
	$comment = new Comment();
1648
	$comment->setDatabase(gGetDb());
1649
    
1650
	$comment->setRequest($request->getId());
1651
	$comment->setVisibility($visibility);
1652
	$comment->setUser(User::getCurrent()->getId());
1653
	$comment->setComment($_POST['comment']);
1654
    
1655
	$comment->save();
1656
    
1657
	if (isset($_GET['hash'])) {
1658
		$urlhash = urlencode(htmlentities($_GET['hash']));
1659
	}
1660
	else {
1661
		$urlhash = "";
1662
	}
1663
1664
	BootstrapSkin::displayAlertBox(
1665
		"<a href='$baseurl/acc.php?action=zoom&amp;id={$request->getId()}&amp;hash=$urlhash'>Return to request #{$request->getId()}</a>",
1666
		"alert-success",
1667
		"Comment added Successfully!",
1668
		true, false);
1669
        
1670
	Notification::commentCreated($comment);
1671
        
1672
	BootstrapSkin::displayInternalFooter();
1673
	die();
1674
}
1675
elseif ($action == "comment-quick") {
1676
	$request = Request::getById($_POST['id'], gGetDb());
1677
	if ($request == false) {
1678
		BootstrapSkin::displayAlertBox("Could not find request!", "alert-error", "Error", true, false);
1679
		BootstrapSkin::displayInternalFooter();
1680
		die();
1681
	}
1682
    
1683
	if (!isset($_POST['comment']) || $_POST['comment'] == "") {
1684
		header("Location: acc.php?action=zoom&id=" . $request->getId());
1685
		die(); 
1686
	}
1687
    
1688
	$visibility = 'user';
1689
	if (isset($_POST['visibility'])) {
1690
		// sanity check
1691
		$visibility = $_POST['visibility'] == 'user' ? 'user' : 'admin';
1692
	}
1693
1694
	//Look for and detect IPv4/IPv6 addresses in comment text, and warn the commenter.
1695
	if ((preg_match('/\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/', $_POST['comment']) || preg_match('/(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/', $_POST['comment'])) && $_POST['privpol-check-override'] != "override") {
1696
			BootstrapSkin::displayAlertBox("IP address detected in comment text.  Warning acknowledgement checkbox must be checked.", "alert-error", "Error", true, false);
1697
			$smarty->assign("request", $request);
1698
			$smarty->assign("comment", $_POST['comment']);
1699
			$smarty->assign("actionLocation", "comment-quick");
1700
			$smarty->display("privpol-warning.tpl");
1701
			BootstrapSkin::displayInternalFooter();
1702
			die();
1703
		}
1704
    
1705
	$comment = new Comment();
1706
	$comment->setDatabase(gGetDb());
1707
    
1708
	$comment->setRequest($request->getId());
1709
	$comment->setVisibility($visibility);
1710
	$comment->setUser(User::getCurrent()->getId());
1711
	$comment->setComment($_POST['comment']);
1712
    
1713
	$comment->save();
1714
    
1715
	Notification::commentCreated($comment);
1716
    
1717
	header("Location: acc.php?action=zoom&id=" . $request->getId());
1718
}
1719
elseif ($action == "changepassword") {
1720
	if ((!isset($_POST['oldpassword'])) || $_POST['oldpassword'] == "") {
1721
		//Throw an error if old password is not specified.
1722
		BootstrapSkin::displayAlertBox("You did not enter your old password.", "alert-error", "Error", true, false);
1723
		BootstrapSkin::displayInternalFooter();
1724
		die();
1725
	}
1726
	
1727
	if ((!isset($_POST['newpassword'])) || $_POST['newpassword'] == "") {
1728
		//Throw an error if new password is not specified.
1729
		BootstrapSkin::displayAlertBox("You did not enter your new password.", "alert-error", "Error", true, false);
1730
		BootstrapSkin::displayInternalFooter();
1731
		die();
1732
	}
1733
	
1734
	if ($_POST['newpassword'] != $_POST['newpasswordconfirm']) {
1735
		//Throw an error if new password does not match what is in the confirmation box.
1736
		BootstrapSkin::displayAlertBox("The 2 new passwords you entered do not match.", "alert-error", "Error", true, false);
1737
		BootstrapSkin::displayInternalFooter();
1738
		die();
1739
	}
1740
    
1741
	$user = User::getCurrent();
1742
	   
1743
	if (!$user->authenticate($_POST['oldpassword'])) {
1744
		//Throw an error if the old password field's value does not match the user's current password.
1745
		BootstrapSkin::displayAlertBox("The old password you entered is not correct.", "alert-error", "Error", true, false);
1746
		BootstrapSkin::displayInternalFooter();
1747
		die();
1748
	}
1749
    
1750
	$user->setPassword($_POST['newpassword']);
1751
	$user->save();
1752
    
1753
	BootstrapSkin::displayAlertBox("Password successfully changed!", "alert-success", "", false, false);
1754
	BootstrapSkin::displayInternalFooter();
1755
	die();
1756
}
1757
elseif ($action == "ec") {
1758
	// edit comment
1759
  
1760
	global $smarty, $baseurl;
1761
    
1762
	$comment = Comment::getById($_GET['id'], gGetDb());
1763
    
1764
	if ($comment == false) {
1765
		// Only using die("Message"); for errors looks ugly.
1766
		BootstrapSkin::displayAlertBox("Comment not found.", "alert-error", "Error", true, false);
1767
		BootstrapSkin::displayInternalFooter();
1768
		die();
1769
	}
1770
	
1771
	// Unauthorized if user is not an admin or the user who made the comment being edited.
1772
	if (!User::getCurrent()->isAdmin() && !User::getCurrent()->isCheckuser() && $comment->getUser() != User::getCurrent()->getId()) {
1773
		BootstrapSkin::displayAccessDenied();
1774
		BootstrapSkin::displayInternalFooter();
1775
		die();
1776
	}
1777
	
1778
	// get[id] is safe by this point.
1779
	
1780
	if ($_SERVER['REQUEST_METHOD'] == 'POST') {
1781
		$database = gGetDb();
1782
		$database->transactionally(function() use ($database, $comment, $baseurl)
1783
		{
1784
            
1785
			$comment->setComment($_POST['newcomment']);
1786
			$comment->setVisibility($_POST['visibility']);
1787
        
1788
			$comment->save();
1789
        
1790
			Logger::editComment($database, $comment);
1791
        
1792
			Notification::commentEdited($comment);
1793
        
1794
			SessionAlert::success("Comment has been saved successfully");
1795
			header("Location: $baseurl/acc.php?action=zoom&id=" . $comment->getRequest());
1796
		});
1797
        
1798
		die();    
1799
	}
1800
	else {
1801
		$smarty->assign("comment", $comment);
1802
		$smarty->display("edit-comment.tpl");
1803
		BootstrapSkin::displayInternalFooter();
1804
		die();
1805
	}
1806
}
1807
elseif ($action == "sendtouser") {
1808
	global $baseurl;
1809
    
1810
	$database = gGetDb();
1811
    
1812
	$requestObject = Request::getById($_POST['id'], $database);
1813
	if ($requestObject == false) {
1814
		BootstrapSkin::displayAlertBox("Request invalid", "alert-error", "Could not find request", true, false);
1815
		BootstrapSkin::displayInternalFooter();
1816
		die();
1817
	}
1818
    
1819
	$request = $requestObject->getId();
1820
    
1821
	$user = User::getByUsername($_POST['user'], $database);
1822
	$curuser = User::getCurrent()->getUsername();
1823
    
1824
	if ($user == false) {
1825
		BootstrapSkin::displayAlertBox("We couldn't find the user you wanted to send the reservation to. Please check that this user exists and is an active user on the tool.", "alert-error", "Could not find user", true, false);
1826
		BootstrapSkin::displayInternalFooter();
1827
		die();
1828
	}
1829
    
1830
	$database->transactionally(function() use ($database, $user, $request, $curuser)
1831
	{
1832
		$updateStatement = $database->prepare("UPDATE request SET reserved = :userid WHERE id = :request LIMIT 1;");
1833
		$updateStatement->bindValue(":userid", $user->getId());
1834
		$updateStatement->bindValue(":request", $request);
1835
		if (!$updateStatement->execute()) {
1836
			throw new TransactionException("Error updating reserved status of request.");   
1837
		}
1838
        
1839
		Logger::sendReservation($database, Request::getById($request, $database), $user);
1840
	});
1841
    
1842
	Notification::requestReservationSent($request, $user);
1843
	SessionAlert::success("Reservation sent successfully");
1844
	header("Location: $baseurl/acc.php?action=zoom&id=$request");
1845
}
1846
elseif ($action == "emailmgmt") {
1847
	global $smarty, $createdid, $availableRequestStates;
1848
    
1849
	/* New page for managing Emails, since I would rather not be handling editing
1850
	interface messages (such as the Sitenotice) and the new Emails in the same place. */
1851
	if (isset($_GET['create'])) {
1852
		if (!User::getCurrent()->isAdmin()) {
1853
			BootstrapSkin::displayAccessDenied();
1854
			BootstrapSkin::displayInternalFooter();
1855
			die();
1856
		}
1857
		if (isset($_POST['submit'])) {
1858
			$database = gGetDb();
1859
			$database->transactionally(function() use ($database)
1860
			{
1861
				global $baseurl;
1862
                
1863
				$emailTemplate = new EmailTemplate();
1864
				$emailTemplate->setDatabase($database);
1865
            
1866
				$emailTemplate->setName($_POST['name']);
1867
				$emailTemplate->setText($_POST['text']);
1868
				$emailTemplate->setJsquestion($_POST['jsquestion']);
1869
				$emailTemplate->setDefaultAction($_POST['defaultaction']);
1870
				$emailTemplate->setActive(isset($_POST['active']));
1871
1872
				// Check if the entered name already exists (since these names are going to be used as the labels for buttons on the zoom page).
1873
				// getByName(...) returns false on no records found.
1874
				if (EmailTemplate::getByName($_POST['name'], $database)) {
1875
					throw new TransactionException("That Email template name is already being used. Please choose another.");
1876
				}
1877
			
1878
				$emailTemplate->save();
1879
                
1880
				Logger::createEmail($database, $emailTemplate);
1881
                
1882
				Notification::emailCreated($emailTemplate);
1883
                
1884
				SessionAlert::success("Email template has been saved successfully.");
1885
				header("Location: $baseurl/acc.php?action=emailmgmt");
1886
			});
1887
            
1888
			die();
1889
		}
1890
        
1891
		$smarty->assign('id', null);
1892
		$smarty->assign('createdid', $createdid);
1893
		$smarty->assign('requeststates', $availableRequestStates);
1894
		$smarty->assign('emailTemplate', new EmailTemplate());
1895
		$smarty->assign('emailmgmtpage', 'Create'); //Use a variable so we don't need two Smarty templates for creating and editing.
1896
		$smarty->display("email-management/edit.tpl");
1897
		BootstrapSkin::displayInternalFooter();
1898
		die();
1899
	}
1900
	if (isset($_GET['edit'])) {
1901
		global $createdid;
1902
        
1903
		$database = gGetDb();
1904
        
1905
		if (isset($_POST['submit'])) {
1906
			$emailTemplate = EmailTemplate::getById($_GET['edit'], $database);
1907
			// Allow the user to see the edit form (with read only fields) but not POST anything.
1908
			if (!User::getCurrent()->isAdmin()) {
1909
				BootstrapSkin::displayAccessDenied();
1910
				BootstrapSkin::displayInternalFooter();
1911
				die();
1912
			}
1913
            
1914
			$emailTemplate->setName($_POST['name']);
1915
			$emailTemplate->setText($_POST['text']);
1916
			$emailTemplate->setJsquestion($_POST['jsquestion']);
1917
			
1918
			if ($_GET['edit'] == $createdid) {
1919
				// Both checkboxes on the main created message should always be enabled.
1920
				$emailTemplate->setDefaultAction(EmailTemplate::CREATED);
1921
				$emailTemplate->setActive(1);
1922
				$emailTemplate->setPreloadOnly(0);
1923
			}
1924
			else {
1925
				$emailTemplate->setDefaultAction($_POST['defaultaction']);
1926
				$emailTemplate->setActive(isset($_POST['active']));
1927
				$emailTemplate->setPreloadOnly(isset($_POST['preloadonly']));
1928
			}
1929
				
1930
			// Check if the entered name already exists (since these names are going to be used as the labels for buttons on the zoom page).
1931
			$nameCheck = EmailTemplate::getByName($_POST['name'], gGetDb());
1932
			if ($nameCheck != false && $nameCheck->getId() != $_GET['edit']) {
1933
				BootstrapSkin::displayAlertBox("That Email template name is already being used. Please choose another.");
1934
				BootstrapSkin::displayInternalFooter();
1935
				die();
1936
			}
1937
1938
			$database->transactionally(function() use ($database, $emailTemplate)
1939
			{
1940
				$emailTemplate->save();
1941
                
1942
				Logger::editedEmail($database, $emailTemplate);
1943
            
1944
				global $baseurl;
1945
                
1946
				Notification::emailEdited($emailTemplate);
1947
				SessionAlert::success("Email template has been saved successfully.");
1948
				header("Location: $baseurl/acc.php?action=emailmgmt");
1949
			});
1950
            
1951
			die();
1952
		}
1953
        
1954
		$emailTemplate = EmailTemplate::getById($_GET['edit'], gGetDb());
1955
		$smarty->assign('id', $emailTemplate->getId());
1956
		$smarty->assign('emailTemplate', $emailTemplate);
1957
		$smarty->assign('createdid', $createdid);
1958
		$smarty->assign('requeststates', $availableRequestStates);
1959
		$smarty->assign('emailmgmtpage', 'Edit'); // Use a variable so we don't need two Smarty templates for creating and editing.
1960
		$smarty->display("email-management/edit.tpl");
1961
		BootstrapSkin::displayInternalFooter();
1962
		die();
1963
	}
1964
    
1965
	$query = "SELECT * FROM emailtemplate WHERE active = 1";
1966
	$statement = gGetDb()->prepare($query);
1967
	$statement->execute();
1968
	$rows = $statement->fetchAll(PDO::FETCH_CLASS, "EmailTemplate");
1969
	$smarty->assign('activeemails', $rows);
1970
        
1971
	$query = "SELECT * FROM emailtemplate WHERE active = 0";
1972
	$statement = gGetDb()->prepare($query);
1973
	$statement->execute();
1974
	$inactiverows = $statement->fetchAll(PDO::FETCH_CLASS, "EmailTemplate");
1975
	$smarty->assign('inactiveemails', $inactiverows);
1976
 
1977
	if (count($inactiverows) > 0) {
1978
		$smarty->assign('displayinactive', true);
1979
	}
1980
	else {
1981
		$smarty->assign('displayinactive', false);
1982
	}
1983
    
1984
	$smarty->display("email-management/main.tpl");
1985
	BootstrapSkin::displayInternalFooter();
1986
	die();
1987
}
1988
elseif ($action == "oauthdetach") {
1989
	if ($enforceOAuth) {
1990
		BootstrapSkin::displayAccessDenied();
1991
		BootstrapSkin::displayInternalFooter();
1992
		die();
1993
	}
1994
    
1995
	global $baseurl;
1996
        
1997
	$currentUser = User::getCurrent();
1998
	$currentUser->detachAccount();
1999
        
2000
	header("Location: {$baseurl}/acc.php?action=logout");
2001
}
2002
elseif ($action == "oauthattach") {
2003
	$database = gGetDb();
2004
	$database->transactionally(function() use ($database)
2005
	{
2006
		try {
2007
			global $oauthConsumerToken, $oauthSecretToken, $oauthBaseUrl, $oauthBaseUrlInternal;
2008
            
2009
			$user = User::getCurrent();
2010
            
2011
			// Get a request token for OAuth
2012
			$util = new OAuthUtility($oauthConsumerToken, $oauthSecretToken, $oauthBaseUrl, $oauthBaseUrlInternal);
2013
			$requestToken = $util->getRequestToken();
2014
2015
			// save the request token for later
2016
			$user->setOAuthRequestToken($requestToken->key);
2017
			$user->setOAuthRequestSecret($requestToken->secret);
2018
			$user->save();
2019
        
2020
			$redirectUrl = $util->getAuthoriseUrl($requestToken);
2021
        
2022
			header("Location: {$redirectUrl}");
2023
        
2024
		}
2025
		catch (Exception $ex) {
2026
			throw new TransactionException($ex->getMessage(), "Connection to Wikipedia failed.", "alert-error", 0, $ex);
2027
		}
2028
	});
2029
}
2030
# If the action specified does not exist, goto the default page.
2031
else {
2032
	echo defaultpage();
2033
	BootstrapSkin::displayInternalFooter();
2034
	die();
2035
}
2036