Passed
Push — dependabot/submodules/lib/medi... ( 354b47 )
by
unknown
03:13
created

anonymous()

Size

Total Lines 49
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

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

505
				$message->/** @scrutinizer ignore-call */ 
506
              setContent($_POST['mailtext']);
Loading history...
506
				$message->setDescription($_POST['maildesc']);
0 ignored issues
show
Bug introduced by
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

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

1492
			if ($request->/** @scrutinizer ignore-call */ getEmailConfirm() != "Confirmed") {
Loading history...
1493
				throw new TransactionException("Email address not yet confirmed for this request.", "Error");
1494
			}
1495
		}
1496
1497
		$logQuery = $database->prepare(<<<SQL
1498
SELECT timestamp FROM log
1499
WHERE objectid = :request AND objecttype = 'Request' AND action LIKE 'Closed%'
1500
ORDER BY timestamp DESC LIMIT 1;
1501
SQL
1502
		);
1503
		$logQuery->bindValue(":request", $request->getId());
1504
		$logQuery->execute();
1505
		$logTime = $logQuery->fetchColumn();
1506
		$logQuery->closeCursor();
1507
        
1508
		$date = new DateTime();
1509
		$date->modify("-7 days");
1510
		$oneweek = $date->format("Y-m-d H:i:s");
1511
        
1512
		if ($request->getStatus() == "Closed" && $logTime < $oneweek && !User::getCurrent($database)->isAdmin()) {
0 ignored issues
show
Bug introduced by
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

1512
		if ($request->/** @scrutinizer ignore-call */ getStatus() == "Closed" && $logTime < $oneweek && !User::getCurrent($database)->isAdmin()) {
Loading history...
1513
			throw new TransactionException("Only administrators and checkusers can reserve a request that has been closed for over a week.", "Error");
1514
		}
1515
        
1516
	   	if ($request->getReserved() != 0 && $request->getReserved() != User::getCurrent($database)->getId()) {
0 ignored issues
show
Bug introduced by
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

1516
	   	if ($request->/** @scrutinizer ignore-call */ getReserved() != 0 && $request->getReserved() != User::getCurrent($database)->getId()) {
Loading history...
1517
			throw new TransactionException("Request is already reserved by {$request->getReservedObject()->getUsername()}.", "Error");
0 ignored issues
show
Bug introduced by
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

1517
			throw new TransactionException("Request is already reserved by {$request->/** @scrutinizer ignore-call */ getReservedObject()->getUsername()}.", "Error");
Loading history...
1518
		}
1519
           
1520
		if ($request->getReserved() == 0) {
1521
			// Check the number of requests a user has reserved already
1522
			$doubleReserveCountQuery = $database->prepare("SELECT COUNT(*) FROM request WHERE reserved = :userid;");
1523
			$doubleReserveCountQuery->bindValue(":userid", User::getCurrent($database)->getId());
1524
			$doubleReserveCountQuery->execute();
1525
			$doubleReserveCount = $doubleReserveCountQuery->fetchColumn();
1526
			$doubleReserveCountQuery->closeCursor();
1527
1528
			// User already has at least one reserved. 
1529
			if ($doubleReserveCount != 0) {
1530
				SessionAlert::warning("You have multiple requests reserved!");
1531
			}
1532
1533
			// Is the request closed?
1534
			if (!isset($_GET['confclosed'])) {
1535
				if ($request->getStatus() == "Closed") {
1536
					// FIXME: bootstrappify properly
1537
					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");
1538
				}
1539
			}	
1540
        
1541
			$request->setReserved(User::getCurrent($database)->getId());
0 ignored issues
show
Bug introduced by
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

1541
			$request->/** @scrutinizer ignore-call */ 
1542
             setReserved(User::getCurrent($database)->getId());
Loading history...
1542
			$request->save();
1543
	
1544
			Logger::reserve($database, $request);
1545
                
1546
			Notification::requestReserved($request);
1547
                
1548
			SessionAlert::success("Reserved request {$request->getId()}.");
1549
		}
1550
        
1551
		header("Location: $baseurl/acc.php?action=zoom&id={$request->getId()}");
1552
	});
