Completed
Pull Request — master (#526)
by Michael
01:57
created
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
// Get all the classes.
22
require_once 'functions.php';
23
initialiseSession();
24
require_once 'includes/PdoDatabase.php';
25
require_once 'includes/SmartyInit.php'; // this needs to be high up, but below config, functions, database and session init
26
require_once 'includes/session.php';
27
28
// Check to see if the database is unavailable.
29
// Uses the false variable as its the internal interface.
30
if (Offline::isOffline()) {
31
	echo Offline::getOfflineMessage(false);
32
	die();
33
}
34
35
// Initialize the class objects.
36
$session = new session();
37
$date = new DateTime();
38
39
// initialise providers
40
global $squidIpList;
41
/** @var ILocationProvider $locationProvider */
42
$locationProvider = new $locationProviderClass(gGetDb('acc'), $locationProviderApiKey);
43
/** @var IRDnsProvider $rdnsProvider */
44
$rdnsProvider = new $rdnsProviderClass(gGetDb('acc'));
45
/** @var IAntiSpoofProvider $antispoofProvider */
46
$antispoofProvider = new $antispoofProviderClass();
47
/** @var IXffTrustProvider $xffTrustProvider */
48
$xffTrustProvider = new $xffTrustProviderClass($squidIpList);
49
50
// Clears the action variable.
51
$action = '';
52
53
// Assign the correct value to the action variable.
54
// The value is retrieved from the $GET variable.
55
if (isset($_GET['action'])) {
56
	$action = $_GET['action'];
57
}
58
59
// Clear session before banner and logged in as message is generated on logout attempt - Prom3th3an
60
if ($action == "logout") {
61
	session_unset();
62
    
63
	BootstrapSkin::displayInternalHeader();
64
	echo showlogin();
0 ignored issues
show
Are you sure the usage of showlogin() is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
65
	BootstrapSkin::displayInternalFooter();
66
	die();
67
}
68
69
// Checks whether the user is set - the user should first login.
70
if (!isset($_SESSION['user'])) {
71
	$suser = '';
72
	BootstrapSkin::displayInternalHeader();
73
74
	// Checks whether the user want to reset his password or register a new account.
75
	// Performs the clause when the action is not one of the above options.
76
	if ($action != 'register' && $action != 'forgotpw' && $action != 'sreg' && $action != "registercomplete" && $action != "login") {
77
		echo showlogin();
0 ignored issues
show
Are you sure the usage of showlogin() is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
78
		BootstrapSkin::displayInternalFooter();
79
		die();
80
	}
81
	else {
82
		// A content block is created if the action is none of the above.
83
		// This block would later be used to keep all the HTML except the header and footer.
84
		$out = "<div id=\"content\">";
85
		echo $out;
86
	}
87
}
88
89
// Forces the current user to logout if necessary.
90
if (isset($_SESSION['userID'])) {
91
	$session->forceLogout($_SESSION['userID']);
92
}
93
94
BootstrapSkin::displayInternalHeader();
95
$session->checksecurity();
0 ignored issues
show
Deprecated Code introduced by
The function session::checksecurity() has been deprecated. ( Ignorable by Annotation )

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

95
/** @scrutinizer ignore-deprecated */ $session->checksecurity();
Loading history...
96
97
98
// When no action is specified the default Internal ACC are displayed.
99
// TODO: Improve way the method is called.
100
if ($action == '') {
101
	echo defaultpage();
102
	BootstrapSkin::displayInternalFooter();
103
	die();
104
}
105
elseif ($action == "sreg") {
106
	global $useOauthSignup, $smarty;
107
        
108
	// TODO: check blocked
109
	// TODO: check age.
110
    
111
	// check if user checked the "I have read and understand the interface guidelines" checkbox
112
	if (!isset($_REQUEST['guidelines'])) {
113
		$smarty->display("registration/alert-interfaceguidelines.tpl");
114
		BootstrapSkin::displayInternalFooter();
115
		die();
116
	}
117
	
118
	if (!filter_var($_REQUEST['email'], FILTER_VALIDATE_EMAIL)) {
119
		$smarty->display("registration/alert-invalidemail.tpl");
120
		BootstrapSkin::displayInternalFooter();
121
		die();
122
	}
123
    
124
	if ($_REQUEST['pass'] !== $_REQUEST['pass2']) {
125
		$smarty->display("registration/alert-passwordmismatch.tpl");
126
		BootstrapSkin::displayInternalFooter();
127
		die();
128
	}
129
    
130
	if (!$useOauthSignup) {
131
		if (!((string)(int)$_REQUEST['conf_revid'] === (string)$_REQUEST['conf_revid']) || $_REQUEST['conf_revid'] == "") {
132
			$smarty->display("registration/alert-confrevid.tpl");
133
			BootstrapSkin::displayInternalFooter();
134
			die();		
135
		}
136
	}
137
    
138
	if (User::getByUsername($_REQUEST['name'], gGetDb()) != false) {
139
		$smarty->display("registration/alert-usernametaken.tpl");
140
		BootstrapSkin::displayInternalFooter();
141
		die();
142
	}
143
    
144
	$query = gGetDb()->prepare("SELECT * FROM user WHERE email = :email LIMIT 1;");
145
	$query->execute(array(":email" => $_REQUEST['email']));
146
	if ($query->fetchObject("User") != false) {
147
		$smarty->display("registration/alert-emailtaken.tpl");
148
		BootstrapSkin::displayInternalFooter();
149
		die();
150
	}
151
	$query->closeCursor();
152
153
	$database = gGetDb();
154
    
155
	$database->transactionally(function() use ($database, $useOauthSignup)
156
	{
157
    
158
		$newUser = new User();
159
		$newUser->setDatabase($database);
160
    
161
		$newUser->setUsername($_REQUEST['name']);
162
		$newUser->setPassword($_REQUEST['pass']);
163
		$newUser->setEmail($_REQUEST['email']);
164
        
165
		if (!$useOauthSignup) {
166
			$newUser->setOnWikiName($_REQUEST['wname']);
167
			$newUser->setConfirmationDiff($_REQUEST['conf_revid']);
168
		}
169
        
170
		$newUser->save();
171
    
172
		global $oauthConsumerToken, $oauthSecretToken, $oauthBaseUrl, $oauthBaseUrlInternal, $useOauthSignup;
173
    
174
		if ($useOauthSignup) {
175
			try {
176
				// Get a request token for OAuth
177
				$util = new OAuthUtility($oauthConsumerToken, $oauthSecretToken, $oauthBaseUrl, $oauthBaseUrlInternal);
178
				$requestToken = $util->getRequestToken();
179
    
180
				// save the request token for later
181
				$newUser->setOAuthRequestToken($requestToken->key);
182
				$newUser->setOAuthRequestSecret($requestToken->secret);
183
				$newUser->save();
184
            
185
				Notification::userNew($newUser);
186
        
187
				$redirectUrl = $util->getAuthoriseUrl($requestToken);
188
            
189
				header("Location: {$redirectUrl}");
190
			}
191
			catch (Exception $ex) {
192
				throw new TransactionException(
193
					$ex->getMessage(), 
194
					"Connection to Wikipedia failed.", 
195
					"alert-error", 
196
					0, 
197
					$ex);
198
			}
199
		}
200
		else {
201
			global $baseurl;
202
			Notification::userNew($newUser);
203
			header("Location: {$baseurl}/acc.php?action=registercomplete");
204
		}
205
	});
206
    
207
	die();
208
}
209
elseif ($action == "register") {
210
	global $useOauthSignup, $smarty;
211
	$smarty->assign("useOauthSignup", $useOauthSignup);
212
	$smarty->display("registration/register.tpl");
213
	BootstrapSkin::displayInternalFooter();
214
	die();
215
}
216
elseif ($action == "registercomplete") {
217
	$smarty->display("registration/alert-registrationcomplete.tpl");
218
	BootstrapSkin::displayInternalFooter();
219
}
220
elseif ($action == "forgotpw") {
221
	global $baseurl, $smarty;
222
    
223
	if (isset ($_GET['si']) && isset ($_GET['id'])) {
224
		$user = User::getById($_GET['id'], gGetDb());
225
        
226
		if ($user === false) {
227
			BootstrapSkin::displayAlertBox("User not found.", "alert-error");
228
			BootstrapSkin::displayInternalFooter();
229
			die();
230
		}
231
        
232
		if (isset ($_POST['pw']) && isset ($_POST['pw2'])) {
233
			$hash = $user->getForgottenPasswordHash();
234
            
235
			if ($hash == $_GET['si']) {
236
				if ($_POST['pw'] == $_POST['pw2']) {
237
					$user->setPassword($_POST['pw2']);
238
					$user->save();
239
                    
240
					BootstrapSkin::displayAlertBox(
241
						"You may now <a href=\"$baseurl/acc.php\">Login</a>", 
242
						"alert-error", 
243
						"Password reset!", 
244
						true, 
245
						false);
246
                    
247
					BootstrapSkin::displayInternalFooter();
248
					die();
249
				}
250
				else {
251
					BootstrapSkin::displayAlertBox("Passwords did not match!", "alert-error", "Error", true, false);
252
					BootstrapSkin::displayInternalFooter();
253
					die();
254
				}
255
			}
256
			else {
257
				BootstrapSkin::displayAlertBox("Invalid request<!-- 1 -->", "alert-error", "Error", true, false);
258
				BootstrapSkin::displayInternalFooter();
259
				die();
260
			}
261
		}
262
        
263
		$hash = $user->getForgottenPasswordHash();
264
        
265
		if ($hash == $_GET['si']) {
266
			$smarty->assign('user', $user);
267
			$smarty->assign('si', $_GET['si']);
268
			$smarty->assign('id', $_GET['id']);
269
			$smarty->display('forgot-password/forgotpwreset.tpl');
270
		}
271
		else {
272
			BootstrapSkin::displayAlertBox(
273
				"The hash supplied in the link did not match the hash in the database!", 
274
				"alert-error", 
275
				"Invalid request", 
276
				true, 
277
				false);
278
		}
279
        
280
		BootstrapSkin::displayInternalFooter();
281
		die();
282
	}
283
    
284
	if (isset ($_POST['username'])) {
285
		$user = User::getByUsername($_POST['username'], gGetDb());
286
287
		if ($user == false) {
288
			BootstrapSkin::displayAlertBox(
289
				"Could not find user with that username and email address!", 
290
				"alert-error", 
291
				"Error", 
292
				true, 
293
				false);
294
            
295
			BootstrapSkin::displayInternalFooter();
296
			die();
297
		}
298
		elseif (strtolower($_POST['email']) != strtolower($user->getEmail())) {
299
			BootstrapSkin::displayAlertBox("Could not find user with that username and email address!", 
300
				"alert-error", 
301
				"Error", 
302
				true, 
303
				false);
304
            
305
			BootstrapSkin::displayInternalFooter();
306
			die();
307
		}
308
		else {
309
			$hash = $user->getForgottenPasswordHash();
310
                       
311
			$smarty->assign("user", $user);
312
			$smarty->assign("hash", $hash);
313
			$smarty->assign("remoteAddress", $_SERVER['REMOTE_ADDR']);
314
            
315
			$mailtxt = $smarty->fetch("forgot-password/reset-mail.tpl");
316
			$headers = 'From: [email protected]';
317
            
318
			mail(
319
				$user->getEmail(), 
320
				"English Wikipedia Account Request System - Forgotten password", 
321
				$mailtxt, 
322
				$headers);
323
            
324
			BootstrapSkin::displayAlertBox(
325
				"<strong>Your password reset request has been completed.</strong> Please check your e-mail.", 
326
				"alert-success", 
327
				"", 
328
				false, 
329
				false);
330
            
331
			BootstrapSkin::displayInternalFooter();
332
			die();
333
		}
334
	}
335
    
336
	$smarty->display('forgot-password/forgotpw.tpl');
337
338
	BootstrapSkin::displayInternalFooter();
339
	die();
340
}
341
elseif ($action == "login") {
342
	global $baseurl, $smarty;
343
    
344
	if (!isset($_POST['username'])) {
345
		header("Location: $baseurl/acc.php?error=authfail&tplUsername=");
346
		die();
347
	}
348
349
	$user = User::getByUsername($_POST['username'], gGetDb());
350
    
351
	if ($user == false || !$user->authenticate($_POST['password'])) {
352
		header("Location: $baseurl/acc.php?error=authfail&tplUsername=" . urlencode($_POST['username']));
353
		die();
354
	}
355
    
356
	if ($user->getStoredOnWikiName() == "##OAUTH##" && $user->getOAuthAccessToken() == null) {
357
		reattachOAuthAccount($user);   
358
	}
359
    
360
	if ($user->isOAuthLinked()) {
361
		try {
362
			// test retrieval of the identity
363
			$user->getOAuthIdentity();
364
		}
365
		catch (TransactionException $ex) {
366
			$user->setOAuthAccessToken(null);
367
			$user->setOAuthAccessSecret(null);
368
			$user->save();
369
            
370
			reattachOAuthAccount($user);
371
		}
372
	}
373
	else {
374
		global $enforceOAuth;
375
        
376
		if ($enforceOAuth) {
377
			reattachOAuthAccount($user);
378
		}
379
	}
380
    
381
	// At this point, the user has successfully authenticated themselves.
382
	// We now proceed to perform login-specific actions, and check the user actually has
383
	// the correct permissions to continue with the login.
384
    
385
	if ($user->getForcelogout()) {
386
		$user->setForcelogout(false);
387
		$user->save();
388
	}
389
    
390
	if ($user->isNew()) {
391
		header("Location: $baseurl/acc.php?error=newacct");
392
		die();
393
	}
394
    
395
	$database = gGetDb();
396
    
397
	$sqlText = <<<SQL
398
SELECT comment FROM log
399
WHERE action = :action AND objectid = :userid AND objecttype = 'User'
400
ORDER BY timestamp DESC LIMIT 1;
401
SQL;
402
    
403
	$suspendstatement = $database->prepare($sqlText);
404
    
405
	if ($user->isDeclined()) {
406
		$suspendAction = "Declined";
407
		$userid = $user->getId();
408
		$suspendstatement->bindValue(":action", $suspendAction);
409
		$suspendstatement->bindValue(":userid", $userid);
410
		$suspendstatement->execute();
411
        
412
		$suspendreason = $suspendstatement->fetchColumn();
413
        
414
		$suspendstatement->closeCursor();
415
        
416
		BootstrapSkin::displayInternalHeader();
417
		$smarty->assign("suspendreason", $suspendreason);
418
		$smarty->display("login/declined.tpl");
419
		BootstrapSkin::displayInternalFooter();
420
		die();
421
	}
422
    
423
	if ($user->isSuspended()) {
424
		$suspendAction = "Suspended";
425
		$userid = $user->getId();
426
		$suspendstatement->bindValue(":action", $suspendAction);
427
		$suspendstatement->bindValue(":userid", $userid);
428
		$suspendstatement->execute();
429
        
430
		$suspendreason = $suspendstatement->fetchColumn();
431
        
432
		$suspendstatement->closeCursor();
433
        
434
		BootstrapSkin::displayInternalHeader();
435
		$smarty->assign("suspendreason", $suspendreason);
436
		$smarty->display("login/suspended.tpl");
437
		BootstrapSkin::displayInternalFooter();
438
		die();
439
	}
440
    
441
	if ($user->getIdentified() < $forceIdentification && $forceIdentification !== false) {
442
		header("Location: $baseurl/acc.php?error=noid");
443
		die();
444
	}
445
    
446
	// At this point, we've tested that the user is OK, so we set the login cookies.
447
    
448
	$_SESSION['user'] = $user->getUsername();
449
	$_SESSION['userID'] = $user->getId();
450
    
451
	if ($user->getOAuthAccessToken() == null && $user->getStoredOnWikiName() == "##OAUTH##") {
452
		reattachOAuthAccount($user);
453
	}
454
    
455
	header("Location: $baseurl/acc.php");
456
}
457
elseif ($action == "messagemgmt") {
458
	global $smarty;
459
    
460
	if (isset($_GET['view'])) {
461
		$message = InterfaceMessage::getById($_GET['view'], gGetDb());
462
                
463
		if ($message == false) {
464
			BootstrapSkin::displayAlertBox("Unable to find specified message", "alert-error", "Error", true, false);
465
			BootstrapSkin::displayInternalFooter();
466
			die();
467
		}
468
        
469
		$smarty->assign("message", $message);
470
		$smarty->assign("readonly", true);
471
		$smarty->display("message-management/editform.tpl");
472
		BootstrapSkin::displayInternalFooter();
473
		die();
474
	}
475
	if (isset($_GET['edit'])) {
476
		if (!(User::getCurrent()->isAdmin() || User::getCurrent()->isCheckuser())) {
477
			BootstrapSkin::displayAccessDenied();
478
			BootstrapSkin::displayInternalFooter();
479
			die();
480
		}
481
        
482
		$database = gGetDb();
483
        
484
		$database->transactionally(function() use ($database)
485
		{
486
			global $smarty;
487
            
488
			$message = InterfaceMessage::getById($_GET['edit'], $database);
489
            
490
			if ($message == false) {
491
				throw new TransactionException("Unable to find specified message", "Error");
492
			}
493
            
494
			if (isset($_GET['submit'])) {
495
				$message->setContent($_POST['mailtext']);
0 ignored issues
show
The method setContent() does not exist on DataObject. It seems like you code against a sub-type of DataObject such as InterfaceMessage. ( Ignorable by Annotation )

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

495
				$message->/** @scrutinizer ignore-call */ 
496
              setContent($_POST['mailtext']);
Loading history...
496
				$message->setDescription($_POST['maildesc']);
0 ignored issues
show
The method setDescription() does not exist on DataObject. It seems like you code against a sub-type of DataObject such as InterfaceMessage. ( Ignorable by Annotation )

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

496
				$message->/** @scrutinizer ignore-call */ 
497
              setDescription($_POST['maildesc']);
Loading history...
497
				$message->save();
498
            
499
				Logger::interfaceMessageEdited(gGetDb(), $message);
500
              
501
				$smarty->assign("message", $message);
502
				$smarty->display("message-management/alert-editsuccess.tpl");
503
                
504
				Notification::interfaceMessageEdited($message);
505
                
506
				BootstrapSkin::displayInternalFooter();
507
				return;
508
			}
509
            
510
			$smarty->assign("message", $message);
511
			$smarty->assign("readonly", false);
512
			$smarty->display("message-management/editform.tpl");
513
        
514
			BootstrapSkin::displayInternalFooter();
515
		});
516
        
517
		die();
518
	}
519
    
520
	$sqlText = <<<SQL
521
        SELECT * 
522
        FROM interfacemessage 
523
        WHERE type = :type 
524
            AND description NOT LIKE '%[deprecated]';
525
SQL;
526
    
527
	$fetchStatement = gGetDb()->prepare($sqlText);
528
	$data = array();
529
        
530
	//$fetchStatement->execute(array(":type" => "Interface"));
531
	//$data['Public Interface messages'] = $fetchStatement->fetchAll(PDO::FETCH_CLASS, 'InterfaceMessage');
532
    
533
	$fetchStatement->execute(array(":type" => "Internal"));
534
	$data['Internal Interface messages'] = $fetchStatement->fetchAll(PDO::FETCH_CLASS, 'InterfaceMessage');
535
    
536
	$smarty->assign("data", $data);
537
	$smarty->display('message-management/view.tpl');
538
   
539
	BootstrapSkin::displayInternalFooter();
540
	die();
541
}
542
elseif ($action == "templatemgmt") {
543
	global $baseurl, $smarty;
544
    
545
	if (isset($_GET['view'])) {
546
		$template = WelcomeTemplate::getById($_GET['view'], gGetDb());
547
        
548
		if ($template === false) {
549
			SessionAlert::success("Something went wrong, we can't find the template you asked for! Please try again.");
550
			header("Location: {$baseurl}/acc.php?action=templatemgmt");
551
			die();
552
		}
553
        
554
		$smarty->assign("template", $template);
555
		$smarty->display("welcometemplate/view.tpl");
556
		BootstrapSkin::displayInternalFooter();
557
		die();
558
	}
559
    
560
	if (isset($_GET['add'])) {
561
		if (!User::getCurrent()->isAdmin() && !User::getCurrent()->isCheckuser()) {
562
			BootstrapSkin::displayAccessDenied();
563
            
564
			BootstrapSkin::displayInternalFooter();
565
			die();
566
		}
567
        
568
		if (isset($_POST['submit'])) {
569
			global $baseurl;
570
            
571
			$database = gGetDb();
572
            
573
			$database->transactionally(function() use ($database, $baseurl)
574
			{
575
				$template = new WelcomeTemplate();
576
				$template->setDatabase($database);
577
				$template->setUserCode($_POST['usercode']);
578
				$template->setBotCode($_POST['botcode']);
579
				$template->save();
580
            
581
				Logger::welcomeTemplateCreated($database, $template);
582
                            
583
				Notification::welcomeTemplateCreated($template);
584
            
585
				SessionAlert::success("Template successfully created.");
586
				header("Location: $baseurl/acc.php?action=templatemgmt");
587
			});
588
		}
589
		else {
590
			
591
			if (isset($_POST['preview'])) {
592
				$usercode = $_POST['usercode'];
593
				$botcode = $_POST['botcode'];
594
				echo displayPreview($usercode);
595
			}
596
			else {
597
				$usercode = '';
598
				$botcode = '';
599
			}
600
601
			$smarty->assign("usercode", $usercode);
602
			$smarty->assign("botcode", $botcode);
603
            
604
			$smarty->display("welcometemplate/add.tpl");
605
			BootstrapSkin::displayInternalFooter();
606
			die();
607
		}
608
        
609
		die();
610
	}
611
    
612
	if (isset($_GET['select'])) {
613
		$user = User::getCurrent();
614
        
615
		if ($_GET['select'] == 0) {
616
			$user->setWelcomeTemplate(null);
617
			$user->save();
618
            
619
			SessionAlert::success("Disabled automatic user welcoming.");
620
			header("Location: {$baseurl}/acc.php?action=templatemgmt");
621
			die();
622
		}
623
		else {
624
			$template = WelcomeTemplate::getById($_GET['select'], gGetDb());
625
			if ($template !== false) {
626
				$user->setWelcomeTemplate($template->getId());
627
				$user->save();
628
                
629
				SessionAlert::success("Updated selected welcome template for automatic welcoming.");
630
				header("Location: {$baseurl}/acc.php?action=templatemgmt");
631
				die();
632
			}
633
			else {
634
				SessionAlert::error("Something went wrong, we can't find the template you asked for!");
635
				header("Location: {$baseurl}/acc.php?action=templatemgmt");
636
				die();
637
			}
638
		}
639
	}
640
    
641
	if (isset($_GET['del'])) {
642
		global $baseurl;
643
        
644
		if (!User::getCurrent()->isAdmin() && !User::getCurrent()->isCheckuser()) {
645
			BootstrapSkin::displayAccessDenied();
646
			BootstrapSkin::displayInternalFooter();
647
			die();
648
		}
649
650
		$database = gGetDb();
651
        
652
		$template = WelcomeTemplate::getById($_GET['del'], $database);
653
		if ($template == false) {
654
			SessionAlert::error("Something went wrong, we can't find the template you asked for!");
655
			header("Location: {$baseurl}/acc.php?action=templatemgmt");
656
			die();
657
		}
658
        
659
		$database->transactionally(function() use($database, $template)
660
		{
661
			$tid = $template->getId();
662
            
663
			$database
664
				->prepare("UPDATE user SET welcome_template = NULL WHERE welcome_template = :id;")
665
				->execute(array(":id" => $tid));
666
            
667
			Logger::welcomeTemplateDeleted($database, $template);
668
            
669
			$template->delete();
670
            
671
			SessionAlert::success("Template deleted. Any users who were using this template have had automatic welcoming disabled.");
672
			Notification::welcomeTemplateDeleted($tid);
673
		});
674
        
675
		header("Location: $baseurl/acc.php?action=templatemgmt");
676
		die();			
677
	}
678
    
679
	if (isset($_GET['edit'])) {
680
		if (!User::getCurrent()->isAdmin() && !User::getCurrent()->isCheckuser()) {
681
			BootstrapSkin::displayAccessDenied();
682
			BootstrapSkin::displayInternalFooter();
683
			die();
684
		}
685
686
		$database = gGetDb();
687
        
688
		$template = WelcomeTemplate::getById($_GET['edit'], $database);
689
		if ($template == false) {
690
			SessionAlert::success("Something went wrong, we can't find the template you asked for! Please try again.");
691
			header("Location: {$baseurl}/acc.php?action=templatemgmt");
692
			die();
693
		}
694
695
		if (isset($_POST['submit'])) {
696
			$database->transactionally(function() use($database, $template)
697
			{
698
				$template->setUserCode($_POST['usercode']);
699
				$template->setBotCode($_POST['botcode']);
700
				$template->save();
701
			
702
				Logger::welcomeTemplateEdited($database, $template);
703
                
704
				SessionAlert::success("Template updated.");
705
				Notification::welcomeTemplateEdited($template);
706
			});
707
            
708
			header("Location: $baseurl/acc.php?action=templatemgmt");
709
			die();
710
		}
711
		else {
712
			$smarty->assign("template", $template);
713
			$smarty->display("welcometemplate/edit.tpl");
714
            
715
			BootstrapSkin::displayInternalFooter();
716
			die();
717
		}
718
	}
719
    
720
	$templateList = WelcomeTemplate::getAll();
721
    
722
	$smarty->assign("templatelist", $templateList);
723
	$smarty->display("welcometemplate/list.tpl");
724
    
725
	BootstrapSkin::displayInternalFooter();
726
	die();
727
}
728
elseif ($action == "sban") {
729
	global $smarty;
730
    
731
	// Checks whether the current user is an admin.
732
	if (!User::getCurrent()->isAdmin() && !User::getCurrent()->isCheckuser()) {
733
		BootstrapSkin::displayAccessDenied();
734
		BootstrapSkin::displayInternalFooter();
735
		die();
736
	}
737
	
738
	// Checks whether there is a reason entered for ban.
739
	if (!isset($_POST['banreason']) || $_POST['banreason'] == "") {
740
		BootstrapSkin::displayAlertBox("You must specify a ban reason", "alert-error", "", false, false);
741
		BootstrapSkin::displayInternalFooter();
742
		die();
743
	}
744
	
745
	// Checks whether there is a target entered to ban.
746
	if (!isset($_POST['target']) || $_POST['target'] == "") {
747
		BootstrapSkin::displayAlertBox("You must specify a target to be banned", "alert-error", "", false, false);
748
		BootstrapSkin::displayInternalFooter();
749
		die();
750
	}
751
	
752
	$duration = $_POST['duration'];
753
    
754
	if ($duration == "-1") {
755
		$duration = -1;
756
	}
757
	elseif ($duration == "other") {
758
		$duration = strtotime($_POST['otherduration']);
759
		if (!$duration) {
760
			BootstrapSkin::displayAlertBox("Invalid ban time", "alert-error", "", false, false);
761
			BootstrapSkin::displayInternalFooter();
762
			die();
763
		}
764
		elseif (time() > $duration) {
765
			BootstrapSkin::displayAlertBox("Ban time has already expired!", "alert-error", "", false, false);
766
			BootstrapSkin::displayInternalFooter();
767
			die();
768
		}
769
	}
770
	else {
771
		$duration = $duration + time();
772
	}
773
    
774
	switch ($_POST['type']) {
775
		case 'IP':
776
			if (filter_var($_POST['target'], FILTER_VALIDATE_IP) === false) {
777
				BootstrapSkin::displayAlertBox("Invalid target - IP address expected.", "alert-error", "", false, false);
778
				BootstrapSkin::displayInternalFooter();
779
				die();
780
			}
781
            
782
			global $squidIpList;
783
			if (in_array($_POST['target'], $squidIpList)) {
784
				BootstrapSkin::displayAlertBox(
785
					"This IP address is on the protected list of proxies, and cannot be banned.", 
786
					"alert-error", 
787
					"", 
788
					false, 
789
					false);
790
				BootstrapSkin::displayInternalFooter();
791
				die();
792
			}
793
			break;
794
		case 'Name':
795
			break;
796
		case 'EMail':
797
			// TODO: cut this down to a bare-bones implementation so we don't accidentally reject a valid address.
798
			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'])) {
799
				BootstrapSkin::displayAlertBox(
800
					"Invalid target - email address expected.", 
801
					"alert-error", 
802
					"", 
803
					false, 
804
					false);
805
                
806
				BootstrapSkin::displayInternalFooter();
807
				die();
808
			}
809
			break;
810
		default:
811
			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);
812
			BootstrapSkin::displayInternalFooter();
813
			die();
814
	}
815
        
816
	if (count(Ban::getActiveBans($_POST['target'])) > 0) {
817
		BootstrapSkin::displayAlertBox("This target is already banned!", "alert-error", "", false, false);
818
		BootstrapSkin::displayInternalFooter();
819
		die();
820
	}
821
    
822
	$database = gGetDb();
823
    
824
	$ban = new Ban();
825
    
826
	$currentUsername = User::getCurrent()->getUsername();
827
    
828
	$database->transactionally(function() use ($database, $ban, $duration, $currentUsername)
829
	{
830
		$ban->setDatabase($database);
831
		$ban->setActive(1);
832
		$ban->setType($_POST['type']);
833
		$ban->setTarget($_POST['target']);
834
		$ban->setUser($currentUsername);
835
		$ban->setReason($_POST['banreason']);
836
		$ban->setDuration($duration);
837
    
838
		$ban->save();
839
        
840
		Logger::banned($database, $ban, $_POST['banreason']);
841
	});
842
    
843
	$smarty->assign("ban", $ban);
844
	BootstrapSkin::displayAlertBox($smarty->fetch("bans/bancomplete.tpl"), "alert-info", "", false, false);
845
        
846
	Notification::banned($ban);
847
    
848
	BootstrapSkin::displayInternalFooter();
849
	die();