1553
	    
1554
	die();	
1555
}
1556
elseif ($action == "breakreserve") {
1557
	global $smarty;
1558
    
1559
	$database = gGetDb();
1560
    
1561
	$request = Request::getById($_GET['resid'], $database);
1562
        
1563
	if ($request == false) {
1564
		BootstrapSkin::displayAlertBox("Could not find request.", "alert-error", "Error", true, false);
1565
		BootstrapSkin::displayInternalFooter();
1566
		die();
1567
	}
1568
    
1569
	if ($request->getReserved() == 0) {
1570
		BootstrapSkin::displayAlertBox("Request is not reserved.", "alert-error", "Error", true, false);
1571
		BootstrapSkin::displayInternalFooter();
1572
		die();
1573
	}
1574
    
1575
	$reservedUser = $request->getReservedObject();
1576
    
1577
	if ($reservedUser == false) {
1578
		BootstrapSkin::displayAlertBox("Could not find user who reserved the request (!!).", "alert-error", "Error", true, false);
1579
		BootstrapSkin::displayInternalFooter();
1580
		die();
1581
	}
1582
    
1583
	if ($reservedUser->getId() != User::getCurrent()->getId()) {
1584
		if (User::getCurrent()->isAdmin()) {
1585
			if (isset($_GET['confirm']) && $_GET['confirm'] == 1) {
1586
				$database->transactionally(function() use($database, $request)
1587
				{
1588
					$request->setReserved(0);
1589
					$request->save();
1590
1591
					Logger::breakReserve($database, $request);
1592
                
1593
					Notification::requestReserveBroken($request);
1594
					header("Location: acc.php");
1595
				});
1596
                
1597
				die();
1598
			}
1599
			else {
1600
				global $baseurl;
1601
				$smarty->assign("reservedUser", $reservedUser);
1602
				$smarty->assign("request", $request);
1603
                
1604
				$smarty->display("confirmations/breakreserve.tpl");
1605
			}
1606
		}
1607
		else {
1608
			echo "You cannot break " . htmlentities($reservedUser->getUsername()) . "'s reservation";
1609
		}
1610
	}
1611
	else {
1612
		$database->transactionally(function() use ($database, $request)
1613
		{
1614
			$request->setReserved(0);
1615
			$request->save();
1616
1617
			Logger::unreserve($database, $request);
1618
        
1619
			Notification::requestUnreserved($request);
1620
			header("Location: acc.php");
1621
		});
1622
        
1623
		die();
1624
	}
1625
    
1626
	BootstrapSkin::displayInternalFooter();
1627
	die();		
1628
}
1629
elseif ($action == "comment") {
1630
	global $smarty;
1631
    
1632
	$request = Request::getById($_GET['id'], gGetDb());
1633
	$smarty->assign("request", $request);
1634
	$smarty->display("commentform.tpl");
1635
	BootstrapSkin::displayInternalFooter();
1636
	die();
1637
}
1638
elseif ($action == "comment-add") {
1639
	global $baseurl, $smarty;
1640
    
1641
	$request = Request::getById($_POST['id'], gGetDb());
1642
	if ($request == false) {
1643
		BootstrapSkin::displayAlertBox("Could not find request!", "alert-error", "Error", true, false);
1644
		BootstrapSkin::displayInternalFooter();
1645
		die();
1646
	}
1647
    
1648
	if (!isset($_POST['comment']) || $_POST['comment'] == "") {
1649
		BootstrapSkin::displayAlertBox("Comment must be supplied!", "alert-error", "Error", true, false);
1650
		BootstrapSkin::displayInternalFooter();
1651
		die(); 
1652
	}
1653
    
1654
	$visibility = 'user';
1655
	if (isset($_POST['visibility'])) {
1656
		// sanity check
1657
		$visibility = $_POST['visibility'] == 'user' ? 'user' : 'admin';
1658
	}
1659
    
1660
	//Look for and detect IPv4/IPv6 addresses in comment text, and warn the commenter.
1661
	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") {
1662
			BootstrapSkin::displayAlertBox("IP address detected in comment text.  Warning acknowledgement checkbox must be checked.", "alert-error", "Error", true, false);
1663
			$smarty->assign("request", $request);
1664
			$smarty->assign("comment", $_POST['comment']);
1665
			$smarty->assign("actionLocation", "comment-add");
1666
			$smarty->display("privpol-warning.tpl");
1667
			BootstrapSkin::displayInternalFooter();
1668
			die();
1669
		}
1670
    
1671
	$comment = new Comment();
1672
	$comment->setDatabase(gGetDb());
1673
    
1674
	$comment->setRequest($request->getId());
1675
	$comment->setVisibility($visibility);
1676
	$comment->setUser(User::getCurrent()->getId());
1677
	$comment->setComment($_POST['comment']);
1678
    
1679
	$comment->save();
1680
    
1681
	if (isset($_GET['hash'])) {
1682
		$urlhash = urlencode(htmlentities($_GET['hash']));
1683
	}
1684
	else {
1685
		$urlhash = "";
1686
	}
1687
1688
	BootstrapSkin::displayAlertBox(
1689
		"<a href='$baseurl/acc.php?action=zoom&amp;id={$request->getId()}&amp;hash=$urlhash'>Return to request #{$request->getId()}</a>",
1690
		"alert-success",
1691
		"Comment added Successfully!",
1692
		true, false);
1693
        
1694
	Notification::commentCreated($comment);
1695
        
1696
	BootstrapSkin::displayInternalFooter();
1697
	die();
1698
}
1699
elseif ($action == "comment-quick") {
1700
	$request = Request::getById($_POST['id'], gGetDb());
1701
	if ($request == false) {
1702
		BootstrapSkin::displayAlertBox("Could not find request!", "alert-error", "Error", true, false);
1703
		BootstrapSkin::displayInternalFooter();
1704
		die();
1705
	}
1706
    
1707
	if (!isset($_POST['comment']) || $_POST['comment'] == "") {
1708
		header("Location: acc.php?action=zoom&id=" . $request->getId());
1709
		die(); 
1710
	}
1711
    
1712
	$visibility = 'user';
1713
	if (isset($_POST['visibility'])) {
1714
		// sanity check
1715
		$visibility = $_POST['visibility'] == 'user' ? 'user' : 'admin';
1716
	}
1717
1718
	//Look for and detect IPv4/IPv6 addresses in comment text, and warn the commenter.
1719
	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") {
1720
			BootstrapSkin::displayAlertBox("IP address detected in comment text.  Warning acknowledgement checkbox must be checked.", "alert-error", "Error", true, false);
1721
			$smarty->assign("request", $request);
1722
			$smarty->assign("comment", $_POST['comment']);
1723
			$smarty->assign("actionLocation", "comment-quick");
1724
			$smarty->display("privpol-warning.tpl");
1725
			BootstrapSkin::displayInternalFooter();
1726
			die();
1727
		}
1728
    
1729
	$comment = new Comment();
1730
	$comment->setDatabase(gGetDb());
1731
    
1732
	$comment->setRequest($request->getId());
1733
	$comment->setVisibility($visibility);
1734
	$comment->setUser(User::getCurrent()->getId());
1735
	$comment->setComment($_POST['comment']);
1736
    
1737
	$comment->save();
1738
    
1739
	Notification::commentCreated($comment);
1740
    
1741
	header("Location: acc.php?action=zoom&id=" . $request->getId());