850
}
851
elseif ($action == "unban") {
852
	global $smarty;
853
    
854
	if (!isset($_GET['id']) || $_GET['id'] == "") {
855
		BootstrapSkin::displayAlertBox(
856
			"The ID parameter appears to be missing! This is probably a bug.", 
857
			"alert-error", 
858
			"Ahoy There! Something's not right...", 
859
			true, 
860
			false);
861
		BootstrapSkin::displayInternalFooter();
862
		die();
863
	}
864
    
865
	if (!User::getCurrent()->isAdmin() && !User::getCurrent()->isCheckuser()) {
866
		BootstrapSkin::displayAccessDenied();
867
		BootstrapSkin::displayInternalFooter();
868
		die();
869
	}
870
    
871
	$ban = Ban::getActiveId($_GET['id']);
872
        
873
	if ($ban == false) {
874
		BootstrapSkin::displayAlertBox(
875
			"The specified ban ID is not currently active or doesn't exist!", 
876
			"alert-error", 
877
			"", 
878
			false, 
879
			false);
880
        
881
		BootstrapSkin::displayInternalFooter();
882
		die();
883
	}
884
885
	if (isset($_GET['confirmunban']) && $_GET['confirmunban'] == "true") {
886
		if (!isset($_POST['unbanreason']) || $_POST['unbanreason'] == "") {
887
			BootstrapSkin::displayAlertBox("You must enter an unban reason!", "alert-error", "", false, false);
888
			BootstrapSkin::displayInternalFooter();
889
			die();
890
		}
891
		else {
892
			$database = gGetDb();
893
            
894
			$database->transactionally(function() use ($database, $ban)
895
			{
896
				$ban->setActive(0);
897
				$ban->save();
898
                
899
				$banId = $ban->getId();
0 ignored issues
show
The assignment to $banId is dead and can be removed.
Loading history...
900
				$currentUser = User::getCurrent()->getUsername();
0 ignored issues
show
The assignment to $currentUser is dead and can be removed.
Loading history...
901
                
902
				Logger::unbanned($database, $ban, $_POST['unbanreason']);
903
			});
904
        
905
			BootstrapSkin::displayAlertBox("Unbanned " . $ban->getTarget(), "alert-info", "", false, false);
906
			BootstrapSkin::displayInternalFooter();
907
			Notification::unbanned($ban, $_POST['unbanreason']);
908
			die();
909
		}
910
	}
911
	else {
912
		$smarty->assign("ban", $ban);
913
		$smarty->display("bans/unban.tpl");
914
        
915
		BootstrapSkin::displayInternalFooter();
916
	}
917
}
918
elseif ($action == "ban") {
919
	global $smarty;
920
    
921
	if (isset ($_GET['ip']) || isset ($_GET['email']) || isset ($_GET['name'])) {
922
		if (!User::getCurrent()->isAdmin() && !User::getCurrent()->isCheckuser()) {
923
			BootstrapSkin::displayAlertBox("Only administrators or checkusers may ban users", "alert-error");
924
			BootstrapSkin::displayInternalFooter();
925
			die();
926
		}
927
        
928
		$database = gGetDb();
929
		// TODO: rewrite me!
930
		if (isset($_GET['ip'])) {
931
			$query = "SELECT ip, forwardedip FROM request WHERE id = :ip;";
932
			$statement = $database->prepare($query);
933
			$statement->bindValue(":ip", $_GET['ip']);
934
			$statement->execute();
935
			$row = $statement->fetch(PDO::FETCH_ASSOC);
936
			$target = getTrustedClientIP($row['ip'], $row['forwardedip']);
937
			$type = "IP";
938
		}
939
		elseif (isset($_GET['email'])) {
940
			$query = "SELECT email FROM request WHERE id = :ip;";
941
			$statement = $database->prepare($query);
942
			$statement->bindValue(":ip", $_GET['email']);
943
			$statement->execute();
944
			$row = $statement->fetch(PDO::FETCH_ASSOC);
945
			$target = $row['email'];
946
			$type = "EMail";
947
		}
948
		elseif (isset($_GET['name'])) {
949
			$query = "SELECT name FROM request WHERE id = :ip;";
950
			$statement = $database->prepare($query);
951
			$statement->bindValue(":ip", $_GET['name']);
952
			$statement->execute();
953
			$row = $statement->fetch(PDO::FETCH_ASSOC);
954
			$target = $row['name'];
955
			$type = "Name";
956
		}
957
		else {
958
			BootstrapSkin::displayAlertBox("Unknown ban type.", "alert-error");
959
			BootstrapSkin::displayInternalFooter();
960
			die();    
961
		}
962
        
963
		if (count(Ban::getActiveBans($target))) {
964
			BootstrapSkin::displayAlertBox("This target is already banned!", "alert-error");
965
			BootstrapSkin::displayInternalFooter();
966
			die();
967
		} 
968
        
969
		$smarty->assign("bantype", $type);
970
		$smarty->assign("bantarget", trim($target));
971
		$smarty->display("bans/banform.tpl");
972
	}
973
	else {
974
		$bans = Ban::getActiveBans();
975
  
976
		$smarty->assign("activebans", $bans);
977
		$smarty->display("bans/banlist.tpl");
978
	}
979
    
980
	BootstrapSkin::displayInternalFooter();
981
	die();
982
}
983
elseif ($action == "defer" && $_GET['id'] != "" && $_GET['sum'] != "") {
984
	global $availableRequestStates;
985
	
986
	if (array_key_exists($_GET['target'], $availableRequestStates)) {
987
		$request = Request::getById($_GET['id'], gGetDb());
988
		
989
		if ($request == false) {
990
			BootstrapSkin::displayAlertBox(
991
				"Could not find the specified request!", 
992
				"alert-error", 
993
				"Error!", 
994
				true, 
995
				false);
996
            
997
			BootstrapSkin::displayInternalFooter();
998
			die();
999
		}
1000
		
1001
		if ($request->getChecksum() != $_GET['sum']) {
1002
			SessionAlert::error(
1003
				"This is similar to an edit conflict on Wikipedia; it means that you have tried to perform an action "
1004
				. "on a request that someone else has performed an action on since you loaded the page",
1005
				"Invalid checksum");
1006
            
1007
			header("Location: acc.php?action=zoom&id={$request->getId()}");
1008
			die();
1009
		}
1010
        
1011
		$sqlText = <<<SQL
1012
SELECT timestamp FROM log
1013
WHERE objectid = :request and objecttype = 'Request' AND action LIKE 'Closed%'
1014
ORDER BY timestamp DESC LIMIT 1;
1015
SQL;
1016
        
1017
		$statement = gGetDb()->prepare($sqlText);
1018
		$statement->execute(array(":request" => $request->getId()));
1019
		$logTime = $statement->fetchColumn();
1020
		$statement->closeCursor();
1021
        
1022
		$date = new DateTime();
1023
		$date->modify("-7 days");
1024
		$oneweek = $date->format("Y-m-d H:i:s");
1025
        
1026
		if ($request->getStatus() == "Closed" 
1027
			&& $logTime < $oneweek 
1028
			&& !User::getCurrent()->isAdmin() 
1029
			&& !User::getCurrent()->isCheckuser()) {
1030
			SessionAlert::error("Only administrators and checkusers can reopen a request that has been closed for over a week.");
1031
			header("Location: acc.php?action=zoom&id={$request->getId()}");
1032
			die();
1033
		}
1034
        
1035
		if ($request->getStatus() == $_GET['target']) {
1036
			SessionAlert::error(
1037
				"Cannot set status, target already deferred to " . htmlentities($_GET['target']), 
1038
				"Error");
1039
			header("Location: acc.php?action=zoom&id={$request->getId()}");
1040
			die();
1041
		}
1042
        
1043
		$database = gGetDb();
1044
		$database->transactionally(function() use ($database, $request)
1045
		{
1046
			global $availableRequestStates;
1047
                
1048
			$request->setReserved(0);
1049
			$request->setStatus($_GET['target']);
1050
			$request->updateChecksum();
1051
			$request->save();
1052
            
1053
			$deto = $availableRequestStates[$_GET['target']]['deferto'];
1054
			$detolog = $availableRequestStates[$_GET['target']]['defertolog'];
1055
            
1056
			Logger::deferRequest($database, $request, $detolog);
1057
        
1058
			Notification::requestDeferred($request);
1059
			SessionAlert::success("Request {$request->getId()} deferred to $deto");
1060
			header("Location: acc.php");
1061
		});
1062
        
1063
		die();
1064
	}
1065
	else {
1066
		BootstrapSkin::displayAlertBox("Defer target not valid.", "alert-error", "Error", true, false);
1067
		BootstrapSkin::displayInternalFooter();
1068
		die();
1069
	}
1070
}
1071
elseif ($action == "prefs") {
1072
	global $smarty, $enforceOAuth;
1073
    
1074
	if (isset ($_POST['sig'])) {
1075
		$user = User::getCurrent();
1076
		$user->setWelcomeSig($_POST['sig']);
1077
		$user->setEmailSig($_POST['emailsig']);
1078
		$user->setAbortPref(isset($_POST['abortpref']) ? 1 : 0);
1079
        
1080
		if (isset($_POST['email'])) {
1081
			$mailisvalid = filter_var(trim($_POST['email']), FILTER_VALIDATE_EMAIL);
1082
            
1083
			if ($mailisvalid === false) {
1084
				BootstrapSkin::displayAlertBox("Invalid email address", "alert-error", "Error!");
1085
			}
1086
			else {
1087
				$user->setEmail(trim($_POST['email']));
1088
			}
1089
		}
1090
1091
		try {
1092
			$user->save();
1093
		}
1094
		catch (PDOException $ex) {
1095
			BootstrapSkin::displayAlertBox($ex->getMessage(), "alert-error", "Error saving Preferences", true, false);
1096
			BootstrapSkin::displayInternalFooter();
1097
			die();
1098
		}
1099
        
1100
		BootstrapSkin::displayAlertBox("Preferences updated!", "alert-info");
1101
	}
1102
    
1103
	$smarty->assign("enforceOAuth", $enforceOAuth);
1104
	$smarty->display("prefs.tpl");
1105
	BootstrapSkin::displayInternalFooter();
1106
	die();
1107
}
1108
elseif ($action == "done" && $_GET['id'] != "") {
1109
	// check for valid close reasons
1110
	global $messages, $baseurl, $smarty;
1111
	
1112
	if (isset($_GET['email'])) {
1113
		if ($_GET['email'] == 0 || $_GET['email'] == "custom") {
1114
			$validEmail = true;
1115
		}
1116
		else {
1117
			$validEmail = EmailTemplate::getById($_GET['email'], gGetDb()) != false;
1118
		}
1119
	}
1120
	else {
1121
		$validEmail = false;
1122
	}
1123
    
1124
	if ($validEmail == false) {
1125
		BootstrapSkin::displayAlertBox("Invalid close reason", "alert-error", "Error", true, false);
1126
		BootstrapSkin::displayInternalFooter();
1127
		die();
1128
	}
1129
	
1130
	// sanitise this input ready for inclusion in queries
1131
	$request = Request::getById($_GET['id'], gGetDb());
1132
    
1133
	if ($request == false) {
1134
		// Notifies the user and stops the script.
1135
		BootstrapSkin::displayAlertBox("The request ID supplied is invalid!", "alert-error", "Error", true, false);
1136
		BootstrapSkin::displayInternalFooter();
1137
		die();
1138
	}
1139
    
1140
	$gem = $_GET['email'];
1141
	
1142
	// check the checksum is valid
1143
	if ($request->getChecksum() != $_GET['sum']) {
1144
		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);
1145
		BootstrapSkin::displayInternalFooter();
1146
		die();
1147
	}