1742
}
1743
elseif ($action == "changepassword") {
1744
	if ((!isset($_POST['oldpassword'])) || $_POST['oldpassword'] == "") {
1745
		//Throw an error if old password is not specified.
1746
		BootstrapSkin::displayAlertBox("You did not enter your old password.", "alert-error", "Error", true, false);
1747
		BootstrapSkin::displayInternalFooter();
1748
		die();
1749
	}
1750
	
1751
	if ((!isset($_POST['newpassword'])) || $_POST['newpassword'] == "") {
1752
		//Throw an error if new password is not specified.
1753
		BootstrapSkin::displayAlertBox("You did not enter your new password.", "alert-error", "Error", true, false);
1754
		BootstrapSkin::displayInternalFooter();
1755
		die();
1756
	}
1757
	
1758
	if ($_POST['newpassword'] != $_POST['newpasswordconfirm']) {
1759
		//Throw an error if new password does not match what is in the confirmation box.
1760
		BootstrapSkin::displayAlertBox("The 2 new passwords you entered do not match.", "alert-error", "Error", true, false);
1761
		BootstrapSkin::displayInternalFooter();
1762
		die();
1763
	}
1764
    
1765
	$user = User::getCurrent();
1766
	   
1767
	if (!$user->authenticate($_POST['oldpassword'])) {
1768
		//Throw an error if the old password field's value does not match the user's current password.
1769
		BootstrapSkin::displayAlertBox("The old password you entered is not correct.", "alert-error", "Error", true, false);
1770
		BootstrapSkin::displayInternalFooter();
1771
		die();
1772
	}
1773
    
1774
	$user->setPassword($_POST['newpassword']);
1775
	$user->save();
1776
    
1777
	BootstrapSkin::displayAlertBox("Password successfully changed!", "alert-success", "", false, false);
1778
	BootstrapSkin::displayInternalFooter();
1779
	die();
1780
}
1781
elseif ($action == "ec") {
1782
	// edit comment
1783
  
1784
	global $smarty, $baseurl;
1785
    
1786
	$comment = Comment::getById($_GET['id'], gGetDb());
1787
    
1788
	if ($comment == false) {
1789
		// Only using die("Message"); for errors looks ugly.
1790
		BootstrapSkin::displayAlertBox("Comment not found.", "alert-error", "Error", true, false);
1791
		BootstrapSkin::displayInternalFooter();
1792
		die();
1793
	}
1794
	
1795
	// Unauthorized if user is not an admin or the user who made the comment being edited.
1796
	if (!User::getCurrent()->isAdmin() && !User::getCurrent()->isCheckuser() && $comment->getUser() != User::getCurrent()->getId()) {
1797
		BootstrapSkin::displayAccessDenied();
1798
		BootstrapSkin::displayInternalFooter();
1799
		die();
1800
	}
1801
	
1802
	// get[id] is safe by this point.
1803
	
1804
	if ($_SERVER['REQUEST_METHOD'] == 'POST') {
1805
		$database = gGetDb();
1806
		$database->transactionally(function() use ($database, $comment, $baseurl)
1807
		{
1808
            
1809
			$comment->setComment($_POST['newcomment']);
1810
			$comment->setVisibility($_POST['visibility']);
1811
        
1812
			$comment->save();
1813
        
1814
			Logger::editComment($database, $comment);
1815
        
1816
			Notification::commentEdited($comment);
1817
        
1818
			SessionAlert::success("Comment has been saved successfully");
1819
			header("Location: $baseurl/acc.php?action=zoom&id=" . $comment->getRequest());
1820
		});
1821
        
1822
		die();    
1823
	}
1824
	else {
1825
		$smarty->assign("comment", $comment);
1826
		$smarty->display("edit-comment.tpl");
1827
		BootstrapSkin::displayInternalFooter();
1828
		die();
1829
	}
1830
}
1831
elseif ($action == "sendtouser") {
1832
	global $baseurl;
1833
    
1834
	$database = gGetDb();
1835
1836
	/** @var Request $requestObject */
1837
	$requestObject = Request::getById($_POST['id'], $database);
1838
	if ($requestObject == false) {
1839
		BootstrapSkin::displayAlertBox("Request invalid", "alert-error", "Could not find request", true, false);
1840
		BootstrapSkin::displayInternalFooter();
1841
		die();
1842
	}
1843
    
1844
	$request = $requestObject->getId();
1845
    
1846
	$user = User::getByUsername($_POST['user'], $database);
1847
	$curuser = User::getCurrent()->getUsername();
1848
    
1849
	if ($user == false) {
1850
		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);
1851
		BootstrapSkin::displayInternalFooter();
1852
		die();
1853
	}