1148
	
1149
	// check if an email has already been sent
1150
	if ($request->getEmailSent() == "1" && !isset($_GET['override']) && $gem != 0) {
1151
		$alertContent = "<p>This request has already been closed in a manner that has generated an e-mail to the user, Proceed?</p><br />";
1152
		$alertContent .= "<div class=\"row-fluid\">";
1153
		$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>";
1154
		$alertContent .= "<a class=\"btn btn-danger span3\" href=\"$baseurl/acc.php\">No</a>";
1155
		$alertContent .= "</div>";
1156
        
1157
		BootstrapSkin::displayAlertBox($alertContent, "alert-info", "Warning!", true, false, false, true);
1158
		BootstrapSkin::displayInternalFooter();
1159
		die();
1160
	}
1161
	
1162
	// check the request is not reserved by someone else
1163
	if ($request->getReserved() != 0 && !isset($_GET['reserveoverride']) && $request->getReserved() != User::getCurrent()->getId()) {
1164
		$alertContent = "<p>This request is currently marked as being handled by " . $request->getReservedObject()->getUsername() . ", Proceed?</p><br />";
1165
		$alertContent .= "<div class=\"row-fluid\">";
1166
		$alertContent .= "<a class=\"btn btn-success offset3 span3\"  href=\"$baseurl/acc.php?" . $_SERVER["QUERY_STRING"] . "&reserveoverride=yes\">Yes</a>";
1167
		$alertContent .= "<a class=\"btn btn-danger span3\" href=\"$baseurl/acc.php\">No</a>";
1168
		$alertContent .= "</div>";
1169
        
1170
		BootstrapSkin::displayAlertBox($alertContent, "alert-info", "Warning!", true, false, false, true);
1171
		BootstrapSkin::displayInternalFooter();
1172
		die();
1173
	}
1174
	    
1175
	if ($request->getStatus() == "Closed") {
1176
		BootstrapSkin::displayAlertBox("Cannot close this request. Already closed.", "alert-error", "Error", true, false);
1177
		BootstrapSkin::displayInternalFooter();
1178
		die();
1179
	}
1180
	
1181
	// Checks whether the username is already in use on Wikipedia.
1182
	$userexist = file_get_contents("http://en.wikipedia.org/w/api.php?action=query&list=users&ususers=" . urlencode($request->getName()) . "&format=php");
1183
	$ue = unserialize($userexist);
1184
	if (!isset ($ue['query']['users']['0']['missing'])) {
1185
		$exists = true;
1186
	}
1187
	else {
1188
		$exists = false;
1189
	}
1190
1191
	/** @var EmailTemplate $emailTemplate */
1192
	$emailTemplate = EmailTemplate::getById($gem, gGetDb());
1193
	if ($emailTemplate instanceof EmailTemplate) {
1194
		$isForCreated = $emailTemplate->getDefaultAction() === EmailTemplate::CREATED;
1195
	} else {
1196
		$isForCreated = false;
1197
	}
1198
1199
	// check if a request being created does not already exist.
1200
	if ($isForCreated && !$exists && !isset($_GET['createoverride'])) {
1201
		$alertContent = "<p>You have chosen to mark this request as \"created\", but the account does not exist on the English Wikipedia, proceed?</p><br />";
1202
		$alertContent .= "<div class=\"row-fluid\">";
1203
		$alertContent .= "<a class=\"btn btn-success offset3 span3\"  href=\"$baseurl/acc.php?" . $_SERVER["QUERY_STRING"] . "&amp;createoverride=yes\">Yes</a>";
1204
		$alertContent .= "<a class=\"btn btn-danger span3\" href=\"$baseurl/acc.php\">No</a>";
1205
		$alertContent .= "</div>";
1206
        
1207
		BootstrapSkin::displayAlertBox($alertContent, "alert-info", "Warning!", true, false, false, true);
1208
		BootstrapSkin::displayInternalFooter();
1209
		die();
1210
	}
1211
	
1212
	$messageBody = null;
1213
    
1214
	// custom close reasons
1215
	if ($gem == 'custom') {
1216
		if (!isset($_POST['msgbody']) or empty($_POST['msgbody'])) {
1217
			// Send it through htmlspecialchars so HTML validators don't complain. 
1218
			$querystring = htmlspecialchars($_SERVER["QUERY_STRING"], ENT_COMPAT, 'UTF-8'); 
1219
            
1220
			$template = false;
1221
			if (isset($_GET['preload'])) {
1222
				$template = EmailTemplate::getById($_GET['preload'], gGetDb());
1223
			}
1224
            
1225
			if ($template != false) {
1226
				$preloadTitle = $template->getName();
1227
				$preloadText = $template->getText();
1228
				$preloadAction = $template->getDefaultAction();
1229
			}
1230
			else {
1231
				$preloadText = "";
1232
				$preloadTitle = "";
1233
				$preloadAction = "";
1234
			}
1235
            
1236
			$smarty->assign("requeststates", $availableRequestStates);
1237
			$smarty->assign("defaultAction", $preloadAction);
1238
			$smarty->assign("preloadtext", $preloadText);
1239
			$smarty->assign("preloadtitle", $preloadTitle);
1240
			$smarty->assign("querystring", $querystring);
1241
			$smarty->assign("request", $request);
1242
			$smarty->assign("iplocation", $locationProvider->getIpLocation($request->getTrustedIp()));
1243
			$smarty->display("custom-close.tpl");
1244
			BootstrapSkin::displayInternalFooter();
1245
			die();
1246
		}
1247
1248
		$headers = 'From: [email protected]' . "\r\n";
1249
1250
		// CC mailing list option
1251
		if (User::getCurrent()->isAdmin() || User::getCurrent()->isCheckuser()) {
1252
			// these people get the choice
1253
			if (isset($_POST['ccmailist']) && $_POST['ccmailist'] == "on") {
1254
				$headers .= 'Cc: [email protected]' . "\r\n";
1255
			}
1256
		} else {
1257
			// these people do not.
1258
			$headers .= 'Cc: [email protected]' . "\r\n";
1259
		}
1260
1261
		$headers .= 'X-ACC-Request: ' . $request->getId() . "\r\n";
1262
		$headers .= 'X-ACC-UserID: ' . User::getCurrent()->getId() . "\r\n";
1263
1264
		// Get the closing user's Email signature and append it to the Email.
1265
		if (User::getCurrent()->getEmailSig() != "") {
1266
			$emailsig = html_entity_decode(User::getCurrent()->getEmailSig(), ENT_QUOTES, "UTF-8");
1267
			mail($request->getEmail(), "RE: [ACC #{$request->getId()}] English Wikipedia Account Request", $_POST['msgbody'] . "\n\n" . $emailsig, $headers);
1268
		}
1269
		else {
1270
			mail($request->getEmail(), "RE: [ACC #{$request->getId()}] English Wikipedia Account Request", $_POST['msgbody'], $headers);
1271
		}
1272
1273
		$request->setEmailSent(1);
1274
		$messageBody = $_POST['msgbody'];
1275
1276
		if ($_POST['action'] == EmailTemplate::CREATED || $_POST['action'] == EmailTemplate::NOT_CREATED) {
1277
			$request->setStatus('Closed');
1278
1279
			if ($_POST['action'] == EmailTemplate::CREATED) {
1280
				$gem  = 'custom-y';
1281
				$crea = "Custom, Created";
1282
			}
1283
			else {
1284
				$gem  = 'custom-n';
1285
				$crea = "Custom, Not Created";
1286
			}
1287
1288
			Logger::closeRequest(gGetDb(), $request, $gem, $messageBody);
1289
			
1290
			Notification::requestClosed($request, $crea);
1291
			BootstrapSkin::displayAlertBox(
1292
				"Request " . $request->getId() . " (" . htmlentities($request->getName(), ENT_COMPAT, 'UTF-8') . ") marked as '" . htmlentities($crea, ENT_COMPAT, 'UTF-8') . "'.", 
1293
				"alert-success");
1294
		}
1295
		else if ($_POST['action'] == "mail") {
1296
			// no action other than send mail!
1297
			Logger::sentMail(gGetDb(), $request, $messageBody);
1298
			Logger::unreserve(gGetDb(), $request);
1299
1300
			Notification::sentMail($request);
1301
			BootstrapSkin::displayAlertBox("Sent mail to Request {$request->getId()}", 
1302
				"alert-success");
1303
		}
1304
		else if (array_key_exists($_POST['action'], $availableRequestStates)) {
1305
			// Defer
1306
1307
			$request->setStatus($_POST['action']);
1308
			$deto = $availableRequestStates[$_POST['action']]['deferto'];
1309
			$detolog = $availableRequestStates[$_POST['action']]['defertolog'];
1310
1311
			Logger::sentMail(gGetDb(), $request, $messageBody);
1312
			Logger::deferRequest(gGetDb(), $request, $detolog);
1313
			
1314
			Notification::requestDeferredWithMail($request);
1315
			BootstrapSkin::displayAlertBox("Request {$request->getId()} deferred to $deto, sending an email.", 
1316
				"alert-success");
1317
		}
1318
		else {
1319
			// hmm. not sure what happened. Log that we sent the mail anyway.
1320
			Logger::sentMail(gGetDb(), $request, $messageBody);
1321
			Logger::unreserve(gGetDb(), $request);
1322
1323
			Notification::sentMail($request);
1324
			BootstrapSkin::displayAlertBox("Sent mail to Request {$request->getId()}", 
1325
				"alert-success");
1326
		}
1327
1328
		$request->setReserved(0);
1329
		$request->save();
1330
		
1331
		$request->updateChecksum();
1332
		$request->save();
1333
1334
		echo defaultpage();
1335
		BootstrapSkin::displayInternalFooter();
1336
		die();		
1337
	}
1338
	else {
1339
		// Not a custom close, just a normal close
1340
	    
1341
		$request->setStatus('Closed');
1342
		$request->setReserved(0);
1343
		
1344
		// TODO: make this transactional
1345
		$request->save();
1346
		
1347
		Logger::closeRequest(gGetDb(), $request, $gem, $messageBody);
1348
		
1349
		if ($gem == '0') {
1350
			$crea = "Dropped";
1351
		}
1352
		else {
1353
			$template = EmailTemplate::getById($gem, gGetDb());
1354
			$crea = $template->getName();
1355
		}
1356
1357
		Notification::requestClosed($request, $crea);
1358
		BootstrapSkin::displayAlertBox("Request " . $request->getId() . " (" . htmlentities($request->getName(), ENT_COMPAT, 'UTF-8') . ") marked as '" . htmlentities($crea, ENT_COMPAT, 'UTF-8') . "'.", "alert-success");
1359
		
1360
		$towhom = $request->getEmail();
1361
		if ($gem != "0") {
1362
			sendemail($gem, $towhom, $request->getId());
1363
			$request->setEmailSent(1);
1364
		}
1365
		
1366
		$request->updateChecksum();
1367
		$request->save();
1368
		
1369
		echo defaultpage();
1370
		BootstrapSkin::displayInternalFooter();
1371
		die();
1372
	}