1854
    
1855
	$database->transactionally(function() use ($database, $user, $requestObject, $curuser)
0 ignored issues
show
Unused Code introduced by
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...
1856
	{
1857
		$updateStatement = $database->prepare("UPDATE request SET reserved = :userid WHERE id = :request;");
1858
		$updateStatement->bindValue(":userid", $user->getId());
1859
		$updateStatement->bindValue(":request", $requestObject->getId());
1860
		if (!$updateStatement->execute()) {
1861
			throw new TransactionException("Error updating reserved status of request.");   
1862
		}
1863
        
1864
		Logger::sendReservation($database, $requestObject, $user);
1865
	});
1866
    
1867
	Notification::requestReservationSent($requestObject, $user);
1868
	SessionAlert::success("Reservation sent successfully");
1869
	header("Location: $baseurl/acc.php?action=zoom&id=$request");
1870
}
1871
elseif ($action == "emailmgmt") {
1872
	global $smarty, $createdid, $availableRequestStates;
1873
    
1874
	/* New page for managing Emails, since I would rather not be handling editing
1875
	interface messages (such as the Sitenotice) and the new Emails in the same place. */
1876
	if (isset($_GET['create'])) {
1877
		if (!User::getCurrent()->isAdmin()) {
1878
			BootstrapSkin::displayAccessDenied();
1879
			BootstrapSkin::displayInternalFooter();
1880
			die();
1881
		}
1882
		if (isset($_POST['submit'])) {
1883
			$database = gGetDb();
1884
			$database->transactionally(function() use ($database)
1885
			{
1886
				global $baseurl;
1887
                
1888
				$emailTemplate = new EmailTemplate();
1889
				$emailTemplate->setDatabase($database);
1890
            
1891
				$emailTemplate->setName($_POST['name']);
1892
				$emailTemplate->setText($_POST['text']);
1893
				$emailTemplate->setJsquestion($_POST['jsquestion']);
1894
				$emailTemplate->setDefaultAction($_POST['defaultaction']);
1895
				$emailTemplate->setActive(isset($_POST['active']));
1896
1897
				// Check if the entered name already exists (since these names are going to be used as the labels for buttons on the zoom page).
1898
				// getByName(...) returns false on no records found.
1899
				if (EmailTemplate::getByName($_POST['name'], $database)) {
1900
					throw new TransactionException("That Email template name is already being used. Please choose another.");
1901
				}
1902
			
1903
				$emailTemplate->save();
1904
                
1905
				Logger::createEmail($database, $emailTemplate);
1906
                
1907
				Notification::emailCreated($emailTemplate);
1908
                
1909
				SessionAlert::success("Email template has been saved successfully.");
1910
				header("Location: $baseurl/acc.php?action=emailmgmt");
1911
			});
1912
            
1913
			die();
1914
		}
1915
        
1916
		$smarty->assign('id', null);
1917
		$smarty->assign('createdid', $createdid);
1918
		$smarty->assign('requeststates', $availableRequestStates);
1919
		$smarty->assign('emailTemplate', new EmailTemplate());
1920
		$smarty->assign('emailmgmtpage', 'Create'); //Use a variable so we don't need two Smarty templates for creating and editing.
1921
		$smarty->display("email-management/edit.tpl");
1922
		BootstrapSkin::displayInternalFooter();
1923
		die();
1924
	}
1925
	if (isset($_GET['edit'])) {
1926
		global $createdid;
1927
        
1928
		$database = gGetDb();
1929
        
1930
		if (isset($_POST['submit'])) {
1931
			$emailTemplate = EmailTemplate::getById($_GET['edit'], $database);
1932
			// Allow the user to see the edit form (with read only fields) but not POST anything.
1933
			if (!User::getCurrent()->isAdmin()) {
1934
				BootstrapSkin::displayAccessDenied();
1935
				BootstrapSkin::displayInternalFooter();
1936
				die();
1937
			}
1938
            
1939
			$emailTemplate->setName($_POST['name']);
1940
			$emailTemplate->setText($_POST['text']);
1941
			$emailTemplate->setJsquestion($_POST['jsquestion']);
1942
			
1943
			if ($_GET['edit'] == $createdid) {
1944
				// Both checkboxes on the main created message should always be enabled.
1945
				$emailTemplate->setDefaultAction(EmailTemplate::CREATED);
1946
				$emailTemplate->setActive(1);
1947
				$emailTemplate->setPreloadOnly(0);
1948
			}
1949
			else {
1950
				$emailTemplate->setDefaultAction($_POST['defaultaction']);
1951
				$emailTemplate->setActive(isset($_POST['active']));
1952
				$emailTemplate->setPreloadOnly(isset($_POST['preloadonly']));
1953
			}
1954
				
1955
			// Check if the entered name already exists (since these names are going to be used as the labels for buttons on the zoom page).
1956
			$nameCheck = EmailTemplate::getByName($_POST['name'], gGetDb());
1957
			if ($nameCheck != false && $nameCheck->getId() != $_GET['edit']) {
1958
				BootstrapSkin::displayAlertBox("That Email template name is already being used. Please choose another.");
1959
				BootstrapSkin::displayInternalFooter();
1960
				die();
1961
			}
1962
1963
			$database->transactionally(function() use ($database, $emailTemplate)
1964
			{
1965
				$emailTemplate->save();
1966
                
1967
				Logger::editedEmail($database, $emailTemplate);
1968
            
1969
				global $baseurl;
1970
                
1971
				Notification::emailEdited($emailTemplate);
1972
				SessionAlert::success("Email template has been saved successfully.");
1973
				header("Location: $baseurl/acc.php?action=emailmgmt");
1974
			});
1975
            
1976
			die();
1977
		}
1978
        
1979
		$emailTemplate = EmailTemplate::getById($_GET['edit'], gGetDb());
1980
		$smarty->assign('id', $emailTemplate->getId());
1981
		$smarty->assign('emailTemplate', $emailTemplate);
1982
		$smarty->assign('createdid', $createdid);
1983
		$smarty->assign('requeststates', $availableRequestStates);
1984
		$smarty->assign('emailmgmtpage', 'Edit'); // Use a variable so we don't need two Smarty templates for creating and editing.
1985
		$smarty->display("email-management/edit.tpl");
1986
		BootstrapSkin::displayInternalFooter();
1987
		die();
1988
	}
1989
    
1990
	$query = "SELECT * FROM emailtemplate WHERE active = 1";
1991
	$statement = gGetDb()->prepare($query);
1992
	$statement->execute();
1993
	$rows = $statement->fetchAll(PDO::FETCH_CLASS, "EmailTemplate");
1994
	$smarty->assign('activeemails', $rows);
1995
        
1996
	$query = "SELECT * FROM emailtemplate WHERE active = 0";
1997
	$statement = gGetDb()->prepare($query);
1998
	$statement->execute();
1999
	$inactiverows = $statement->fetchAll(PDO::FETCH_CLASS, "EmailTemplate");
2000
	$smarty->assign('inactiveemails', $inactiverows);
2001
 
2002
	if (count($inactiverows) > 0) {
2003
		$smarty->assign('displayinactive', true);
2004
	}
2005
	else {
2006
		$smarty->assign('displayinactive', false);
2007
	}
2008
    
2009
	$smarty->display("email-management/main.tpl");
2010
	BootstrapSkin::displayInternalFooter();
2011
	die();
2012
}
2013
elseif ($action == "oauthdetach") {
2014
	if ($enforceOAuth) {
2015
		BootstrapSkin::displayAccessDenied();
2016
		BootstrapSkin::displayInternalFooter();
2017
		die();
2018
	}
2019
    
2020
	global $baseurl;
2021
        
2022
	$currentUser = User::getCurrent();
2023
	$currentUser->detachAccount();
2024
        
2025
	header("Location: {$baseurl}/acc.php?action=logout");
2026
}
2027
elseif ($action == "oauthattach") {
2028
	$database = gGetDb();
2029
	$database->transactionally(function() use ($database)
0 ignored issues
show
Unused Code introduced by
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...
2030
	{
2031
		try {
2032
			global $oauthConsumerToken, $oauthSecretToken, $oauthBaseUrl, $oauthBaseUrlInternal;
2033
            
2034
			$user = User::getCurrent();
2035
            
2036
			// Get a request token for OAuth
2037
			$util = new OAuthUtility($oauthConsumerToken, $oauthSecretToken, $oauthBaseUrl, $oauthBaseUrlInternal);
2038
			$requestToken = $util->getRequestToken();
2039
2040
			// save the request token for later
2041
			$user->setOAuthRequestToken($requestToken->key);
2042
			$user->setOAuthRequestSecret($requestToken->secret);
2043
			$user->save();
2044
        
2045
			$redirectUrl = $util->getAuthoriseUrl($requestToken);
2046
        
2047
			header("Location: {$redirectUrl}");
2048
        
2049
		}
2050
		catch (Exception $ex) {
2051
			throw new TransactionException($ex->getMessage(), "Connection to Wikipedia failed.", "alert-error", 0, $ex);
2052
		}
2053
	});
2054
}
2055
elseif ($action == "listall") {
2056
    global $availableRequestStates, $enableEmailConfirm;
2057
2058
	if (isset($_GET['status']) && isset($availableRequestStates[$_GET['status']])) {
2059
		$type = $_GET['status']; // safe, we've verified it's sane in the above if statement.
2060
2061
	    $database = gGetDb();
2062
2063
	    if ($enableEmailConfirm == 1) {
2064
	        $query = "SELECT * FROM request WHERE status = :type AND emailconfirm = 'Confirmed';";
2065
	    } else {
2066
	        $query = "SELECT * FROM request WHERE status = :type;";
2067
	    }
2068
2069
	    $statement = $database->prepare($query);
2070
2071
        $statement->bindValue(":type", $type);
2072
        $statement->execute();
2073
2074
        $requests = $statement->fetchAll(PDO::FETCH_CLASS, "Request");
2075
        foreach ($requests as $req) {
2076
        	/** @var Request $req */
2077
            $req->setDatabase($database);
2078
        }
2079
2080
        global $smarty;
2081
        $smarty->assign("requests", $requests);
2082
        $smarty->assign("showStatus", false);
2083
        $html = $smarty->fetch("mainpage/requesttable.tpl");
2084
        echo $html;
2085
    } else {
2086
        echo defaultpage();
2087
    }
2088
2089
    BootstrapSkin::displayInternalFooter();
2090
    die();
2091
}
2092
# If the action specified does not exist, goto the default page.
2093
else {
2094
	echo defaultpage();
2095
	BootstrapSkin::displayInternalFooter();
2096
	die();
2097
}
2098