1373
}
1374
elseif ($action == "zoom") {
1375
	if (!isset($_GET['id'])) {
1376
		BootstrapSkin::displayAlertBox("No request specified!", "alert-error", "Error!", true, false);
1377
		BootstrapSkin::displayInternalFooter();
1378
		die();
1379
	}
1380
    
1381
	if (isset($_GET['hash'])) {
1382
		$urlhash = $_GET['hash'];
1383
	}
1384
	else {
1385
		$urlhash = "";
1386
	}
1387
	echo zoomPage($_GET['id'], $urlhash);
1388
1389
	$tailscript = getTypeaheadSource(User::getAllUsernames(gGetDb()));
1390
	BootstrapSkin::displayInternalFooter($tailscript);
1391
	die();
1392
}
1393
elseif ($action == "logs") {
1394
	global $baseurl;
1395
	
1396
	$filterUser = isset($_GET['filterUser']) && $_GET['filterUser'] != "" ? $_GET['filterUser'] : false;
1397
	$filterAction = isset($_GET['filterAction']) && $_GET['filterAction'] != "" ? $_GET['filterAction'] : false;
1398
	
1399
	$limit = 100;
1400
	if (isset($_GET['limit'])) {
1401
		$limit = (int)$_GET['limit'];
1402
	}
1403
	
1404
	$offset = 0;
1405
	$page = 1;
1406
	if (isset($_GET['page'])) {
1407
		$page = (int)$_GET['page'];
1408
		$offset = ($page - 1) * $limit;
1409
	}
1410
	
1411
	$logs = Logger::getLogs($filterUser, $filterAction, $limit, $offset);
1412
	if ($logs === false) {
1413
		$smarty->assign("logs", array());
1414
		$smarty->display("logs/main.tpl");
1415
		BootstrapSkin::displayInternalFooter();
1416
		die();
1417
	}
1418
	
1419
	$count = $logs['count'];
1420
	unset($logs['count']);
1421
	
1422
	// The number of pages on the pager to show. Must be odd
1423
	$pageLimit = 9;
1424
	
1425
	$pageData = array( 
1426
		'canprev' => $page != 1,
1427
		'cannext' => ($page * $limit) < $count,
1428
		'maxpage' => ceil($count / $limit),
1429
		'pagelimit' => $pageLimit,
1430
	);
1431
	
1432
	$pageMargin = (($pageLimit - 1) / 2);
1433
	$pageData['lowpage'] = max(1, $page - $pageMargin);
1434
	$pageData['hipage'] = min($pageData['maxpage'], $page + $pageMargin);
1435
	
1436
	$pageCount = ($pageData['hipage'] - $pageData['lowpage']) + 1;
1437
	
1438
	if ($pageCount < $pageLimit) {
1439
		if ($pageData['lowpage'] == 1 && $pageData['hipage'] == $pageData['maxpage']) {
1440
			// nothing to do, we're already at max range.	
1441
		}
1442
		elseif ($pageData['lowpage'] == 1 && $pageData['hipage'] < $pageData['maxpage']) {
1443
			$pageData['hipage'] = min($pageLimit, $pageData['maxpage']);
1444
		}
1445
		elseif ($pageData['lowpage'] > 1 && $pageData['hipage'] == $pageData['maxpage']) {
1446
			$pageData['lowpage'] = max(1, $pageData['maxpage'] - $pageLimit + 1);
1447
		}
1448
	}
1449
	
1450
	$pageData['pages'] = range($pageData['lowpage'], $pageData['hipage']);
1451
		
1452
	$smarty->assign("pagedata", $pageData);
1453
	
1454
	$smarty->assign("limit", $limit);
1455
	$smarty->assign("page", $page);
1456
1457
	$smarty->assign("logs", $logs);
1458
	
1459
	
1460
	$smarty->assign("filterUser", $filterUser);
1461
	$smarty->assign("filterAction", $filterAction);
1462
	$smarty->display("logs/main.tpl");
1463
1464
	$tailscript = getTypeaheadSource(User::getAllUsernames(gGetDb(), true));
1465
	
1466
	BootstrapSkin::displayInternalFooter($tailscript);
1467
	die();
1468
}
1469
elseif ($action == "reserve") {
1470
	$database = gGetDb();
1471
    
1472
	$database->transactionally(function() use ($database)
1473
	{
1474
		$request = Request::getById($_GET['resid'], $database);
1475
        
1476
		if ($request == false) {
1477
			throw new TransactionException("Request not found", "Error");
1478
		}
1479
        
1480
		global $enableEmailConfirm, $baseurl;
1481
		if ($enableEmailConfirm == 1) {
1482
			if ($request->getEmailConfirm() != "Confirmed") {
0 ignored issues
show
The method getEmailConfirm() does not exist on DataObject. It seems like you code against a sub-type of DataObject such as Request. ( Ignorable by Annotation )

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

1482
			if ($request->/** @scrutinizer ignore-call */ getEmailConfirm() != "Confirmed") {
Loading history...
1483
				throw new TransactionException("Email address not yet confirmed for this request.", "Error");
1484
			}
1485
		}
1486
1487
		$logQuery = $database->prepare(<<<SQL
1488
SELECT timestamp FROM log
1489
WHERE objectid = :request AND objecttype = 'Request' AND action LIKE 'Closed%'
1490
ORDER BY timestamp DESC LIMIT 1;
1491
SQL
1492
		);
1493
		$logQuery->bindValue(":request", $request->getId());
1494
		$logQuery->execute();
1495
		$logTime = $logQuery->fetchColumn();
1496
		$logQuery->closeCursor();
1497
        
1498
		$date = new DateTime();
1499
		$date->modify("-7 days");
1500
		$oneweek = $date->format("Y-m-d H:i:s");
1501
        
1502
		if ($request->getStatus() == "Closed" && $logTime < $oneweek && !User::getCurrent($database)->isAdmin()) {
0 ignored issues
show
The method getStatus() does not exist on DataObject. It seems like you code against a sub-type of DataObject such as User or Request. ( Ignorable by Annotation )

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

1502
		if ($request->/** @scrutinizer ignore-call */ getStatus() == "Closed" && $logTime < $oneweek && !User::getCurrent($database)->isAdmin()) {
Loading history...
1503
			throw new TransactionException("Only administrators and checkusers can reserve a request that has been closed for over a week.", "Error");
1504
		}
1505
        
1506
	   	if ($request->getReserved() != 0 && $request->getReserved() != User::getCurrent($database)->getId()) {
0 ignored issues
show
The method getReserved() does not exist on DataObject. It seems like you code against a sub-type of DataObject such as Request. ( Ignorable by Annotation )

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

1506
	   	if ($request->/** @scrutinizer ignore-call */ getReserved() != 0 && $request->getReserved() != User::getCurrent($database)->getId()) {
Loading history...
1507
			throw new TransactionException("Request is already reserved by {$request->getReservedObject()->getUsername()}.", "Error");
0 ignored issues
show
The method getReservedObject() does not exist on DataObject. It seems like you code against a sub-type of DataObject such as Request. ( Ignorable by Annotation )

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

1507
			throw new TransactionException("Request is already reserved by {$request->/** @scrutinizer ignore-call */ getReservedObject()->getUsername()}.", "Error");
Loading history...
1508
		}
1509
           
1510
		if ($request->getReserved() == 0) {
1511
			// Check the number of requests a user has reserved already
1512
			$doubleReserveCountQuery = $database->prepare("SELECT COUNT(*) FROM request WHERE reserved = :userid;");
1513
			$doubleReserveCountQuery->bindValue(":userid", User::getCurrent($database)->getId());
1514
			$doubleReserveCountQuery->execute();
1515
			$doubleReserveCount = $doubleReserveCountQuery->fetchColumn();
1516
			$doubleReserveCountQuery->closeCursor();
1517
1518
			// User already has at least one reserved. 
1519
			if ($doubleReserveCount != 0) {
1520
				SessionAlert::warning("You have multiple requests reserved!");
1521
			}
1522
1523
			// Is the request closed?
1524
			if (!isset($_GET['confclosed'])) {
1525
				if ($request->getStatus() == "Closed") {
1526
					// FIXME: bootstrappify properly
1527
					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");
1528
				}
1529
			}	
1530
        
1531
			$request->setReserved(User::getCurrent($database)->getId());
0 ignored issues
show
The method setReserved() does not exist on DataObject. It seems like you code against a sub-type of DataObject such as Request. ( Ignorable by Annotation )

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

1531
			$request->/** @scrutinizer ignore-call */ 
1532
             setReserved(User::getCurrent($database)->getId());
Loading history...
1532
			$request->save();
1533
	
1534
			Logger::reserve($database, $request);
1535
                
1536
			Notification::requestReserved($request);
1537
                
1538
			SessionAlert::success("Reserved request {$request->getId()}.");
1539
		}
1540
        
1541
		header("Location: $baseurl/acc.php?action=zoom&id={$request->getId()}");
1542
	});
1543
	    
1544
	die();	
1545
}
1546
elseif ($action == "breakreserve") {
1547
	global $smarty;
1548
    
1549
	$database = gGetDb();
1550
    
1551
	$request = Request::getById($_GET['resid'], $database);
1552
        
1553
	if ($request == false) {
1554
		BootstrapSkin::displayAlertBox("Could not find request.", "alert-error", "Error", true, false);
1555
		BootstrapSkin::displayInternalFooter();
1556
		die();
1557
	}
1558
    
1559
	if ($request->getReserved() == 0) {
1560
		BootstrapSkin::displayAlertBox("Request is not reserved.", "alert-error", "Error", true, false);
1561
		BootstrapSkin::displayInternalFooter();
1562
		die();
1563
	}
1564
    
1565
	$reservedUser = $request->getReservedObject();
1566
    
1567
	if ($reservedUser == false) {
1568
		BootstrapSkin::displayAlertBox("Could not find user who reserved the request (!!).", "alert-error", "Error", true, false);
1569
		BootstrapSkin::displayInternalFooter();
1570
		die();
1571
	}
1572
    
1573
	if ($reservedUser->getId() != User::getCurrent()->getId()) {
1574
		if (User::getCurrent()->isAdmin()) {
1575
			if (isset($_GET['confirm']) && $_GET['confirm'] == 1) {
1576
				$database->transactionally(function() use($database, $request)
1577
				{
1578
					$request->setReserved(0);
1579
					$request->save();
1580
1581
					Logger::breakReserve($database, $request);
1582
                
1583
					Notification::requestReserveBroken($request);
1584
					header("Location: acc.php");
1585
				});
1586
                
1587
				die();
1588
			}
1589
			else {
1590
				global $baseurl;
1591
				$smarty->assign("reservedUser", $reservedUser);
1592
				$smarty->assign("request", $request);
1593
                
1594
				$smarty->display("confirmations/breakreserve.tpl");
1595
			}
1596
		}
1597
		else {
1598
			echo "You cannot break " . htmlentities($reservedUser->getUsername()) . "'s reservation";
1599
		}
1600
	}
1601
	else {
1602
		$database->transactionally(function() use ($database, $request)
1603
		{
1604
			$request->setReserved(0);
1605
			$request->save();
1606
1607
			Logger::unreserve($database, $request);
1608
        
1609
			Notification::requestUnreserved($request);
1610
			header("Location: acc.php");
1611
		});
1612
        
1613
		die();
1614
	}
1615
    
1616
	BootstrapSkin::displayInternalFooter();
1617
	die();		
1618
}
1619
elseif ($action == "comment") {
1620
	global $smarty;
1621
    
1622
	$request = Request::getById($_GET['id'], gGetDb());
1623
	$smarty->assign("request", $request);
1624
	$smarty->display("commentform.tpl");
1625
	BootstrapSkin::displayInternalFooter();
1626
	die();
1627
}
1628
elseif ($action == "comment-add") {
1629
	global $baseurl, $smarty;
1630
    
1631
	$request = Request::getById($_POST['id'], gGetDb());
1632
	if ($request == false) {
1633
		BootstrapSkin::displayAlertBox("Could not find request!", "alert-error", "Error", true, false);
1634
		BootstrapSkin::displayInternalFooter();
1635
		die();
1636
	}
1637
    
1638
	if (!isset($_POST['comment']) || $_POST['comment'] == "") {
1639
		BootstrapSkin::displayAlertBox("Comment must be supplied!", "alert-error", "Error", true, false);
1640
		BootstrapSkin::displayInternalFooter();
1641
		die(); 
1642
	}
1643
    
1644
	$visibility = 'user';
1645
	if (isset($_POST['visibility'])) {
1646
		// sanity check
1647
		$visibility = $_POST['visibility'] == 'user' ? 'user' : 'admin';
1648
	}
1649
    
1650
	//Look for and detect IPv4/IPv6 addresses in comment text, and warn the commenter.
1651
	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") {
1652
			BootstrapSkin::displayAlertBox("IP address detected in comment text.  Warning acknowledgement checkbox must be checked.", "alert-error", "Error", true, false);
1653
			$smarty->assign("request", $request);
1654
			$smarty->assign("comment", $_POST['comment']);
1655
			$smarty->assign("actionLocation", "comment-add");
1656
			$smarty->display("privpol-warning.tpl");
1657
			BootstrapSkin::displayInternalFooter();
1658
			die();
1659
		}
1660
    
1661
	$comment = new Comment();
1662
	$comment->setDatabase(gGetDb());
1663
    
1664
	$comment->setRequest($request->getId());
1665
	$comment->setVisibility($visibility);
1666
	$comment->setUser(User::getCurrent()->getId());
1667
	$comment->setComment($_POST['comment']);
1668
    
1669
	$comment->save();
1670
    
1671
	if (isset($_GET['hash'])) {
1672
		$urlhash = urlencode(htmlentities($_GET['hash']));
1673
	}
1674
	else {
1675
		$urlhash = "";
1676
	}
1677
1678
	BootstrapSkin::displayAlertBox(
1679
		"<a href='$baseurl/acc.php?action=zoom&amp;id={$request->getId()}&amp;hash=$urlhash'>Return to request #{$request->getId()}</a>",
1680
		"alert-success",
1681
		"Comment added Successfully!",
1682
		true, false);
1683
        
1684
	Notification::commentCreated($comment);
1685
        
1686
	BootstrapSkin::displayInternalFooter();
1687
	die();
1688
}
1689
elseif ($action == "comment-quick") {
1690
	$request = Request::getById($_POST['id'], gGetDb());
1691
	if ($request == false) {
1692
		BootstrapSkin::displayAlertBox("Could not find request!", "alert-error", "Error", true, false);
1693
		BootstrapSkin::displayInternalFooter();
1694
		die();
1695
	}
1696
    
1697
	if (!isset($_POST['comment']) || $_POST['comment'] == "") {
1698
		header("Location: acc.php?action=zoom&id=" . $request->getId());
1699
		die(); 
1700
	}
1701
    
1702
	$visibility = 'user';
1703
	if (isset($_POST['visibility'])) {
1704
		// sanity check
1705
		$visibility = $_POST['visibility'] == 'user' ? 'user' : 'admin';
1706
	}
1707
1708
	//Look for and detect IPv4/IPv6 addresses in comment text, and warn the commenter.
1709
	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") {
1710
			BootstrapSkin::displayAlertBox("IP address detected in comment text.  Warning acknowledgement checkbox must be checked.", "alert-error", "Error", true, false);
1711
			$smarty->assign("request", $request);
1712
			$smarty->assign("comment", $_POST['comment']);
1713
			$smarty->assign("actionLocation", "comment-quick");
1714
			$smarty->display("privpol-warning.tpl");
1715
			BootstrapSkin::displayInternalFooter();
1716
			die();
1717
		}
1718
    
1719
	$comment = new Comment();
1720
	$comment->setDatabase(gGetDb());
1721
    
1722
	$comment->setRequest($request->getId());
1723
	$comment->setVisibility($visibility);
1724
	$comment->setUser(User::getCurrent()->getId());
1725
	$comment->setComment($_POST['comment']);
1726
    
1727
	$comment->save();
1728
    
1729
	Notification::commentCreated($comment);
1730
    
1731
	header("Location: acc.php?action=zoom&id=" . $request->getId());
1732
}
1733
elseif ($action == "changepassword") {
1734
	if ((!isset($_POST['oldpassword'])) || $_POST['oldpassword'] == "") {
1735
		//Throw an error if old password is not specified.
1736
		BootstrapSkin::displayAlertBox("You did not enter your old password.", "alert-error", "Error", true, false);
1737
		BootstrapSkin::displayInternalFooter();
1738
		die();
1739
	}
1740
	
1741
	if ((!isset($_POST['newpassword'])) || $_POST['newpassword'] == "") {
1742
		//Throw an error if new password is not specified.
1743
		BootstrapSkin::displayAlertBox("You did not enter your new password.", "alert-error", "Error", true, false);
1744
		BootstrapSkin::displayInternalFooter();
1745
		die();
1746
	}
1747
	
1748
	if ($_POST['newpassword'] != $_POST['newpasswordconfirm']) {
1749
		//Throw an error if new password does not match what is in the confirmation box.
1750
		BootstrapSkin::displayAlertBox("The 2 new passwords you entered do not match.", "alert-error", "Error", true, false);
1751
		BootstrapSkin::displayInternalFooter();
1752
		die();
1753
	}
1754
    
1755
	$user = User::getCurrent();
1756
	   
1757
	if (!$user->authenticate($_POST['oldpassword'])) {
1758
		//Throw an error if the old password field's value does not match the user's current password.
1759
		BootstrapSkin::displayAlertBox("The old password you entered is not correct.", "alert-error", "Error", true, false);
1760
		BootstrapSkin::displayInternalFooter();
1761
		die();
1762
	}
1763
    
1764
	$user->setPassword($_POST['newpassword']);
1765
	$user->save();
1766
    
1767
	BootstrapSkin::displayAlertBox("Password successfully changed!", "alert-success", "", false, false);
1768
	BootstrapSkin::displayInternalFooter();
1769
	die();
1770
}
1771
elseif ($action == "ec") {
1772
	// edit comment
1773
  
1774
	global $smarty, $baseurl;
1775
    
1776
	$comment = Comment::getById($_GET['id'], gGetDb());
1777
    
1778
	if ($comment == false) {
1779
		// Only using die("Message"); for errors looks ugly.
1780
		BootstrapSkin::displayAlertBox("Comment not found.", "alert-error", "Error", true, false);
1781
		BootstrapSkin::displayInternalFooter();
1782
		die();
1783
	}
1784
	
1785
	// Unauthorized if user is not an admin or the user who made the comment being edited.
1786
	if (!User::getCurrent()->isAdmin() && !User::getCurrent()->isCheckuser() && $comment->getUser() != User::getCurrent()->getId()) {
1787
		BootstrapSkin::displayAccessDenied();
1788
		BootstrapSkin::displayInternalFooter();
1789
		die();
1790
	}
1791
	
1792
	// get[id] is safe by this point.
1793
	
1794
	if ($_SERVER['REQUEST_METHOD'] == 'POST') {
1795
		$database = gGetDb();
1796
		$database->transactionally(function() use ($database, $comment, $baseurl)
1797
		{
1798
            
1799
			$comment->setComment($_POST['newcomment']);
1800
			$comment->setVisibility($_POST['visibility']);
1801
        
1802
			$comment->save();
1803
        
1804
			Logger::editComment($database, $comment);
1805
        
1806
			Notification::commentEdited($comment);
1807
        
1808
			SessionAlert::success("Comment has been saved successfully");
1809
			header("Location: $baseurl/acc.php?action=zoom&id=" . $comment->getRequest());
1810
		});
1811
        
1812
		die();    
1813
	}
1814
	else {
1815
		$smarty->assign("comment", $comment);
1816
		$smarty->display("edit-comment.tpl");
1817
		BootstrapSkin::displayInternalFooter();
1818
		die();
1819
	}
1820
}
1821
elseif ($action == "sendtouser") {
1822
	global $baseurl;
1823
    
1824
	$database = gGetDb();
1825
1826
	/** @var Request $requestObject */
1827
	$requestObject = Request::getById($_POST['id'], $database);
1828
	if ($requestObject == false) {
1829
		BootstrapSkin::displayAlertBox("Request invalid", "alert-error", "Could not find request", true, false);
1830
		BootstrapSkin::displayInternalFooter();
1831
		die();
1832
	}
1833
    
1834
	$request = $requestObject->getId();
1835
    
1836
	$user = User::getByUsername($_POST['user'], $database);
1837
	$curuser = User::getCurrent()->getUsername();
1838
    
1839
	if ($user == false) {
1840
		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);
1841
		BootstrapSkin::displayInternalFooter();
1842
		die();
1843
	}
1844
    
1845
	$database->transactionally(function() use ($database, $user, $requestObject, $curuser)
0 ignored issues
show
The import $curuser is not used and could be removed.

This check looks for imports that have been defined, but are not used in the scope.

Loading history...
1846
	{
1847
		$updateStatement = $database->prepare("UPDATE request SET reserved = :userid WHERE id = :request;");
1848
		$updateStatement->bindValue(":userid", $user->getId());
1849
		$updateStatement->bindValue(":request", $requestObject->getId());
1850
		if (!$updateStatement->execute()) {
1851
			throw new TransactionException("Error updating reserved status of request.");   
1852
		}
1853
        
1854
		Logger::sendReservation($database, $requestObject, $user);
1855
	});
1856
    
1857
	Notification::requestReservationSent($requestObject, $user);
1858
	SessionAlert::success("Reservation sent successfully");
1859
	header("Location: $baseurl/acc.php?action=zoom&id=$request");
1860
}
1861
elseif ($action == "emailmgmt") {
1862
	global $smarty, $createdid, $availableRequestStates;
1863
    
1864
	/* New page for managing Emails, since I would rather not be handling editing
1865
	interface messages (such as the Sitenotice) and the new Emails in the same place. */
1866
	if (isset($_GET['create'])) {
1867
		if (!User::getCurrent()->isAdmin()) {
1868
			BootstrapSkin::displayAccessDenied();
1869
			BootstrapSkin::displayInternalFooter();
1870
			die();
1871
		}
1872
		if (isset($_POST['submit'])) {
1873
			$database = gGetDb();
1874
			$database->transactionally(function() use ($database)
1875
			{
1876
				global $baseurl;
1877
                
1878
				$emailTemplate = new EmailTemplate();
1879
				$emailTemplate->setDatabase($database);
1880
            
1881
				$emailTemplate->setName($_POST['name']);
1882
				$emailTemplate->setText($_POST['text']);
1883
				$emailTemplate->setJsquestion($_POST['jsquestion']);
1884
				$emailTemplate->setDefaultAction($_POST['defaultaction']);
1885
				$emailTemplate->setActive(isset($_POST['active']));
1886
1887
				// Check if the entered name already exists (since these names are going to be used as the labels for buttons on the zoom page).
1888
				// getByName(...) returns false on no records found.
1889
				if (EmailTemplate::getByName($_POST['name'], $database)) {
1890
					throw new TransactionException("That Email template name is already being used. Please choose another.");
1891
				}
1892
			
1893
				$emailTemplate->save();
1894
                
1895
				Logger::createEmail($database, $emailTemplate);
1896
                
1897
				Notification::emailCreated($emailTemplate);
1898
                
1899
				SessionAlert::success("Email template has been saved successfully.");
1900
				header("Location: $baseurl/acc.php?action=emailmgmt");
1901
			});
1902
            
1903
			die();
1904
		}
1905
        
1906
		$smarty->assign('id', null);
1907
		$smarty->assign('createdid', $createdid);
1908
		$smarty->assign('requeststates', $availableRequestStates);
1909
		$smarty->assign('emailTemplate', new EmailTemplate());
1910
		$smarty->assign('emailmgmtpage', 'Create'); //Use a variable so we don't need two Smarty templates for creating and editing.
1911
		$smarty->display("email-management/edit.tpl");
1912
		BootstrapSkin::displayInternalFooter();
1913
		die();
1914
	}
1915
	if (isset($_GET['edit'])) {
1916
		global $createdid;
1917
        
1918
		$database = gGetDb();
1919
        
1920
		if (isset($_POST['submit'])) {
1921
			$emailTemplate = EmailTemplate::getById($_GET['edit'], $database);
1922
			// Allow the user to see the edit form (with read only fields) but not POST anything.
1923
			if (!User::getCurrent()->isAdmin()) {
1924
				BootstrapSkin::displayAccessDenied();
1925
				BootstrapSkin::displayInternalFooter();
1926
				die();
1927
			}
1928
            
1929
			$emailTemplate->setName($_POST['name']);
1930
			$emailTemplate->setText($_POST['text']);
1931
			$emailTemplate->setJsquestion($_POST['jsquestion']);
1932
			
1933
			if ($_GET['edit'] == $createdid) {
1934
				// Both checkboxes on the main created message should always be enabled.
1935
				$emailTemplate->setDefaultAction(EmailTemplate::CREATED);
1936
				$emailTemplate->setActive(1);
1937
				$emailTemplate->setPreloadOnly(0);
1938
			}
1939
			else {
1940
				$emailTemplate->setDefaultAction($_POST['defaultaction']);
1941
				$emailTemplate->setActive(isset($_POST['active']));
1942
				$emailTemplate->setPreloadOnly(isset($_POST['preloadonly']));
1943
			}
1944
				
1945
			// Check if the entered name already exists (since these names are going to be used as the labels for buttons on the zoom page).
1946
			$nameCheck = EmailTemplate::getByName($_POST['name'], gGetDb());
1947
			if ($nameCheck != false && $nameCheck->getId() != $_GET['edit']) {
1948
				BootstrapSkin::displayAlertBox("That Email template name is already being used. Please choose another.");
1949
				BootstrapSkin::displayInternalFooter();
1950
				die();
1951
			}
1952
1953
			$database->transactionally(function() use ($database, $emailTemplate)
1954
			{
1955
				$emailTemplate->save();
1956
                
1957
				Logger::editedEmail($database, $emailTemplate);
1958
            
1959
				global $baseurl;
1960
                
1961
				Notification::emailEdited($emailTemplate);
1962
				SessionAlert::success("Email template has been saved successfully.");
1963
				header("Location: $baseurl/acc.php?action=emailmgmt");
1964
			});
1965
            
1966
			die();
1967
		}
1968
        
1969
		$emailTemplate = EmailTemplate::getById($_GET['edit'], gGetDb());
1970
		$smarty->assign('id', $emailTemplate->getId());
1971
		$smarty->assign('emailTemplate', $emailTemplate);
1972
		$smarty->assign('createdid', $createdid);
1973
		$smarty->assign('requeststates', $availableRequestStates);
1974
		$smarty->assign('emailmgmtpage', 'Edit'); // Use a variable so we don't need two Smarty templates for creating and editing.
1975
		$smarty->display("email-management/edit.tpl");
1976
		BootstrapSkin::displayInternalFooter();
1977
		die();
1978
	}
1979
    
1980
	$query = "SELECT * FROM emailtemplate WHERE active = 1";
1981
	$statement = gGetDb()->prepare($query);
1982
	$statement->execute();
1983
	$rows = $statement->fetchAll(PDO::FETCH_CLASS, "EmailTemplate");
1984
	$smarty->assign('activeemails', $rows);
1985
        
1986
	$query = "SELECT * FROM emailtemplate WHERE active = 0";
1987
	$statement = gGetDb()->prepare($query);
1988
	$statement->execute();
1989
	$inactiverows = $statement->fetchAll(PDO::FETCH_CLASS, "EmailTemplate");
1990
	$smarty->assign('inactiveemails', $inactiverows);
1991
 
1992
	if (count($inactiverows) > 0) {
1993
		$smarty->assign('displayinactive', true);
1994
	}
1995
	else {
1996
		$smarty->assign('displayinactive', false);
1997
	}
1998
    
1999
	$smarty->display("email-management/main.tpl");
2000
	BootstrapSkin::displayInternalFooter();
2001
	die();
2002
}
2003
elseif ($action == "oauthdetach") {
2004
	if ($enforceOAuth) {
2005
		BootstrapSkin::displayAccessDenied();
2006
		BootstrapSkin::displayInternalFooter();
2007
		die();
2008
	}
2009
    
2010
	global $baseurl;
2011
        
2012
	$currentUser = User::getCurrent();
2013
	$currentUser->detachAccount();
2014
        
2015
	header("Location: {$baseurl}/acc.php?action=logout");
2016
}
2017
elseif ($action == "oauthattach") {
2018
	$database = gGetDb();
2019
	$database->transactionally(function() use ($database)
0 ignored issues
show
The import $database is not used and could be removed.

This check looks for imports that have been defined, but are not used in the scope.

Loading history...
2020
	{
2021
		try {
2022
			global $oauthConsumerToken, $oauthSecretToken, $oauthBaseUrl, $oauthBaseUrlInternal;
2023
            
2024
			$user = User::getCurrent();
2025
            
2026
			// Get a request token for OAuth
2027
			$util = new OAuthUtility($oauthConsumerToken, $oauthSecretToken, $oauthBaseUrl, $oauthBaseUrlInternal);
2028
			$requestToken = $util->getRequestToken();
2029
2030
			// save the request token for later
2031
			$user->setOAuthRequestToken($requestToken->key);
2032
			$user->setOAuthRequestSecret($requestToken->secret);
2033
			$user->save();
2034
        
2035
			$redirectUrl = $util->getAuthoriseUrl($requestToken);
2036
        
2037
			header("Location: {$redirectUrl}");
2038
        
2039
		}
2040
		catch (Exception $ex) {
2041
			throw new TransactionException($ex->getMessage(), "Connection to Wikipedia failed.", "alert-error", 0, $ex);
2042
		}
2043
	});
2044
}
2045
elseif ($action == "listall") {
2046
    global $availableRequestStates, $enableEmailConfirm;
2047
2048
	if (isset($_GET['status']) && isset($availableRequestStates[$_GET['status']])) {
2049
		$type = $_GET['status']; // safe, we've verified it's sane in the above if statement.
2050
2051
	    $database = gGetDb();
2052
2053
	    if ($enableEmailConfirm == 1) {
2054
	        $query = "SELECT * FROM request WHERE status = :type AND emailconfirm = 'Confirmed';";
2055
	    } else {
2056
	        $query = "SELECT * FROM request WHERE status = :type;";
2057
	    }
2058
2059
	    $statement = $database->prepare($query);
2060
2061
        $statement->bindValue(":type", $type);
2062
        $statement->execute();
2063
2064
        $requests = $statement->fetchAll(PDO::FETCH_CLASS, "Request");
2065
        foreach ($requests as $req) {
2066
        	/** @var Request $req */
2067
            $req->setDatabase($database);
2068
        }
2069
2070
        global $smarty;
2071
        $smarty->assign("requests", $requests);
2072
        $smarty->assign("showStatus", false);
2073
        $html = $smarty->fetch("mainpage/requesttable.tpl");
2074
        echo $html;
2075
    } else {
2076
        echo defaultpage();
2077
    }
2078
2079
    BootstrapSkin::displayInternalFooter();
2080
    die();
2081
}
2082
# If the action specified does not exist, goto the default page.
2083
else {
2084
	echo defaultpage();
2085
	BootstrapSkin::displayInternalFooter();
2086
	die();
2087
}
2088