@@ -16,24 +16,24 @@ |
||
16 | 16 | */ |
17 | 17 | function smarty_function_defaultsort($params, Smarty_Internal_Template $template) |
18 | 18 | { |
19 | - if (empty($params['id'])) { |
|
20 | - return ""; |
|
21 | - } |
|
19 | + if (empty($params['id'])) { |
|
20 | + return ""; |
|
21 | + } |
|
22 | 22 | |
23 | - $attr = 'data-sortname="' . htmlspecialchars($params['id'], ENT_QUOTES) . '"'; |
|
23 | + $attr = 'data-sortname="' . htmlspecialchars($params['id'], ENT_QUOTES) . '"'; |
|
24 | 24 | |
25 | - if (empty($params['req'])) { |
|
26 | - return $attr; |
|
27 | - } |
|
25 | + if (empty($params['req'])) { |
|
26 | + return $attr; |
|
27 | + } |
|
28 | 28 | |
29 | - if ($params['dir'] !== 'asc' && $params['dir'] !== 'desc') { |
|
30 | - $params['dir'] = 'asc'; |
|
31 | - } |
|
29 | + if ($params['dir'] !== 'asc' && $params['dir'] !== 'desc') { |
|
30 | + $params['dir'] = 'asc'; |
|
31 | + } |
|
32 | 32 | |
33 | - $sort = ''; |
|
34 | - if ($params['req'] === $params['id']) { |
|
35 | - $sort = ' data-defaultsort="' . htmlspecialchars($params['dir'], ENT_QUOTES) . '"'; |
|
36 | - } |
|
33 | + $sort = ''; |
|
34 | + if ($params['req'] === $params['id']) { |
|
35 | + $sort = ' data-defaultsort="' . htmlspecialchars($params['dir'], ENT_QUOTES) . '"'; |
|
36 | + } |
|
37 | 37 | |
38 | - return $attr . $sort; |
|
38 | + return $attr . $sort; |
|
39 | 39 | } |
40 | 40 | \ No newline at end of file |
@@ -16,78 +16,78 @@ |
||
16 | 16 | */ |
17 | 17 | function smarty_modifier_timespan($input) |
18 | 18 | { |
19 | - $remaining = abs(floor($input)); |
|
19 | + $remaining = abs(floor($input)); |
|
20 | 20 | |
21 | - $seconds = $remaining % 60; |
|
22 | - $remaining = $remaining - $seconds; |
|
21 | + $seconds = $remaining % 60; |
|
22 | + $remaining = $remaining - $seconds; |
|
23 | 23 | |
24 | - $minutes = $remaining % (60 * 60); |
|
25 | - $remaining = $remaining - $minutes; |
|
26 | - $minutes /= 60; |
|
24 | + $minutes = $remaining % (60 * 60); |
|
25 | + $remaining = $remaining - $minutes; |
|
26 | + $minutes /= 60; |
|
27 | 27 | |
28 | - $hours = $remaining % (60 * 60 * 24); |
|
29 | - $remaining = $remaining - $hours; |
|
30 | - $hours /= (60 * 60); |
|
28 | + $hours = $remaining % (60 * 60 * 24); |
|
29 | + $remaining = $remaining - $hours; |
|
30 | + $hours /= (60 * 60); |
|
31 | 31 | |
32 | - $days = $remaining % (60 * 60 * 24 * 7); |
|
33 | - $weeks = $remaining - $days; |
|
34 | - $days /= (60 * 60 * 24); |
|
35 | - $weeks /= (60 * 60 * 24 * 7); |
|
32 | + $days = $remaining % (60 * 60 * 24 * 7); |
|
33 | + $weeks = $remaining - $days; |
|
34 | + $days /= (60 * 60 * 24); |
|
35 | + $weeks /= (60 * 60 * 24 * 7); |
|
36 | 36 | |
37 | - $stringval = ''; |
|
38 | - $trip = false; |
|
37 | + $stringval = ''; |
|
38 | + $trip = false; |
|
39 | 39 | |
40 | - if ($weeks > 0) { |
|
41 | - $stringval .= "${weeks}w "; |
|
42 | - } |
|
40 | + if ($weeks > 0) { |
|
41 | + $stringval .= "${weeks}w "; |
|
42 | + } |
|
43 | 43 | |
44 | - if ($days > 0) { |
|
45 | - if ($stringval !== '') { |
|
46 | - $trip = true; |
|
47 | - } |
|
44 | + if ($days > 0) { |
|
45 | + if ($stringval !== '') { |
|
46 | + $trip = true; |
|
47 | + } |
|
48 | 48 | |
49 | - $stringval .= "${days}d "; |
|
49 | + $stringval .= "${days}d "; |
|
50 | 50 | |
51 | - if ($trip) { |
|
52 | - return trim($stringval); |
|
53 | - } |
|
54 | - } |
|
51 | + if ($trip) { |
|
52 | + return trim($stringval); |
|
53 | + } |
|
54 | + } |
|
55 | 55 | |
56 | - if ($hours > 0) { |
|
57 | - if ($stringval !== '') { |
|
58 | - $trip = true; |
|
59 | - } |
|
56 | + if ($hours > 0) { |
|
57 | + if ($stringval !== '') { |
|
58 | + $trip = true; |
|
59 | + } |
|
60 | 60 | |
61 | - $stringval .= "${hours}h "; |
|
61 | + $stringval .= "${hours}h "; |
|
62 | 62 | |
63 | - if ($trip) { |
|
64 | - return trim($stringval); |
|
65 | - } |
|
66 | - } |
|
63 | + if ($trip) { |
|
64 | + return trim($stringval); |
|
65 | + } |
|
66 | + } |
|
67 | 67 | |
68 | - if ($minutes > 0) { |
|
69 | - if ($stringval !== '') { |
|
70 | - $trip = true; |
|
71 | - } |
|
68 | + if ($minutes > 0) { |
|
69 | + if ($stringval !== '') { |
|
70 | + $trip = true; |
|
71 | + } |
|
72 | 72 | |
73 | - $stringval .= "${minutes}m "; |
|
73 | + $stringval .= "${minutes}m "; |
|
74 | 74 | |
75 | - if ($trip) { |
|
76 | - return trim($stringval); |
|
77 | - } |
|
78 | - } |
|
75 | + if ($trip) { |
|
76 | + return trim($stringval); |
|
77 | + } |
|
78 | + } |
|
79 | 79 | |
80 | - if ($seconds > 0) { |
|
81 | - if ($stringval !== '') { |
|
82 | - $trip = true; |
|
83 | - } |
|
80 | + if ($seconds > 0) { |
|
81 | + if ($stringval !== '') { |
|
82 | + $trip = true; |
|
83 | + } |
|
84 | 84 | |
85 | - $stringval .= "${seconds}s "; |
|
85 | + $stringval .= "${seconds}s "; |
|
86 | 86 | |
87 | - if ($trip) { |
|
88 | - return trim($stringval); |
|
89 | - } |
|
90 | - } |
|
87 | + if ($trip) { |
|
88 | + return trim($stringval); |
|
89 | + } |
|
90 | + } |
|
91 | 91 | |
92 | - return trim($stringval); |
|
92 | + return trim($stringval); |
|
93 | 93 | } |
94 | 94 | \ No newline at end of file |
@@ -12,102 +12,102 @@ |
||
12 | 12 | |
13 | 13 | class ValidationError |
14 | 14 | { |
15 | - const NAME_EMPTY = "name_empty"; |
|
16 | - const NAME_TOO_LONG = "name_too_long"; |
|
17 | - const NAME_EXISTS = "name_exists"; |
|
18 | - const NAME_EXISTS_SUL = "name_exists_sul"; |
|
19 | - const NAME_NUMONLY = "name_numonly"; |
|
20 | - const NAME_INVALIDCHAR = "name_invalidchar"; |
|
21 | - const NAME_SANITISED = "name_sanitised"; |
|
22 | - const NAME_IP = "name_ip"; |
|
23 | - const EMAIL_EMPTY = "email_empty"; |
|
24 | - const EMAIL_WIKIMEDIA = "email_wikimedia"; |
|
25 | - const EMAIL_INVALID = "email_invalid"; |
|
26 | - const EMAIL_MISMATCH = "email_mismatch"; |
|
27 | - const OPEN_REQUEST_NAME = "open_request_name"; |
|
28 | - const BANNED = "banned"; |
|
29 | - const BANNED_TOR = "banned_tor"; |
|
30 | - /** |
|
31 | - * @var array Error text for the above |
|
32 | - */ |
|
33 | - private static $errorText = array( |
|
34 | - self::NAME_EMPTY => 'You\'ve not chosen a username!', |
|
35 | - self::NAME_TOO_LONG => 'Your chosen username is too long. Please choose a shorter one.', |
|
36 | - self::NAME_EXISTS => 'I\'m sorry, but the username you selected is already taken. Please try another. ' |
|
37 | - . 'Please note that Wikipedia automatically capitalizes the first letter of any user name, therefore ' |
|
38 | - . '[[User:example]] would become [[User:Example]].', |
|
39 | - self::NAME_EXISTS_SUL => 'I\'m sorry, but the username you selected is already taken. Please try another. ' |
|
40 | - . 'Please note that Wikipedia automatically capitalizes the first letter of any user name, therefore ' |
|
41 | - . '[[User:example]] would become [[User:Example]].', |
|
42 | - self::NAME_NUMONLY => 'The username you chose is invalid: it consists entirely of numbers. Please retry ' |
|
43 | - . 'with a valid username.', |
|
44 | - self::NAME_INVALIDCHAR => 'There appears to be an invalid character in your username. Please note that the ' |
|
45 | - . 'following characters are not allowed: <code># @ / < > [ ] | { }</code>', |
|
46 | - self::NAME_SANITISED => 'Your requested username has been automatically adjusted due to technical ' |
|
47 | - . 'restrictions. Underscores have been replaced with spaces, and the first character has been capitalised.', |
|
48 | - self::NAME_IP => 'The username you chose is invalid: it cannot be an IP address', |
|
49 | - self::EMAIL_EMPTY => 'You need to supply an email address.', |
|
50 | - self::EMAIL_WIKIMEDIA => 'Please provide your email address here.', |
|
51 | - self::EMAIL_INVALID => 'Invalid E-mail address supplied. Please check you entered it correctly.', |
|
52 | - self::EMAIL_MISMATCH => 'The email addresses you entered do not match. Please try again.', |
|
53 | - self::OPEN_REQUEST_NAME => 'There is already an open request with this name in this system.', |
|
54 | - self::BANNED => 'Sorry, you are currently banned from requesting accounts using this tool.', |
|
55 | - self::BANNED_TOR => 'Tor exit nodes are currently banned from using this tool due to excessive abuse. ' |
|
56 | - . 'Please note that Tor is also currently banned from editing Wikipedia.', |
|
57 | - ); |
|
58 | - /** |
|
59 | - * Summary of $errorCode |
|
60 | - * @var string |
|
61 | - */ |
|
62 | - private $errorCode; |
|
63 | - /** |
|
64 | - * Summary of $isError |
|
65 | - * @var bool |
|
66 | - */ |
|
67 | - private $isError; |
|
15 | + const NAME_EMPTY = "name_empty"; |
|
16 | + const NAME_TOO_LONG = "name_too_long"; |
|
17 | + const NAME_EXISTS = "name_exists"; |
|
18 | + const NAME_EXISTS_SUL = "name_exists_sul"; |
|
19 | + const NAME_NUMONLY = "name_numonly"; |
|
20 | + const NAME_INVALIDCHAR = "name_invalidchar"; |
|
21 | + const NAME_SANITISED = "name_sanitised"; |
|
22 | + const NAME_IP = "name_ip"; |
|
23 | + const EMAIL_EMPTY = "email_empty"; |
|
24 | + const EMAIL_WIKIMEDIA = "email_wikimedia"; |
|
25 | + const EMAIL_INVALID = "email_invalid"; |
|
26 | + const EMAIL_MISMATCH = "email_mismatch"; |
|
27 | + const OPEN_REQUEST_NAME = "open_request_name"; |
|
28 | + const BANNED = "banned"; |
|
29 | + const BANNED_TOR = "banned_tor"; |
|
30 | + /** |
|
31 | + * @var array Error text for the above |
|
32 | + */ |
|
33 | + private static $errorText = array( |
|
34 | + self::NAME_EMPTY => 'You\'ve not chosen a username!', |
|
35 | + self::NAME_TOO_LONG => 'Your chosen username is too long. Please choose a shorter one.', |
|
36 | + self::NAME_EXISTS => 'I\'m sorry, but the username you selected is already taken. Please try another. ' |
|
37 | + . 'Please note that Wikipedia automatically capitalizes the first letter of any user name, therefore ' |
|
38 | + . '[[User:example]] would become [[User:Example]].', |
|
39 | + self::NAME_EXISTS_SUL => 'I\'m sorry, but the username you selected is already taken. Please try another. ' |
|
40 | + . 'Please note that Wikipedia automatically capitalizes the first letter of any user name, therefore ' |
|
41 | + . '[[User:example]] would become [[User:Example]].', |
|
42 | + self::NAME_NUMONLY => 'The username you chose is invalid: it consists entirely of numbers. Please retry ' |
|
43 | + . 'with a valid username.', |
|
44 | + self::NAME_INVALIDCHAR => 'There appears to be an invalid character in your username. Please note that the ' |
|
45 | + . 'following characters are not allowed: <code># @ / < > [ ] | { }</code>', |
|
46 | + self::NAME_SANITISED => 'Your requested username has been automatically adjusted due to technical ' |
|
47 | + . 'restrictions. Underscores have been replaced with spaces, and the first character has been capitalised.', |
|
48 | + self::NAME_IP => 'The username you chose is invalid: it cannot be an IP address', |
|
49 | + self::EMAIL_EMPTY => 'You need to supply an email address.', |
|
50 | + self::EMAIL_WIKIMEDIA => 'Please provide your email address here.', |
|
51 | + self::EMAIL_INVALID => 'Invalid E-mail address supplied. Please check you entered it correctly.', |
|
52 | + self::EMAIL_MISMATCH => 'The email addresses you entered do not match. Please try again.', |
|
53 | + self::OPEN_REQUEST_NAME => 'There is already an open request with this name in this system.', |
|
54 | + self::BANNED => 'Sorry, you are currently banned from requesting accounts using this tool.', |
|
55 | + self::BANNED_TOR => 'Tor exit nodes are currently banned from using this tool due to excessive abuse. ' |
|
56 | + . 'Please note that Tor is also currently banned from editing Wikipedia.', |
|
57 | + ); |
|
58 | + /** |
|
59 | + * Summary of $errorCode |
|
60 | + * @var string |
|
61 | + */ |
|
62 | + private $errorCode; |
|
63 | + /** |
|
64 | + * Summary of $isError |
|
65 | + * @var bool |
|
66 | + */ |
|
67 | + private $isError; |
|
68 | 68 | |
69 | - /** |
|
70 | - * Summary of __construct |
|
71 | - * |
|
72 | - * @param string $errorCode |
|
73 | - * @param bool $isError |
|
74 | - */ |
|
75 | - public function __construct($errorCode, $isError = true) |
|
76 | - { |
|
77 | - $this->errorCode = $errorCode; |
|
78 | - $this->isError = $isError; |
|
79 | - } |
|
69 | + /** |
|
70 | + * Summary of __construct |
|
71 | + * |
|
72 | + * @param string $errorCode |
|
73 | + * @param bool $isError |
|
74 | + */ |
|
75 | + public function __construct($errorCode, $isError = true) |
|
76 | + { |
|
77 | + $this->errorCode = $errorCode; |
|
78 | + $this->isError = $isError; |
|
79 | + } |
|
80 | 80 | |
81 | - /** |
|
82 | - * Summary of getErrorCode |
|
83 | - * @return string |
|
84 | - */ |
|
85 | - public function getErrorCode() |
|
86 | - { |
|
87 | - return $this->errorCode; |
|
88 | - } |
|
81 | + /** |
|
82 | + * Summary of getErrorCode |
|
83 | + * @return string |
|
84 | + */ |
|
85 | + public function getErrorCode() |
|
86 | + { |
|
87 | + return $this->errorCode; |
|
88 | + } |
|
89 | 89 | |
90 | - /** |
|
91 | - * @return string |
|
92 | - * @throws Exception |
|
93 | - */ |
|
94 | - public function getErrorMessage() |
|
95 | - { |
|
96 | - $text = self::$errorText[$this->errorCode]; |
|
90 | + /** |
|
91 | + * @return string |
|
92 | + * @throws Exception |
|
93 | + */ |
|
94 | + public function getErrorMessage() |
|
95 | + { |
|
96 | + $text = self::$errorText[$this->errorCode]; |
|
97 | 97 | |
98 | - if ($text == null) { |
|
99 | - throw new Exception('Unknown validation error'); |
|
100 | - } |
|
98 | + if ($text == null) { |
|
99 | + throw new Exception('Unknown validation error'); |
|
100 | + } |
|
101 | 101 | |
102 | - return $text; |
|
103 | - } |
|
102 | + return $text; |
|
103 | + } |
|
104 | 104 | |
105 | - /** |
|
106 | - * Summary of isError |
|
107 | - * @return bool |
|
108 | - */ |
|
109 | - public function isError() |
|
110 | - { |
|
111 | - return $this->isError; |
|
112 | - } |
|
105 | + /** |
|
106 | + * Summary of isError |
|
107 | + * @return bool |
|
108 | + */ |
|
109 | + public function isError() |
|
110 | + { |
|
111 | + return $this->isError; |
|
112 | + } |
|
113 | 113 | } |
@@ -31,429 +31,429 @@ |
||
31 | 31 | */ |
32 | 32 | class RequestValidationHelper |
33 | 33 | { |
34 | - /** @var IBanHelper */ |
|
35 | - private $banHelper; |
|
36 | - /** @var PdoDatabase */ |
|
37 | - private $database; |
|
38 | - /** @var IAntiSpoofProvider */ |
|
39 | - private $antiSpoofProvider; |
|
40 | - /** @var IXffTrustProvider */ |
|
41 | - private $xffTrustProvider; |
|
42 | - /** @var HttpHelper */ |
|
43 | - private $httpHelper; |
|
44 | - /** |
|
45 | - * @var string |
|
46 | - */ |
|
47 | - private $mediawikiApiEndpoint; |
|
48 | - private $titleBlacklistEnabled; |
|
49 | - /** |
|
50 | - * @var TorExitProvider |
|
51 | - */ |
|
52 | - private $torExitProvider; |
|
53 | - /** |
|
54 | - * @var SiteConfiguration |
|
55 | - */ |
|
56 | - private $siteConfiguration; |
|
57 | - |
|
58 | - private $validationRemoteTimeout = 5000; |
|
59 | - |
|
60 | - /** |
|
61 | - * Summary of __construct |
|
62 | - * |
|
63 | - * @param IBanHelper $banHelper |
|
64 | - * @param PdoDatabase $database |
|
65 | - * @param IAntiSpoofProvider $antiSpoofProvider |
|
66 | - * @param IXffTrustProvider $xffTrustProvider |
|
67 | - * @param HttpHelper $httpHelper |
|
68 | - * @param TorExitProvider $torExitProvider |
|
69 | - * @param SiteConfiguration $siteConfiguration |
|
70 | - */ |
|
71 | - public function __construct( |
|
72 | - IBanHelper $banHelper, |
|
73 | - PdoDatabase $database, |
|
74 | - IAntiSpoofProvider $antiSpoofProvider, |
|
75 | - IXffTrustProvider $xffTrustProvider, |
|
76 | - HttpHelper $httpHelper, |
|
77 | - TorExitProvider $torExitProvider, |
|
78 | - SiteConfiguration $siteConfiguration |
|
79 | - ) { |
|
80 | - $this->banHelper = $banHelper; |
|
81 | - $this->database = $database; |
|
82 | - $this->antiSpoofProvider = $antiSpoofProvider; |
|
83 | - $this->xffTrustProvider = $xffTrustProvider; |
|
84 | - $this->httpHelper = $httpHelper; |
|
85 | - |
|
86 | - // FIXME: domains! |
|
87 | - /** @var Domain $domain */ |
|
88 | - $domain = Domain::getById(1, $database); |
|
89 | - |
|
90 | - $this->mediawikiApiEndpoint = $domain->getWikiApiPath(); |
|
91 | - $this->titleBlacklistEnabled = $siteConfiguration->getTitleBlacklistEnabled(); |
|
92 | - $this->torExitProvider = $torExitProvider; |
|
93 | - $this->siteConfiguration = $siteConfiguration; |
|
94 | - } |
|
95 | - |
|
96 | - /** |
|
97 | - * Summary of validateName |
|
98 | - * |
|
99 | - * @param Request $request |
|
100 | - * |
|
101 | - * @return ValidationError[] |
|
102 | - */ |
|
103 | - public function validateName(Request $request) |
|
104 | - { |
|
105 | - $errorList = array(); |
|
106 | - |
|
107 | - // ERRORS |
|
108 | - // name is empty |
|
109 | - if (trim($request->getName()) == "") { |
|
110 | - $errorList[ValidationError::NAME_EMPTY] = new ValidationError(ValidationError::NAME_EMPTY); |
|
111 | - } |
|
112 | - |
|
113 | - // name is too long |
|
114 | - if (mb_strlen(trim($request->getName())) > 500) { |
|
115 | - $errorList[ValidationError::NAME_EMPTY] = new ValidationError(ValidationError::NAME_TOO_LONG); |
|
116 | - } |
|
117 | - |
|
118 | - // username already exists |
|
119 | - if ($this->userExists($request)) { |
|
120 | - $errorList[ValidationError::NAME_EXISTS] = new ValidationError(ValidationError::NAME_EXISTS); |
|
121 | - } |
|
122 | - |
|
123 | - // username part of SUL account |
|
124 | - if ($this->userSulExists($request)) { |
|
125 | - // using same error slot as name exists - it's the same sort of error, and we probably only want to show one. |
|
126 | - $errorList[ValidationError::NAME_EXISTS] = new ValidationError(ValidationError::NAME_EXISTS_SUL); |
|
127 | - } |
|
128 | - |
|
129 | - // username is numbers |
|
130 | - if (preg_match("/^[0-9]+$/", $request->getName()) === 1) { |
|
131 | - $errorList[ValidationError::NAME_NUMONLY] = new ValidationError(ValidationError::NAME_NUMONLY); |
|
132 | - } |
|
133 | - |
|
134 | - // username can't contain #@/<>[]|{} |
|
135 | - if (preg_match("/[" . preg_quote("#@/<>[]|{}", "/") . "]/", $request->getName()) === 1) { |
|
136 | - $errorList[ValidationError::NAME_INVALIDCHAR] = new ValidationError(ValidationError::NAME_INVALIDCHAR); |
|
137 | - } |
|
138 | - |
|
139 | - // username is an IP |
|
140 | - if (filter_var($request->getName(), FILTER_VALIDATE_IP)) { |
|
141 | - $errorList[ValidationError::NAME_IP] = new ValidationError(ValidationError::NAME_IP); |
|
142 | - } |
|
143 | - |
|
144 | - // existing non-closed request for this name |
|
145 | - if ($this->nameRequestExists($request)) { |
|
146 | - $errorList[ValidationError::OPEN_REQUEST_NAME] = new ValidationError(ValidationError::OPEN_REQUEST_NAME); |
|
147 | - } |
|
148 | - |
|
149 | - return $errorList; |
|
150 | - } |
|
151 | - |
|
152 | - /** |
|
153 | - * Summary of validateEmail |
|
154 | - * |
|
155 | - * @param Request $request |
|
156 | - * @param string $emailConfirmation |
|
157 | - * |
|
158 | - * @return ValidationError[] |
|
159 | - */ |
|
160 | - public function validateEmail(Request $request, $emailConfirmation) |
|
161 | - { |
|
162 | - $errorList = array(); |
|
163 | - |
|
164 | - // ERRORS |
|
165 | - |
|
166 | - // email addresses must match |
|
167 | - if ($request->getEmail() != $emailConfirmation) { |
|
168 | - $errorList[ValidationError::EMAIL_MISMATCH] = new ValidationError(ValidationError::EMAIL_MISMATCH); |
|
169 | - } |
|
170 | - |
|
171 | - // email address must be validly formed |
|
172 | - if (trim($request->getEmail()) == "") { |
|
173 | - $errorList[ValidationError::EMAIL_EMPTY] = new ValidationError(ValidationError::EMAIL_EMPTY); |
|
174 | - } |
|
175 | - |
|
176 | - // email address must be validly formed |
|
177 | - if (!filter_var($request->getEmail(), FILTER_VALIDATE_EMAIL)) { |
|
178 | - if (trim($request->getEmail()) != "") { |
|
179 | - $errorList[ValidationError::EMAIL_INVALID] = new ValidationError(ValidationError::EMAIL_INVALID); |
|
180 | - } |
|
181 | - } |
|
182 | - |
|
183 | - // email address can't be wikimedia/wikipedia .com/org |
|
184 | - if (preg_match('/.*@.*wiki(m.dia|p.dia)\.(org|com)/i', $request->getEmail()) === 1) { |
|
185 | - $errorList[ValidationError::EMAIL_WIKIMEDIA] = new ValidationError(ValidationError::EMAIL_WIKIMEDIA); |
|
186 | - } |
|
187 | - |
|
188 | - return $errorList; |
|
189 | - } |
|
190 | - |
|
191 | - /** |
|
192 | - * Summary of validateOther |
|
193 | - * |
|
194 | - * @param Request $request |
|
195 | - * |
|
196 | - * @return ValidationError[] |
|
197 | - */ |
|
198 | - public function validateOther(Request $request) |
|
199 | - { |
|
200 | - $errorList = array(); |
|
201 | - |
|
202 | - $trustedIp = $this->xffTrustProvider->getTrustedClientIp($request->getIp(), |
|
203 | - $request->getForwardedIp()); |
|
204 | - |
|
205 | - // ERRORS |
|
206 | - |
|
207 | - // TOR nodes |
|
208 | - if ($this->torExitProvider->isTorExit($trustedIp)) { |
|
209 | - $errorList[ValidationError::BANNED] = new ValidationError(ValidationError::BANNED_TOR); |
|
210 | - } |
|
211 | - |
|
212 | - // Bans |
|
213 | - if ($this->banHelper->isBlockBanned($request)) { |
|
214 | - $errorList[ValidationError::BANNED] = new ValidationError(ValidationError::BANNED); |
|
215 | - } |
|
216 | - |
|
217 | - return $errorList; |
|
218 | - } |
|
219 | - |
|
220 | - public function postSaveValidations(Request $request) |
|
221 | - { |
|
222 | - // Antispoof check |
|
223 | - $this->checkAntiSpoof($request); |
|
224 | - |
|
225 | - // Blacklist check |
|
226 | - $this->checkTitleBlacklist($request); |
|
227 | - |
|
228 | - // Add comment for form override |
|
229 | - $this->formOverride($request); |
|
230 | - |
|
231 | - $bans = $this->banHelper->getBans($request); |
|
232 | - |
|
233 | - foreach ($bans as $ban) { |
|
234 | - if ($ban->getAction() == Ban::ACTION_DROP) { |
|
235 | - $request->setStatus(RequestStatus::CLOSED); |
|
236 | - $request->save(); |
|
237 | - |
|
238 | - Logger::closeRequest($request->getDatabase(), $request, 0, null); |
|
239 | - |
|
240 | - $comment = new Comment(); |
|
241 | - $comment->setDatabase($this->database); |
|
242 | - $comment->setRequest($request->getId()); |
|
243 | - $comment->setVisibility('user'); |
|
244 | - $comment->setUser(null); |
|
245 | - |
|
246 | - $comment->setComment('Request dropped automatically due to matching rule.'); |
|
247 | - $comment->save(); |
|
248 | - } |
|
249 | - |
|
250 | - if ($ban->getAction() == Ban::ACTION_DEFER) { |
|
251 | - /** @var RequestQueue|false $targetQueue */ |
|
252 | - $targetQueue = RequestQueue::getById($ban->getTargetQueue(), $this->database); |
|
253 | - |
|
254 | - if ($targetQueue === false ) { |
|
255 | - $comment = new Comment(); |
|
256 | - $comment->setDatabase($this->database); |
|
257 | - $comment->setRequest($request->getId()); |
|
258 | - $comment->setVisibility('user'); |
|
259 | - $comment->setUser(null); |
|
260 | - |
|
261 | - $comment->setComment("This request would have been deferred automatically due to a matching rule, but the queue to defer to could not be found."); |
|
262 | - $comment->save(); |
|
263 | - } |
|
264 | - else { |
|
265 | - $this->deferRequest($request, $targetQueue, 'Request deferred automatically due to matching rule.'); |
|
266 | - } |
|
267 | - } |
|
268 | - } |
|
269 | - } |
|
270 | - |
|
271 | - private function checkAntiSpoof(Request $request) |
|
272 | - { |
|
273 | - try { |
|
274 | - if (count($this->antiSpoofProvider->getSpoofs($request->getName())) > 0) { |
|
275 | - // If there were spoofs an Admin should handle the request. |
|
276 | - // FIXME: domains! |
|
277 | - $defaultQueue = RequestQueue::getDefaultQueue($this->database, 1, RequestQueue::DEFAULT_ANTISPOOF); |
|
278 | - $this->deferRequest($request, $defaultQueue, |
|
279 | - 'Request automatically deferred due to AntiSpoof hit'); |
|
280 | - } |
|
281 | - } |
|
282 | - catch (Exception $ex) { |
|
283 | - $skippable = [ |
|
284 | - 'Contains unassigned character', |
|
285 | - 'Contains incompatible mixed scripts', |
|
286 | - 'Does not contain any letters', |
|
287 | - 'Usernames must contain one or more characters', |
|
288 | - 'Usernames cannot contain characters from different writing systems', |
|
289 | - 'Usernames cannot contain the character' |
|
290 | - ]; |
|
291 | - |
|
292 | - $skip = false; |
|
293 | - |
|
294 | - foreach ($skippable as $s) { |
|
295 | - if (strpos($ex->getMessage(), 'Encountered error while getting result: ' . $s) !== false) { |
|
296 | - $skip = true; |
|
297 | - break; |
|
298 | - } |
|
299 | - } |
|
300 | - |
|
301 | - // Only log to disk if this *isn't* a "skippable" error. |
|
302 | - if (!$skip) { |
|
303 | - ExceptionHandler::logExceptionToDisk($ex, $this->siteConfiguration); |
|
304 | - } |
|
305 | - } |
|
306 | - } |
|
307 | - |
|
308 | - private function checkTitleBlacklist(Request $request) |
|
309 | - { |
|
310 | - if ($this->titleBlacklistEnabled == 1) { |
|
311 | - try { |
|
312 | - $apiResult = $this->httpHelper->get( |
|
313 | - $this->mediawikiApiEndpoint, |
|
314 | - array( |
|
315 | - 'action' => 'titleblacklist', |
|
316 | - 'tbtitle' => $request->getName(), |
|
317 | - 'tbaction' => 'new-account', |
|
318 | - 'tbnooverride' => true, |
|
319 | - 'format' => 'php', |
|
320 | - ), |
|
321 | - [], |
|
322 | - $this->validationRemoteTimeout |
|
323 | - ); |
|
324 | - |
|
325 | - $data = unserialize($apiResult); |
|
326 | - |
|
327 | - $requestIsOk = $data['titleblacklist']['result'] == "ok"; |
|
328 | - } |
|
329 | - catch (CurlException $ex) { |
|
330 | - ExceptionHandler::logExceptionToDisk($ex, $this->siteConfiguration); |
|
331 | - |
|
332 | - // Don't kill the request, just assume it's fine. Humans can deal with it later. |
|
333 | - return; |
|
334 | - } |
|
335 | - |
|
336 | - if (!$requestIsOk) { |
|
337 | - // FIXME: domains! |
|
338 | - $defaultQueue = RequestQueue::getDefaultQueue($this->database, 1, RequestQueue::DEFAULT_TITLEBLACKLIST); |
|
339 | - |
|
340 | - $this->deferRequest($request, $defaultQueue, |
|
341 | - 'Request automatically deferred due to title blacklist hit'); |
|
342 | - } |
|
343 | - } |
|
344 | - } |
|
345 | - |
|
346 | - private function userExists(Request $request) |
|
347 | - { |
|
348 | - try { |
|
349 | - $userExists = $this->httpHelper->get( |
|
350 | - $this->mediawikiApiEndpoint, |
|
351 | - array( |
|
352 | - 'action' => 'query', |
|
353 | - 'list' => 'users', |
|
354 | - 'ususers' => $request->getName(), |
|
355 | - 'format' => 'php', |
|
356 | - ), |
|
357 | - [], |
|
358 | - $this->validationRemoteTimeout |
|
359 | - ); |
|
360 | - |
|
361 | - $ue = unserialize($userExists); |
|
362 | - if (!isset ($ue['query']['users']['0']['missing']) && isset ($ue['query']['users']['0']['userid'])) { |
|
363 | - return true; |
|
364 | - } |
|
365 | - } |
|
366 | - catch (CurlException $ex) { |
|
367 | - ExceptionHandler::logExceptionToDisk($ex, $this->siteConfiguration); |
|
368 | - |
|
369 | - // Don't kill the request, just assume it's fine. Humans can deal with it later. |
|
370 | - return false; |
|
371 | - } |
|
372 | - |
|
373 | - return false; |
|
374 | - } |
|
375 | - |
|
376 | - private function userSulExists(Request $request) |
|
377 | - { |
|
378 | - $requestName = $request->getName(); |
|
379 | - |
|
380 | - try { |
|
381 | - $userExists = $this->httpHelper->get( |
|
382 | - $this->mediawikiApiEndpoint, |
|
383 | - array( |
|
384 | - 'action' => 'query', |
|
385 | - 'meta' => 'globaluserinfo', |
|
386 | - 'guiuser' => $requestName, |
|
387 | - 'format' => 'php', |
|
388 | - ), |
|
389 | - [], |
|
390 | - $this->validationRemoteTimeout |
|
391 | - ); |
|
392 | - |
|
393 | - $ue = unserialize($userExists); |
|
394 | - if (isset ($ue['query']['globaluserinfo']['id'])) { |
|
395 | - return true; |
|
396 | - } |
|
397 | - } |
|
398 | - catch (CurlException $ex) { |
|
399 | - ExceptionHandler::logExceptionToDisk($ex, $this->siteConfiguration); |
|
400 | - |
|
401 | - // Don't kill the request, just assume it's fine. Humans can deal with it later. |
|
402 | - return false; |
|
403 | - } |
|
404 | - |
|
405 | - return false; |
|
406 | - } |
|
407 | - |
|
408 | - /** |
|
409 | - * Checks if a request with this name is currently open |
|
410 | - * |
|
411 | - * @param Request $request |
|
412 | - * |
|
413 | - * @return bool |
|
414 | - */ |
|
415 | - private function nameRequestExists(Request $request) |
|
416 | - { |
|
417 | - $query = "SELECT COUNT(id) FROM request WHERE status != 'Closed' AND name = :name;"; |
|
418 | - $statement = $this->database->prepare($query); |
|
419 | - $statement->execute(array(':name' => $request->getName())); |
|
420 | - |
|
421 | - if (!$statement) { |
|
422 | - return false; |
|
423 | - } |
|
424 | - |
|
425 | - return $statement->fetchColumn() > 0; |
|
426 | - } |
|
427 | - |
|
428 | - private function deferRequest(Request $request, RequestQueue $targetQueue, $deferComment): void |
|
429 | - { |
|
430 | - $request->setQueue($targetQueue->getId()); |
|
431 | - $request->save(); |
|
432 | - |
|
433 | - $logTarget = $targetQueue->getLogName(); |
|
434 | - |
|
435 | - Logger::deferRequest($this->database, $request, $logTarget); |
|
436 | - |
|
437 | - $comment = new Comment(); |
|
438 | - $comment->setDatabase($this->database); |
|
439 | - $comment->setRequest($request->getId()); |
|
440 | - $comment->setVisibility('user'); |
|
441 | - $comment->setUser(null); |
|
442 | - |
|
443 | - $comment->setComment($deferComment); |
|
444 | - $comment->save(); |
|
445 | - } |
|
446 | - |
|
447 | - private function formOverride(Request $request) |
|
448 | - { |
|
449 | - $form = $request->getOriginFormObject(); |
|
450 | - if($form === null || $form->getOverrideQueue() === null) { |
|
451 | - return; |
|
452 | - } |
|
453 | - |
|
454 | - /** @var RequestQueue $targetQueue */ |
|
455 | - $targetQueue = RequestQueue::getById($form->getOverrideQueue(), $request->getDatabase()); |
|
456 | - |
|
457 | - $this->deferRequest($request, $targetQueue, 'Request deferred automatically due to request submission through a request form with a default queue set.'); |
|
458 | - } |
|
34 | + /** @var IBanHelper */ |
|
35 | + private $banHelper; |
|
36 | + /** @var PdoDatabase */ |
|
37 | + private $database; |
|
38 | + /** @var IAntiSpoofProvider */ |
|
39 | + private $antiSpoofProvider; |
|
40 | + /** @var IXffTrustProvider */ |
|
41 | + private $xffTrustProvider; |
|
42 | + /** @var HttpHelper */ |
|
43 | + private $httpHelper; |
|
44 | + /** |
|
45 | + * @var string |
|
46 | + */ |
|
47 | + private $mediawikiApiEndpoint; |
|
48 | + private $titleBlacklistEnabled; |
|
49 | + /** |
|
50 | + * @var TorExitProvider |
|
51 | + */ |
|
52 | + private $torExitProvider; |
|
53 | + /** |
|
54 | + * @var SiteConfiguration |
|
55 | + */ |
|
56 | + private $siteConfiguration; |
|
57 | + |
|
58 | + private $validationRemoteTimeout = 5000; |
|
59 | + |
|
60 | + /** |
|
61 | + * Summary of __construct |
|
62 | + * |
|
63 | + * @param IBanHelper $banHelper |
|
64 | + * @param PdoDatabase $database |
|
65 | + * @param IAntiSpoofProvider $antiSpoofProvider |
|
66 | + * @param IXffTrustProvider $xffTrustProvider |
|
67 | + * @param HttpHelper $httpHelper |
|
68 | + * @param TorExitProvider $torExitProvider |
|
69 | + * @param SiteConfiguration $siteConfiguration |
|
70 | + */ |
|
71 | + public function __construct( |
|
72 | + IBanHelper $banHelper, |
|
73 | + PdoDatabase $database, |
|
74 | + IAntiSpoofProvider $antiSpoofProvider, |
|
75 | + IXffTrustProvider $xffTrustProvider, |
|
76 | + HttpHelper $httpHelper, |
|
77 | + TorExitProvider $torExitProvider, |
|
78 | + SiteConfiguration $siteConfiguration |
|
79 | + ) { |
|
80 | + $this->banHelper = $banHelper; |
|
81 | + $this->database = $database; |
|
82 | + $this->antiSpoofProvider = $antiSpoofProvider; |
|
83 | + $this->xffTrustProvider = $xffTrustProvider; |
|
84 | + $this->httpHelper = $httpHelper; |
|
85 | + |
|
86 | + // FIXME: domains! |
|
87 | + /** @var Domain $domain */ |
|
88 | + $domain = Domain::getById(1, $database); |
|
89 | + |
|
90 | + $this->mediawikiApiEndpoint = $domain->getWikiApiPath(); |
|
91 | + $this->titleBlacklistEnabled = $siteConfiguration->getTitleBlacklistEnabled(); |
|
92 | + $this->torExitProvider = $torExitProvider; |
|
93 | + $this->siteConfiguration = $siteConfiguration; |
|
94 | + } |
|
95 | + |
|
96 | + /** |
|
97 | + * Summary of validateName |
|
98 | + * |
|
99 | + * @param Request $request |
|
100 | + * |
|
101 | + * @return ValidationError[] |
|
102 | + */ |
|
103 | + public function validateName(Request $request) |
|
104 | + { |
|
105 | + $errorList = array(); |
|
106 | + |
|
107 | + // ERRORS |
|
108 | + // name is empty |
|
109 | + if (trim($request->getName()) == "") { |
|
110 | + $errorList[ValidationError::NAME_EMPTY] = new ValidationError(ValidationError::NAME_EMPTY); |
|
111 | + } |
|
112 | + |
|
113 | + // name is too long |
|
114 | + if (mb_strlen(trim($request->getName())) > 500) { |
|
115 | + $errorList[ValidationError::NAME_EMPTY] = new ValidationError(ValidationError::NAME_TOO_LONG); |
|
116 | + } |
|
117 | + |
|
118 | + // username already exists |
|
119 | + if ($this->userExists($request)) { |
|
120 | + $errorList[ValidationError::NAME_EXISTS] = new ValidationError(ValidationError::NAME_EXISTS); |
|
121 | + } |
|
122 | + |
|
123 | + // username part of SUL account |
|
124 | + if ($this->userSulExists($request)) { |
|
125 | + // using same error slot as name exists - it's the same sort of error, and we probably only want to show one. |
|
126 | + $errorList[ValidationError::NAME_EXISTS] = new ValidationError(ValidationError::NAME_EXISTS_SUL); |
|
127 | + } |
|
128 | + |
|
129 | + // username is numbers |
|
130 | + if (preg_match("/^[0-9]+$/", $request->getName()) === 1) { |
|
131 | + $errorList[ValidationError::NAME_NUMONLY] = new ValidationError(ValidationError::NAME_NUMONLY); |
|
132 | + } |
|
133 | + |
|
134 | + // username can't contain #@/<>[]|{} |
|
135 | + if (preg_match("/[" . preg_quote("#@/<>[]|{}", "/") . "]/", $request->getName()) === 1) { |
|
136 | + $errorList[ValidationError::NAME_INVALIDCHAR] = new ValidationError(ValidationError::NAME_INVALIDCHAR); |
|
137 | + } |
|
138 | + |
|
139 | + // username is an IP |
|
140 | + if (filter_var($request->getName(), FILTER_VALIDATE_IP)) { |
|
141 | + $errorList[ValidationError::NAME_IP] = new ValidationError(ValidationError::NAME_IP); |
|
142 | + } |
|
143 | + |
|
144 | + // existing non-closed request for this name |
|
145 | + if ($this->nameRequestExists($request)) { |
|
146 | + $errorList[ValidationError::OPEN_REQUEST_NAME] = new ValidationError(ValidationError::OPEN_REQUEST_NAME); |
|
147 | + } |
|
148 | + |
|
149 | + return $errorList; |
|
150 | + } |
|
151 | + |
|
152 | + /** |
|
153 | + * Summary of validateEmail |
|
154 | + * |
|
155 | + * @param Request $request |
|
156 | + * @param string $emailConfirmation |
|
157 | + * |
|
158 | + * @return ValidationError[] |
|
159 | + */ |
|
160 | + public function validateEmail(Request $request, $emailConfirmation) |
|
161 | + { |
|
162 | + $errorList = array(); |
|
163 | + |
|
164 | + // ERRORS |
|
165 | + |
|
166 | + // email addresses must match |
|
167 | + if ($request->getEmail() != $emailConfirmation) { |
|
168 | + $errorList[ValidationError::EMAIL_MISMATCH] = new ValidationError(ValidationError::EMAIL_MISMATCH); |
|
169 | + } |
|
170 | + |
|
171 | + // email address must be validly formed |
|
172 | + if (trim($request->getEmail()) == "") { |
|
173 | + $errorList[ValidationError::EMAIL_EMPTY] = new ValidationError(ValidationError::EMAIL_EMPTY); |
|
174 | + } |
|
175 | + |
|
176 | + // email address must be validly formed |
|
177 | + if (!filter_var($request->getEmail(), FILTER_VALIDATE_EMAIL)) { |
|
178 | + if (trim($request->getEmail()) != "") { |
|
179 | + $errorList[ValidationError::EMAIL_INVALID] = new ValidationError(ValidationError::EMAIL_INVALID); |
|
180 | + } |
|
181 | + } |
|
182 | + |
|
183 | + // email address can't be wikimedia/wikipedia .com/org |
|
184 | + if (preg_match('/.*@.*wiki(m.dia|p.dia)\.(org|com)/i', $request->getEmail()) === 1) { |
|
185 | + $errorList[ValidationError::EMAIL_WIKIMEDIA] = new ValidationError(ValidationError::EMAIL_WIKIMEDIA); |
|
186 | + } |
|
187 | + |
|
188 | + return $errorList; |
|
189 | + } |
|
190 | + |
|
191 | + /** |
|
192 | + * Summary of validateOther |
|
193 | + * |
|
194 | + * @param Request $request |
|
195 | + * |
|
196 | + * @return ValidationError[] |
|
197 | + */ |
|
198 | + public function validateOther(Request $request) |
|
199 | + { |
|
200 | + $errorList = array(); |
|
201 | + |
|
202 | + $trustedIp = $this->xffTrustProvider->getTrustedClientIp($request->getIp(), |
|
203 | + $request->getForwardedIp()); |
|
204 | + |
|
205 | + // ERRORS |
|
206 | + |
|
207 | + // TOR nodes |
|
208 | + if ($this->torExitProvider->isTorExit($trustedIp)) { |
|
209 | + $errorList[ValidationError::BANNED] = new ValidationError(ValidationError::BANNED_TOR); |
|
210 | + } |
|
211 | + |
|
212 | + // Bans |
|
213 | + if ($this->banHelper->isBlockBanned($request)) { |
|
214 | + $errorList[ValidationError::BANNED] = new ValidationError(ValidationError::BANNED); |
|
215 | + } |
|
216 | + |
|
217 | + return $errorList; |
|
218 | + } |
|
219 | + |
|
220 | + public function postSaveValidations(Request $request) |
|
221 | + { |
|
222 | + // Antispoof check |
|
223 | + $this->checkAntiSpoof($request); |
|
224 | + |
|
225 | + // Blacklist check |
|
226 | + $this->checkTitleBlacklist($request); |
|
227 | + |
|
228 | + // Add comment for form override |
|
229 | + $this->formOverride($request); |
|
230 | + |
|
231 | + $bans = $this->banHelper->getBans($request); |
|
232 | + |
|
233 | + foreach ($bans as $ban) { |
|
234 | + if ($ban->getAction() == Ban::ACTION_DROP) { |
|
235 | + $request->setStatus(RequestStatus::CLOSED); |
|
236 | + $request->save(); |
|
237 | + |
|
238 | + Logger::closeRequest($request->getDatabase(), $request, 0, null); |
|
239 | + |
|
240 | + $comment = new Comment(); |
|
241 | + $comment->setDatabase($this->database); |
|
242 | + $comment->setRequest($request->getId()); |
|
243 | + $comment->setVisibility('user'); |
|
244 | + $comment->setUser(null); |
|
245 | + |
|
246 | + $comment->setComment('Request dropped automatically due to matching rule.'); |
|
247 | + $comment->save(); |
|
248 | + } |
|
249 | + |
|
250 | + if ($ban->getAction() == Ban::ACTION_DEFER) { |
|
251 | + /** @var RequestQueue|false $targetQueue */ |
|
252 | + $targetQueue = RequestQueue::getById($ban->getTargetQueue(), $this->database); |
|
253 | + |
|
254 | + if ($targetQueue === false ) { |
|
255 | + $comment = new Comment(); |
|
256 | + $comment->setDatabase($this->database); |
|
257 | + $comment->setRequest($request->getId()); |
|
258 | + $comment->setVisibility('user'); |
|
259 | + $comment->setUser(null); |
|
260 | + |
|
261 | + $comment->setComment("This request would have been deferred automatically due to a matching rule, but the queue to defer to could not be found."); |
|
262 | + $comment->save(); |
|
263 | + } |
|
264 | + else { |
|
265 | + $this->deferRequest($request, $targetQueue, 'Request deferred automatically due to matching rule.'); |
|
266 | + } |
|
267 | + } |
|
268 | + } |
|
269 | + } |
|
270 | + |
|
271 | + private function checkAntiSpoof(Request $request) |
|
272 | + { |
|
273 | + try { |
|
274 | + if (count($this->antiSpoofProvider->getSpoofs($request->getName())) > 0) { |
|
275 | + // If there were spoofs an Admin should handle the request. |
|
276 | + // FIXME: domains! |
|
277 | + $defaultQueue = RequestQueue::getDefaultQueue($this->database, 1, RequestQueue::DEFAULT_ANTISPOOF); |
|
278 | + $this->deferRequest($request, $defaultQueue, |
|
279 | + 'Request automatically deferred due to AntiSpoof hit'); |
|
280 | + } |
|
281 | + } |
|
282 | + catch (Exception $ex) { |
|
283 | + $skippable = [ |
|
284 | + 'Contains unassigned character', |
|
285 | + 'Contains incompatible mixed scripts', |
|
286 | + 'Does not contain any letters', |
|
287 | + 'Usernames must contain one or more characters', |
|
288 | + 'Usernames cannot contain characters from different writing systems', |
|
289 | + 'Usernames cannot contain the character' |
|
290 | + ]; |
|
291 | + |
|
292 | + $skip = false; |
|
293 | + |
|
294 | + foreach ($skippable as $s) { |
|
295 | + if (strpos($ex->getMessage(), 'Encountered error while getting result: ' . $s) !== false) { |
|
296 | + $skip = true; |
|
297 | + break; |
|
298 | + } |
|
299 | + } |
|
300 | + |
|
301 | + // Only log to disk if this *isn't* a "skippable" error. |
|
302 | + if (!$skip) { |
|
303 | + ExceptionHandler::logExceptionToDisk($ex, $this->siteConfiguration); |
|
304 | + } |
|
305 | + } |
|
306 | + } |
|
307 | + |
|
308 | + private function checkTitleBlacklist(Request $request) |
|
309 | + { |
|
310 | + if ($this->titleBlacklistEnabled == 1) { |
|
311 | + try { |
|
312 | + $apiResult = $this->httpHelper->get( |
|
313 | + $this->mediawikiApiEndpoint, |
|
314 | + array( |
|
315 | + 'action' => 'titleblacklist', |
|
316 | + 'tbtitle' => $request->getName(), |
|
317 | + 'tbaction' => 'new-account', |
|
318 | + 'tbnooverride' => true, |
|
319 | + 'format' => 'php', |
|
320 | + ), |
|
321 | + [], |
|
322 | + $this->validationRemoteTimeout |
|
323 | + ); |
|
324 | + |
|
325 | + $data = unserialize($apiResult); |
|
326 | + |
|
327 | + $requestIsOk = $data['titleblacklist']['result'] == "ok"; |
|
328 | + } |
|
329 | + catch (CurlException $ex) { |
|
330 | + ExceptionHandler::logExceptionToDisk($ex, $this->siteConfiguration); |
|
331 | + |
|
332 | + // Don't kill the request, just assume it's fine. Humans can deal with it later. |
|
333 | + return; |
|
334 | + } |
|
335 | + |
|
336 | + if (!$requestIsOk) { |
|
337 | + // FIXME: domains! |
|
338 | + $defaultQueue = RequestQueue::getDefaultQueue($this->database, 1, RequestQueue::DEFAULT_TITLEBLACKLIST); |
|
339 | + |
|
340 | + $this->deferRequest($request, $defaultQueue, |
|
341 | + 'Request automatically deferred due to title blacklist hit'); |
|
342 | + } |
|
343 | + } |
|
344 | + } |
|
345 | + |
|
346 | + private function userExists(Request $request) |
|
347 | + { |
|
348 | + try { |
|
349 | + $userExists = $this->httpHelper->get( |
|
350 | + $this->mediawikiApiEndpoint, |
|
351 | + array( |
|
352 | + 'action' => 'query', |
|
353 | + 'list' => 'users', |
|
354 | + 'ususers' => $request->getName(), |
|
355 | + 'format' => 'php', |
|
356 | + ), |
|
357 | + [], |
|
358 | + $this->validationRemoteTimeout |
|
359 | + ); |
|
360 | + |
|
361 | + $ue = unserialize($userExists); |
|
362 | + if (!isset ($ue['query']['users']['0']['missing']) && isset ($ue['query']['users']['0']['userid'])) { |
|
363 | + return true; |
|
364 | + } |
|
365 | + } |
|
366 | + catch (CurlException $ex) { |
|
367 | + ExceptionHandler::logExceptionToDisk($ex, $this->siteConfiguration); |
|
368 | + |
|
369 | + // Don't kill the request, just assume it's fine. Humans can deal with it later. |
|
370 | + return false; |
|
371 | + } |
|
372 | + |
|
373 | + return false; |
|
374 | + } |
|
375 | + |
|
376 | + private function userSulExists(Request $request) |
|
377 | + { |
|
378 | + $requestName = $request->getName(); |
|
379 | + |
|
380 | + try { |
|
381 | + $userExists = $this->httpHelper->get( |
|
382 | + $this->mediawikiApiEndpoint, |
|
383 | + array( |
|
384 | + 'action' => 'query', |
|
385 | + 'meta' => 'globaluserinfo', |
|
386 | + 'guiuser' => $requestName, |
|
387 | + 'format' => 'php', |
|
388 | + ), |
|
389 | + [], |
|
390 | + $this->validationRemoteTimeout |
|
391 | + ); |
|
392 | + |
|
393 | + $ue = unserialize($userExists); |
|
394 | + if (isset ($ue['query']['globaluserinfo']['id'])) { |
|
395 | + return true; |
|
396 | + } |
|
397 | + } |
|
398 | + catch (CurlException $ex) { |
|
399 | + ExceptionHandler::logExceptionToDisk($ex, $this->siteConfiguration); |
|
400 | + |
|
401 | + // Don't kill the request, just assume it's fine. Humans can deal with it later. |
|
402 | + return false; |
|
403 | + } |
|
404 | + |
|
405 | + return false; |
|
406 | + } |
|
407 | + |
|
408 | + /** |
|
409 | + * Checks if a request with this name is currently open |
|
410 | + * |
|
411 | + * @param Request $request |
|
412 | + * |
|
413 | + * @return bool |
|
414 | + */ |
|
415 | + private function nameRequestExists(Request $request) |
|
416 | + { |
|
417 | + $query = "SELECT COUNT(id) FROM request WHERE status != 'Closed' AND name = :name;"; |
|
418 | + $statement = $this->database->prepare($query); |
|
419 | + $statement->execute(array(':name' => $request->getName())); |
|
420 | + |
|
421 | + if (!$statement) { |
|
422 | + return false; |
|
423 | + } |
|
424 | + |
|
425 | + return $statement->fetchColumn() > 0; |
|
426 | + } |
|
427 | + |
|
428 | + private function deferRequest(Request $request, RequestQueue $targetQueue, $deferComment): void |
|
429 | + { |
|
430 | + $request->setQueue($targetQueue->getId()); |
|
431 | + $request->save(); |
|
432 | + |
|
433 | + $logTarget = $targetQueue->getLogName(); |
|
434 | + |
|
435 | + Logger::deferRequest($this->database, $request, $logTarget); |
|
436 | + |
|
437 | + $comment = new Comment(); |
|
438 | + $comment->setDatabase($this->database); |
|
439 | + $comment->setRequest($request->getId()); |
|
440 | + $comment->setVisibility('user'); |
|
441 | + $comment->setUser(null); |
|
442 | + |
|
443 | + $comment->setComment($deferComment); |
|
444 | + $comment->save(); |
|
445 | + } |
|
446 | + |
|
447 | + private function formOverride(Request $request) |
|
448 | + { |
|
449 | + $form = $request->getOriginFormObject(); |
|
450 | + if($form === null || $form->getOverrideQueue() === null) { |
|
451 | + return; |
|
452 | + } |
|
453 | + |
|
454 | + /** @var RequestQueue $targetQueue */ |
|
455 | + $targetQueue = RequestQueue::getById($form->getOverrideQueue(), $request->getDatabase()); |
|
456 | + |
|
457 | + $this->deferRequest($request, $targetQueue, 'Request deferred automatically due to request submission through a request form with a default queue set.'); |
|
458 | + } |
|
459 | 459 | } |
@@ -251,7 +251,7 @@ discard block |
||
251 | 251 | /** @var RequestQueue|false $targetQueue */ |
252 | 252 | $targetQueue = RequestQueue::getById($ban->getTargetQueue(), $this->database); |
253 | 253 | |
254 | - if ($targetQueue === false ) { |
|
254 | + if ($targetQueue === false) { |
|
255 | 255 | $comment = new Comment(); |
256 | 256 | $comment->setDatabase($this->database); |
257 | 257 | $comment->setRequest($request->getId()); |
@@ -447,7 +447,7 @@ discard block |
||
447 | 447 | private function formOverride(Request $request) |
448 | 448 | { |
449 | 449 | $form = $request->getOriginFormObject(); |
450 | - if($form === null || $form->getOverrideQueue() === null) { |
|
450 | + if ($form === null || $form->getOverrideQueue() === null) { |
|
451 | 451 | return; |
452 | 452 | } |
453 | 453 |
@@ -260,8 +260,7 @@ |
||
260 | 260 | |
261 | 261 | $comment->setComment("This request would have been deferred automatically due to a matching rule, but the queue to defer to could not be found."); |
262 | 262 | $comment->save(); |
263 | - } |
|
264 | - else { |
|
263 | + } else { |
|
265 | 264 | $this->deferRequest($request, $targetQueue, 'Request deferred automatically due to matching rule.'); |
266 | 265 | } |
267 | 266 | } |
@@ -22,258 +22,258 @@ |
||
22 | 22 | |
23 | 23 | class PageWelcomeTemplateManagement extends InternalPageBase |
24 | 24 | { |
25 | - /** |
|
26 | - * Main function for this page, when no specific actions are called. |
|
27 | - * @return void |
|
28 | - */ |
|
29 | - protected function main() |
|
30 | - { |
|
31 | - $database = $this->getDatabase(); |
|
32 | - $templateList = WelcomeTemplate::getAll($database, 1); // FIXME: domains |
|
33 | - $preferenceManager = PreferenceManager::getForCurrent($database); |
|
25 | + /** |
|
26 | + * Main function for this page, when no specific actions are called. |
|
27 | + * @return void |
|
28 | + */ |
|
29 | + protected function main() |
|
30 | + { |
|
31 | + $database = $this->getDatabase(); |
|
32 | + $templateList = WelcomeTemplate::getAll($database, 1); // FIXME: domains |
|
33 | + $preferenceManager = PreferenceManager::getForCurrent($database); |
|
34 | 34 | |
35 | - $this->setHtmlTitle('Welcome Templates'); |
|
35 | + $this->setHtmlTitle('Welcome Templates'); |
|
36 | 36 | |
37 | - $this->assignCSRFToken(); |
|
37 | + $this->assignCSRFToken(); |
|
38 | 38 | |
39 | - $user = User::getCurrent($database); |
|
39 | + $user = User::getCurrent($database); |
|
40 | 40 | |
41 | - $currentTemplate = $preferenceManager->getPreference(PreferenceManager::PREF_WELCOMETEMPLATE); |
|
42 | - $this->assign('currentTemplate', $currentTemplate); |
|
41 | + $currentTemplate = $preferenceManager->getPreference(PreferenceManager::PREF_WELCOMETEMPLATE); |
|
42 | + $this->assign('currentTemplate', $currentTemplate); |
|
43 | 43 | |
44 | - $this->assign('canEdit', $this->barrierTest('edit', $user)); |
|
45 | - $this->assign('canAdd', $this->barrierTest('add', $user)); |
|
46 | - $this->assign('canSelect', $this->barrierTest('select', $user)); |
|
44 | + $this->assign('canEdit', $this->barrierTest('edit', $user)); |
|
45 | + $this->assign('canAdd', $this->barrierTest('add', $user)); |
|
46 | + $this->assign('canSelect', $this->barrierTest('select', $user)); |
|
47 | 47 | |
48 | - $this->assign('templateList', $templateList); |
|
49 | - $this->setTemplate('welcome-template/list.tpl'); |
|
50 | - } |
|
48 | + $this->assign('templateList', $templateList); |
|
49 | + $this->setTemplate('welcome-template/list.tpl'); |
|
50 | + } |
|
51 | 51 | |
52 | - /** |
|
53 | - * Handles the requests for selecting a template to use. |
|
54 | - * |
|
55 | - * @throws ApplicationLogicException |
|
56 | - */ |
|
57 | - protected function select() |
|
58 | - { |
|
59 | - // get rid of GETs |
|
60 | - if (!WebRequest::wasPosted()) { |
|
61 | - $this->redirect('welcomeTemplates'); |
|
62 | - } |
|
52 | + /** |
|
53 | + * Handles the requests for selecting a template to use. |
|
54 | + * |
|
55 | + * @throws ApplicationLogicException |
|
56 | + */ |
|
57 | + protected function select() |
|
58 | + { |
|
59 | + // get rid of GETs |
|
60 | + if (!WebRequest::wasPosted()) { |
|
61 | + $this->redirect('welcomeTemplates'); |
|
62 | + } |
|
63 | 63 | |
64 | - $this->validateCSRFToken(); |
|
64 | + $this->validateCSRFToken(); |
|
65 | 65 | |
66 | - $database = $this->getDatabase(); |
|
67 | - $user = User::getCurrent($database); |
|
68 | - $preferenceManager = PreferenceManager::getForCurrent($database); |
|
66 | + $database = $this->getDatabase(); |
|
67 | + $user = User::getCurrent($database); |
|
68 | + $preferenceManager = PreferenceManager::getForCurrent($database); |
|
69 | 69 | |
70 | - if (WebRequest::postBoolean('disable')) { |
|
71 | - $preferenceManager->setLocalPreference(PreferenceManager::PREF_WELCOMETEMPLATE, null); |
|
70 | + if (WebRequest::postBoolean('disable')) { |
|
71 | + $preferenceManager->setLocalPreference(PreferenceManager::PREF_WELCOMETEMPLATE, null); |
|
72 | 72 | |
73 | - SessionAlert::success('Disabled automatic user welcoming.'); |
|
74 | - $this->redirect('welcomeTemplates'); |
|
73 | + SessionAlert::success('Disabled automatic user welcoming.'); |
|
74 | + $this->redirect('welcomeTemplates'); |
|
75 | 75 | |
76 | - return; |
|
77 | - } |
|
76 | + return; |
|
77 | + } |
|
78 | 78 | |
79 | - $templateId = WebRequest::postInt('template'); |
|
80 | - /** @var false|WelcomeTemplate $template */ |
|
81 | - $template = WelcomeTemplate::getById($templateId, $database); |
|
79 | + $templateId = WebRequest::postInt('template'); |
|
80 | + /** @var false|WelcomeTemplate $template */ |
|
81 | + $template = WelcomeTemplate::getById($templateId, $database); |
|
82 | 82 | |
83 | - if ($template === false || $template->isDeleted()) { |
|
84 | - throw new ApplicationLogicException('Unknown template'); |
|
85 | - } |
|
83 | + if ($template === false || $template->isDeleted()) { |
|
84 | + throw new ApplicationLogicException('Unknown template'); |
|
85 | + } |
|
86 | 86 | |
87 | - $preferenceManager->setLocalPreference(PreferenceManager::PREF_WELCOMETEMPLATE, $template->getId()); |
|
87 | + $preferenceManager->setLocalPreference(PreferenceManager::PREF_WELCOMETEMPLATE, $template->getId()); |
|
88 | 88 | |
89 | - SessionAlert::success("Updated selected welcome template for automatic welcoming."); |
|
89 | + SessionAlert::success("Updated selected welcome template for automatic welcoming."); |
|
90 | 90 | |
91 | - $this->redirect('welcomeTemplates'); |
|
92 | - } |
|
91 | + $this->redirect('welcomeTemplates'); |
|
92 | + } |
|
93 | 93 | |
94 | - /** |
|
95 | - * Handles the requests for viewing a template. |
|
96 | - * |
|
97 | - * @throws ApplicationLogicException |
|
98 | - */ |
|
99 | - protected function view() |
|
100 | - { |
|
101 | - $this->setHtmlTitle('View Welcome Template'); |
|
94 | + /** |
|
95 | + * Handles the requests for viewing a template. |
|
96 | + * |
|
97 | + * @throws ApplicationLogicException |
|
98 | + */ |
|
99 | + protected function view() |
|
100 | + { |
|
101 | + $this->setHtmlTitle('View Welcome Template'); |
|
102 | 102 | |
103 | - $database = $this->getDatabase(); |
|
103 | + $database = $this->getDatabase(); |
|
104 | 104 | |
105 | - $templateId = WebRequest::getInt('template'); |
|
105 | + $templateId = WebRequest::getInt('template'); |
|
106 | 106 | |
107 | - /** @var false|WelcomeTemplate $template */ |
|
108 | - $template = WelcomeTemplate::getById($templateId, $database); |
|
107 | + /** @var false|WelcomeTemplate $template */ |
|
108 | + $template = WelcomeTemplate::getById($templateId, $database); |
|
109 | 109 | |
110 | - if ($template === false) { |
|
111 | - throw new ApplicationLogicException('Cannot find requested template'); |
|
112 | - } |
|
110 | + if ($template === false) { |
|
111 | + throw new ApplicationLogicException('Cannot find requested template'); |
|
112 | + } |
|
113 | 113 | |
114 | - $currentUser = User::getCurrent($database); |
|
114 | + $currentUser = User::getCurrent($database); |
|
115 | 115 | |
116 | - // This includes a section header, because we use the "new section" API call. |
|
117 | - $wikiText = "== " . $template->getSectionHeader() . "==\n" . $template->getBotCodeForWikiSave('Example User', $currentUser->getOnWikiName()); |
|
116 | + // This includes a section header, because we use the "new section" API call. |
|
117 | + $wikiText = "== " . $template->getSectionHeader() . "==\n" . $template->getBotCodeForWikiSave('Example User', $currentUser->getOnWikiName()); |
|
118 | 118 | |
119 | - $oauth = new OAuthUserHelper($currentUser, $database, $this->getOauthProtocolHelper(), |
|
120 | - $this->getSiteConfiguration()); |
|
121 | - $mediaWikiHelper = new MediaWikiHelper($oauth, $this->getSiteConfiguration()); |
|
119 | + $oauth = new OAuthUserHelper($currentUser, $database, $this->getOauthProtocolHelper(), |
|
120 | + $this->getSiteConfiguration()); |
|
121 | + $mediaWikiHelper = new MediaWikiHelper($oauth, $this->getSiteConfiguration()); |
|
122 | 122 | |
123 | - $templateHtml = $mediaWikiHelper->getHtmlForWikiText($wikiText); |
|
123 | + $templateHtml = $mediaWikiHelper->getHtmlForWikiText($wikiText); |
|
124 | 124 | |
125 | - // Add site to relevant links, since the MediaWiki parser returns, eg, `/wiki/Help:Introduction` |
|
126 | - // and we want to link to <https://en.wikipedia.org/wiki/Help:Introduction> rather than |
|
127 | - // <https://accounts.wmflabs.org/wiki/Help:Introduction> |
|
128 | - // The code currently assumes that the template was parsed for enwiki, and will need to be |
|
129 | - // updated once other wikis are supported. |
|
130 | - $templateHtml = preg_replace('/(<a href=")(\/wiki\/)/', '$1//en.wikipedia.org$2', $templateHtml); |
|
131 | - |
|
132 | - $this->assign('templateHtml', $templateHtml); |
|
133 | - $this->assign('template', $template); |
|
134 | - $this->setTemplate('welcome-template/view.tpl'); |
|
135 | - } |
|
136 | - |
|
137 | - /** |
|
138 | - * Handler for the add action to create a new welcome template |
|
139 | - * |
|
140 | - * @throws Exception |
|
141 | - */ |
|
142 | - protected function add() |
|
143 | - { |
|
144 | - $this->assign('createmode', true); |
|
125 | + // Add site to relevant links, since the MediaWiki parser returns, eg, `/wiki/Help:Introduction` |
|
126 | + // and we want to link to <https://en.wikipedia.org/wiki/Help:Introduction> rather than |
|
127 | + // <https://accounts.wmflabs.org/wiki/Help:Introduction> |
|
128 | + // The code currently assumes that the template was parsed for enwiki, and will need to be |
|
129 | + // updated once other wikis are supported. |
|
130 | + $templateHtml = preg_replace('/(<a href=")(\/wiki\/)/', '$1//en.wikipedia.org$2', $templateHtml); |
|
131 | + |
|
132 | + $this->assign('templateHtml', $templateHtml); |
|
133 | + $this->assign('template', $template); |
|
134 | + $this->setTemplate('welcome-template/view.tpl'); |
|
135 | + } |
|
136 | + |
|
137 | + /** |
|
138 | + * Handler for the add action to create a new welcome template |
|
139 | + * |
|
140 | + * @throws Exception |
|
141 | + */ |
|
142 | + protected function add() |
|
143 | + { |
|
144 | + $this->assign('createmode', true); |
|
145 | 145 | |
146 | - if (WebRequest::wasPosted()) { |
|
147 | - $this->validateCSRFToken(); |
|
148 | - $database = $this->getDatabase(); |
|
146 | + if (WebRequest::wasPosted()) { |
|
147 | + $this->validateCSRFToken(); |
|
148 | + $database = $this->getDatabase(); |
|
149 | 149 | |
150 | - $userCode = WebRequest::postString('usercode'); |
|
151 | - $botCode = WebRequest::postString('botcode'); |
|
150 | + $userCode = WebRequest::postString('usercode'); |
|
151 | + $botCode = WebRequest::postString('botcode'); |
|
152 | 152 | |
153 | - $this->validate($userCode, $botCode); |
|
153 | + $this->validate($userCode, $botCode); |
|
154 | 154 | |
155 | - $template = new WelcomeTemplate(); |
|
156 | - $template->setDatabase($database); |
|
157 | - $template->setUserCode($userCode); |
|
158 | - $template->setBotCode($botCode); |
|
159 | - $template->setDomain(1); // FIXME: domains! |
|
160 | - $template->save(); |
|
155 | + $template = new WelcomeTemplate(); |
|
156 | + $template->setDatabase($database); |
|
157 | + $template->setUserCode($userCode); |
|
158 | + $template->setBotCode($botCode); |
|
159 | + $template->setDomain(1); // FIXME: domains! |
|
160 | + $template->save(); |
|
161 | 161 | |
162 | - Logger::welcomeTemplateCreated($database, $template); |
|
162 | + Logger::welcomeTemplateCreated($database, $template); |
|
163 | 163 | |
164 | - $this->getNotificationHelper()->welcomeTemplateCreated($template); |
|
164 | + $this->getNotificationHelper()->welcomeTemplateCreated($template); |
|
165 | 165 | |
166 | - SessionAlert::success("Template successfully created."); |
|
166 | + SessionAlert::success("Template successfully created."); |
|
167 | 167 | |
168 | - $this->redirect('welcomeTemplates'); |
|
169 | - } |
|
170 | - else { |
|
171 | - $this->assignCSRFToken(); |
|
172 | - $this->assign('template', new WelcomeTemplate()); |
|
173 | - $this->setTemplate("welcome-template/edit.tpl"); |
|
174 | - } |
|
175 | - } |
|
168 | + $this->redirect('welcomeTemplates'); |
|
169 | + } |
|
170 | + else { |
|
171 | + $this->assignCSRFToken(); |
|
172 | + $this->assign('template', new WelcomeTemplate()); |
|
173 | + $this->setTemplate("welcome-template/edit.tpl"); |
|
174 | + } |
|
175 | + } |
|
176 | 176 | |
177 | - /** |
|
178 | - * Handler for editing templates |
|
179 | - */ |
|
180 | - protected function edit() |
|
181 | - { |
|
182 | - $database = $this->getDatabase(); |
|
177 | + /** |
|
178 | + * Handler for editing templates |
|
179 | + */ |
|
180 | + protected function edit() |
|
181 | + { |
|
182 | + $database = $this->getDatabase(); |
|
183 | 183 | |
184 | - $templateId = WebRequest::getInt('template'); |
|
184 | + $templateId = WebRequest::getInt('template'); |
|
185 | 185 | |
186 | - /** @var false|WelcomeTemplate $template */ |
|
187 | - $template = WelcomeTemplate::getById($templateId, $database); |
|
186 | + /** @var false|WelcomeTemplate $template */ |
|
187 | + $template = WelcomeTemplate::getById($templateId, $database); |
|
188 | 188 | |
189 | - if ($template === false) { |
|
190 | - throw new ApplicationLogicException('Cannot find requested template'); |
|
191 | - } |
|
189 | + if ($template === false) { |
|
190 | + throw new ApplicationLogicException('Cannot find requested template'); |
|
191 | + } |
|
192 | 192 | |
193 | - if ($template->isDeleted()) { |
|
194 | - throw new ApplicationLogicException('The specified template has been deleted'); |
|
195 | - } |
|
193 | + if ($template->isDeleted()) { |
|
194 | + throw new ApplicationLogicException('The specified template has been deleted'); |
|
195 | + } |
|
196 | 196 | |
197 | - $this->assign('createmode', false); |
|
197 | + $this->assign('createmode', false); |
|
198 | 198 | |
199 | - if (WebRequest::wasPosted()) { |
|
200 | - $this->validateCSRFToken(); |
|
199 | + if (WebRequest::wasPosted()) { |
|
200 | + $this->validateCSRFToken(); |
|
201 | 201 | |
202 | - $userCode = WebRequest::postString('usercode'); |
|
203 | - $botCode = WebRequest::postString('botcode'); |
|
202 | + $userCode = WebRequest::postString('usercode'); |
|
203 | + $botCode = WebRequest::postString('botcode'); |
|
204 | 204 | |
205 | - $this->validate($userCode, $botCode); |
|
205 | + $this->validate($userCode, $botCode); |
|
206 | 206 | |
207 | - $template->setUserCode($userCode); |
|
208 | - $template->setBotCode($botCode); |
|
209 | - $template->setUpdateVersion(WebRequest::postInt('updateversion')); |
|
210 | - $template->save(); |
|
207 | + $template->setUserCode($userCode); |
|
208 | + $template->setBotCode($botCode); |
|
209 | + $template->setUpdateVersion(WebRequest::postInt('updateversion')); |
|
210 | + $template->save(); |
|
211 | 211 | |
212 | - Logger::welcomeTemplateEdited($database, $template); |
|
212 | + Logger::welcomeTemplateEdited($database, $template); |
|
213 | 213 | |
214 | - SessionAlert::success("Template updated."); |
|
214 | + SessionAlert::success("Template updated."); |
|
215 | 215 | |
216 | - $this->getNotificationHelper()->welcomeTemplateEdited($template); |
|
216 | + $this->getNotificationHelper()->welcomeTemplateEdited($template); |
|
217 | 217 | |
218 | - $this->redirect('welcomeTemplates'); |
|
219 | - } |
|
220 | - else { |
|
221 | - $this->assignCSRFToken(); |
|
222 | - $this->assign('template', $template); |
|
223 | - $this->setTemplate('welcome-template/edit.tpl'); |
|
224 | - } |
|
225 | - } |
|
218 | + $this->redirect('welcomeTemplates'); |
|
219 | + } |
|
220 | + else { |
|
221 | + $this->assignCSRFToken(); |
|
222 | + $this->assign('template', $template); |
|
223 | + $this->setTemplate('welcome-template/edit.tpl'); |
|
224 | + } |
|
225 | + } |
|
226 | 226 | |
227 | - protected function delete() |
|
228 | - { |
|
229 | - if (!WebRequest::wasPosted()) { |
|
230 | - $this->redirect('welcomeTemplates'); |
|
231 | - return; |
|
232 | - } |
|
227 | + protected function delete() |
|
228 | + { |
|
229 | + if (!WebRequest::wasPosted()) { |
|
230 | + $this->redirect('welcomeTemplates'); |
|
231 | + return; |
|
232 | + } |
|
233 | 233 | |
234 | - $this->validateCSRFToken(); |
|
234 | + $this->validateCSRFToken(); |
|
235 | 235 | |
236 | - $database = $this->getDatabase(); |
|
236 | + $database = $this->getDatabase(); |
|
237 | 237 | |
238 | - $templateId = WebRequest::postInt('template'); |
|
239 | - $updateVersion = WebRequest::postInt('updateversion'); |
|
238 | + $templateId = WebRequest::postInt('template'); |
|
239 | + $updateVersion = WebRequest::postInt('updateversion'); |
|
240 | 240 | |
241 | - /** @var false|WelcomeTemplate $template */ |
|
242 | - $template = WelcomeTemplate::getById($templateId, $database); |
|
241 | + /** @var false|WelcomeTemplate $template */ |
|
242 | + $template = WelcomeTemplate::getById($templateId, $database); |
|
243 | 243 | |
244 | - if ($template === false || $template->isDeleted()) { |
|
245 | - throw new ApplicationLogicException('Cannot find requested template'); |
|
246 | - } |
|
244 | + if ($template === false || $template->isDeleted()) { |
|
245 | + throw new ApplicationLogicException('Cannot find requested template'); |
|
246 | + } |
|
247 | 247 | |
248 | - // set the update version to the version sent by the client (optimisticly lock from initial page load) |
|
249 | - $template->setUpdateVersion($updateVersion); |
|
248 | + // set the update version to the version sent by the client (optimisticly lock from initial page load) |
|
249 | + $template->setUpdateVersion($updateVersion); |
|
250 | 250 | |
251 | - $database |
|
252 | - ->prepare("UPDATE userpreference SET value = NULL, updateversion = updateversion + 1 WHERE preference = :pref and value = :id;") |
|
253 | - ->execute([ |
|
254 | - ':id' => $templateId, |
|
255 | - ':pref' => PreferenceManager::PREF_WELCOMETEMPLATE |
|
256 | - ]); |
|
251 | + $database |
|
252 | + ->prepare("UPDATE userpreference SET value = NULL, updateversion = updateversion + 1 WHERE preference = :pref and value = :id;") |
|
253 | + ->execute([ |
|
254 | + ':id' => $templateId, |
|
255 | + ':pref' => PreferenceManager::PREF_WELCOMETEMPLATE |
|
256 | + ]); |
|
257 | 257 | |
258 | - Logger::welcomeTemplateDeleted($database, $template); |
|
258 | + Logger::welcomeTemplateDeleted($database, $template); |
|
259 | 259 | |
260 | - $template->delete(); |
|
260 | + $template->delete(); |
|
261 | 261 | |
262 | - $this->redirect('welcomeTemplates'); |
|
262 | + $this->redirect('welcomeTemplates'); |
|
263 | 263 | |
264 | - SessionAlert::success( |
|
265 | - "Template deleted. Any users who were using this template have had automatic welcoming disabled."); |
|
266 | - $this->getNotificationHelper()->welcomeTemplateDeleted($templateId); |
|
267 | - } |
|
264 | + SessionAlert::success( |
|
265 | + "Template deleted. Any users who were using this template have had automatic welcoming disabled."); |
|
266 | + $this->getNotificationHelper()->welcomeTemplateDeleted($templateId); |
|
267 | + } |
|
268 | 268 | |
269 | - private function validate($userCode, $botCode) |
|
270 | - { |
|
271 | - if ($userCode === null) { |
|
272 | - throw new ApplicationLogicException('User code cannot be null'); |
|
273 | - } |
|
269 | + private function validate($userCode, $botCode) |
|
270 | + { |
|
271 | + if ($userCode === null) { |
|
272 | + throw new ApplicationLogicException('User code cannot be null'); |
|
273 | + } |
|
274 | 274 | |
275 | - if ($botCode === null) { |
|
276 | - throw new ApplicationLogicException('Bot code cannot be null'); |
|
277 | - } |
|
278 | - } |
|
275 | + if ($botCode === null) { |
|
276 | + throw new ApplicationLogicException('Bot code cannot be null'); |
|
277 | + } |
|
278 | + } |
|
279 | 279 | } |
@@ -166,8 +166,7 @@ discard block |
||
166 | 166 | SessionAlert::success("Template successfully created."); |
167 | 167 | |
168 | 168 | $this->redirect('welcomeTemplates'); |
169 | - } |
|
170 | - else { |
|
169 | + } else { |
|
171 | 170 | $this->assignCSRFToken(); |
172 | 171 | $this->assign('template', new WelcomeTemplate()); |
173 | 172 | $this->setTemplate("welcome-template/edit.tpl"); |
@@ -216,8 +215,7 @@ discard block |
||
216 | 215 | $this->getNotificationHelper()->welcomeTemplateEdited($template); |
217 | 216 | |
218 | 217 | $this->redirect('welcomeTemplates'); |
219 | - } |
|
220 | - else { |
|
218 | + } else { |
|
221 | 219 | $this->assignCSRFToken(); |
222 | 220 | $this->assign('template', $template); |
223 | 221 | $this->setTemplate('welcome-template/edit.tpl'); |
@@ -13,136 +13,136 @@ |
||
13 | 13 | |
14 | 14 | class PageXffDemo extends InternalPageBase |
15 | 15 | { |
16 | - use RequestData; |
|
17 | - |
|
18 | - /** |
|
19 | - * @inheritDoc |
|
20 | - */ |
|
21 | - protected function main() |
|
22 | - { |
|
23 | - $this->setTemplate('xffdemo.tpl'); |
|
24 | - |
|
25 | - // requestHasForwardedIp == false |
|
26 | - // requestProxyData |
|
27 | - // requestRealIp == proxy |
|
28 | - // requestForwardedIp == xff header |
|
29 | - // forwardedOrigin == top of the chain, assuming xff is trusted |
|
30 | - |
|
31 | - |
|
32 | - $this->assign('demo2', [ |
|
33 | - [ |
|
34 | - 'trust' => true, |
|
35 | - 'trustedlink' => true, |
|
36 | - 'ip' => '172.16.0.164', |
|
37 | - 'routable' => false, |
|
38 | - |
|
39 | - ], [ |
|
40 | - 'trust' => true, |
|
41 | - 'ip' => '198.51.100.123', |
|
42 | - 'routable' => true, |
|
43 | - 'rdns' => 'trustedproxy.example.com', |
|
44 | - |
|
45 | - ], [ |
|
46 | - 'trust' => true, |
|
47 | - 'ip' => '192.0.2.1', |
|
48 | - 'routable' => true, |
|
49 | - 'rdns' => 'client.users.example.org', |
|
50 | - 'location' => [ |
|
51 | - 'cityName' => 'San Francisco', |
|
52 | - 'regionName' => 'California', |
|
53 | - 'countryName' => 'United States' |
|
54 | - ], |
|
55 | - 'showlinks' => true |
|
56 | - ] |
|
57 | - ]); |
|
58 | - |
|
59 | - $this->assign('demo3', [ |
|
60 | - [ |
|
61 | - 'trust' => true, |
|
62 | - 'trustedlink' => true, |
|
63 | - 'ip' => '172.16.0.164', |
|
64 | - 'routable' => false, |
|
65 | - |
|
66 | - ], [ |
|
67 | - 'trust' => false, |
|
68 | - 'ip' => '198.51.100.234', |
|
69 | - 'routable' => true, |
|
70 | - 'rdns' => 'sketchyproxy.example.com', |
|
71 | - 'showlinks' => true |
|
72 | - |
|
73 | - ], [ |
|
74 | - 'trust' => false, |
|
75 | - 'ip' => '192.0.2.1', |
|
76 | - 'routable' => true, |
|
77 | - 'rdns' => 'client.users.example.org', |
|
78 | - 'location' => [ |
|
79 | - 'cityName' => 'San Francisco', |
|
80 | - 'regionName' => 'California', |
|
81 | - 'countryName' => 'United States' |
|
82 | - ], |
|
83 | - 'showlinks' => true |
|
84 | - ] |
|
85 | - ]); |
|
86 | - |
|
87 | - $this->assign('demo4', [ |
|
88 | - [ |
|
89 | - 'trust' => true, |
|
90 | - 'trustedlink' => true, |
|
91 | - 'ip' => '172.16.0.164', |
|
92 | - 'routable' => false, |
|
93 | - |
|
94 | - ], [ |
|
95 | - 'trust' => true, |
|
96 | - 'ip' => '198.51.100.123', |
|
97 | - 'routable' => true, |
|
98 | - 'rdns' => 'trustedproxy.example.com', |
|
99 | - ], [ |
|
100 | - 'trust' => false, |
|
101 | - 'ip' => '198.51.100.234', |
|
102 | - 'routable' => true, |
|
103 | - 'rdns' => 'sketchyproxy.example.com', |
|
104 | - 'showlinks' => true |
|
105 | - ], [ |
|
106 | - 'trust' => false, |
|
107 | - 'trustedlink' => true, |
|
108 | - 'ip' => '198.51.100.124', |
|
109 | - 'routable' => true, |
|
110 | - 'rdns' => 'trustedproxy2.example.com', |
|
111 | - 'showlinks' => true |
|
112 | - ], [ |
|
113 | - 'trust' => false, |
|
114 | - 'ip' => '192.0.2.1', |
|
115 | - 'routable' => true, |
|
116 | - 'rdns' => 'client.users.example.org', |
|
117 | - 'location' => [ |
|
118 | - 'cityName' => 'San Francisco', |
|
119 | - 'regionName' => 'California', |
|
120 | - 'countryName' => 'United States' |
|
121 | - ], |
|
122 | - 'showlinks' => true |
|
123 | - ] |
|
124 | - ]); |
|
125 | - |
|
126 | - $this->assign('demo1', [ |
|
127 | - [ |
|
128 | - 'trust' => true, |
|
129 | - 'trustedlink' => true, |
|
130 | - 'ip' => '172.16.0.164', |
|
131 | - 'routable' => false, |
|
132 | - |
|
133 | - ], [ |
|
134 | - 'trust' => true, |
|
135 | - 'trustedlink' => true, |
|
136 | - 'ip' => '192.0.2.1', |
|
137 | - 'routable' => true, |
|
138 | - 'rdns' => 'client.users.example.org', |
|
139 | - 'location' => [ |
|
140 | - 'cityName' => 'San Francisco', |
|
141 | - 'regionName' => 'California', |
|
142 | - 'countryName' => 'United States' |
|
143 | - ], |
|
144 | - 'showlinks' => true |
|
145 | - ] |
|
146 | - ]); |
|
147 | - } |
|
16 | + use RequestData; |
|
17 | + |
|
18 | + /** |
|
19 | + * @inheritDoc |
|
20 | + */ |
|
21 | + protected function main() |
|
22 | + { |
|
23 | + $this->setTemplate('xffdemo.tpl'); |
|
24 | + |
|
25 | + // requestHasForwardedIp == false |
|
26 | + // requestProxyData |
|
27 | + // requestRealIp == proxy |
|
28 | + // requestForwardedIp == xff header |
|
29 | + // forwardedOrigin == top of the chain, assuming xff is trusted |
|
30 | + |
|
31 | + |
|
32 | + $this->assign('demo2', [ |
|
33 | + [ |
|
34 | + 'trust' => true, |
|
35 | + 'trustedlink' => true, |
|
36 | + 'ip' => '172.16.0.164', |
|
37 | + 'routable' => false, |
|
38 | + |
|
39 | + ], [ |
|
40 | + 'trust' => true, |
|
41 | + 'ip' => '198.51.100.123', |
|
42 | + 'routable' => true, |
|
43 | + 'rdns' => 'trustedproxy.example.com', |
|
44 | + |
|
45 | + ], [ |
|
46 | + 'trust' => true, |
|
47 | + 'ip' => '192.0.2.1', |
|
48 | + 'routable' => true, |
|
49 | + 'rdns' => 'client.users.example.org', |
|
50 | + 'location' => [ |
|
51 | + 'cityName' => 'San Francisco', |
|
52 | + 'regionName' => 'California', |
|
53 | + 'countryName' => 'United States' |
|
54 | + ], |
|
55 | + 'showlinks' => true |
|
56 | + ] |
|
57 | + ]); |
|
58 | + |
|
59 | + $this->assign('demo3', [ |
|
60 | + [ |
|
61 | + 'trust' => true, |
|
62 | + 'trustedlink' => true, |
|
63 | + 'ip' => '172.16.0.164', |
|
64 | + 'routable' => false, |
|
65 | + |
|
66 | + ], [ |
|
67 | + 'trust' => false, |
|
68 | + 'ip' => '198.51.100.234', |
|
69 | + 'routable' => true, |
|
70 | + 'rdns' => 'sketchyproxy.example.com', |
|
71 | + 'showlinks' => true |
|
72 | + |
|
73 | + ], [ |
|
74 | + 'trust' => false, |
|
75 | + 'ip' => '192.0.2.1', |
|
76 | + 'routable' => true, |
|
77 | + 'rdns' => 'client.users.example.org', |
|
78 | + 'location' => [ |
|
79 | + 'cityName' => 'San Francisco', |
|
80 | + 'regionName' => 'California', |
|
81 | + 'countryName' => 'United States' |
|
82 | + ], |
|
83 | + 'showlinks' => true |
|
84 | + ] |
|
85 | + ]); |
|
86 | + |
|
87 | + $this->assign('demo4', [ |
|
88 | + [ |
|
89 | + 'trust' => true, |
|
90 | + 'trustedlink' => true, |
|
91 | + 'ip' => '172.16.0.164', |
|
92 | + 'routable' => false, |
|
93 | + |
|
94 | + ], [ |
|
95 | + 'trust' => true, |
|
96 | + 'ip' => '198.51.100.123', |
|
97 | + 'routable' => true, |
|
98 | + 'rdns' => 'trustedproxy.example.com', |
|
99 | + ], [ |
|
100 | + 'trust' => false, |
|
101 | + 'ip' => '198.51.100.234', |
|
102 | + 'routable' => true, |
|
103 | + 'rdns' => 'sketchyproxy.example.com', |
|
104 | + 'showlinks' => true |
|
105 | + ], [ |
|
106 | + 'trust' => false, |
|
107 | + 'trustedlink' => true, |
|
108 | + 'ip' => '198.51.100.124', |
|
109 | + 'routable' => true, |
|
110 | + 'rdns' => 'trustedproxy2.example.com', |
|
111 | + 'showlinks' => true |
|
112 | + ], [ |
|
113 | + 'trust' => false, |
|
114 | + 'ip' => '192.0.2.1', |
|
115 | + 'routable' => true, |
|
116 | + 'rdns' => 'client.users.example.org', |
|
117 | + 'location' => [ |
|
118 | + 'cityName' => 'San Francisco', |
|
119 | + 'regionName' => 'California', |
|
120 | + 'countryName' => 'United States' |
|
121 | + ], |
|
122 | + 'showlinks' => true |
|
123 | + ] |
|
124 | + ]); |
|
125 | + |
|
126 | + $this->assign('demo1', [ |
|
127 | + [ |
|
128 | + 'trust' => true, |
|
129 | + 'trustedlink' => true, |
|
130 | + 'ip' => '172.16.0.164', |
|
131 | + 'routable' => false, |
|
132 | + |
|
133 | + ], [ |
|
134 | + 'trust' => true, |
|
135 | + 'trustedlink' => true, |
|
136 | + 'ip' => '192.0.2.1', |
|
137 | + 'routable' => true, |
|
138 | + 'rdns' => 'client.users.example.org', |
|
139 | + 'location' => [ |
|
140 | + 'cityName' => 'San Francisco', |
|
141 | + 'regionName' => 'California', |
|
142 | + 'countryName' => 'United States' |
|
143 | + ], |
|
144 | + 'showlinks' => true |
|
145 | + ] |
|
146 | + ]); |
|
147 | + } |
|
148 | 148 | } |
@@ -14,127 +14,127 @@ |
||
14 | 14 | |
15 | 15 | class PageErrorLogViewer extends InternalPageBase |
16 | 16 | { |
17 | - /** |
|
18 | - * @inheritDoc |
|
19 | - */ |
|
20 | - protected function main() |
|
21 | - { |
|
22 | - $this->setHtmlTitle('Exception viewer'); |
|
23 | - |
|
24 | - $user = User::getCurrent($this->getDatabase()); |
|
25 | - $this->assign('canView', $this->barrierTest('view', $user)); |
|
26 | - $this->assign('canRemove', $this->barrierTest('remove', $user)); |
|
27 | - |
|
28 | - // Get the list of exception logs from the error log directory |
|
29 | - $errorLogDirectory = $this->getSiteConfiguration()->getErrorLog(); |
|
30 | - $files = scandir($errorLogDirectory); |
|
31 | - |
|
32 | - // Exclude the files we know should be there |
|
33 | - $filteredFiles = array_filter($files, function($file) { |
|
34 | - return !in_array($file, ['.', '..', 'README.md']); |
|
35 | - }); |
|
36 | - |
|
37 | - $exceptionDetails = array_map(function($item) use ($errorLogDirectory) { |
|
38 | - $filename = realpath($errorLogDirectory) . DIRECTORY_SEPARATOR . $item; |
|
39 | - |
|
40 | - return [ |
|
41 | - 'id' => str_replace('.log', '', $item), |
|
42 | - 'date' => date('Y-m-d H:i:s', filemtime($filename)), |
|
43 | - 'data' => str_replace($this->getSiteConfiguration()->getFilePath(), '.', |
|
44 | - unserialize(file_get_contents($filename))), |
|
45 | - ]; |
|
46 | - }, $filteredFiles); |
|
47 | - |
|
48 | - $this->assign('exceptionEntries', $exceptionDetails); |
|
49 | - $this->setTemplate('errorlog/main.tpl'); |
|
50 | - } |
|
51 | - |
|
52 | - protected function view() |
|
53 | - { |
|
54 | - $this->setHtmlTitle('Exception viewer'); |
|
55 | - |
|
56 | - $requestedErrorId = WebRequest::getString('id'); |
|
57 | - $safeFilename = $this->safetyCheck($requestedErrorId); |
|
58 | - |
|
59 | - if ($safeFilename === false) { |
|
60 | - $this->redirect('errorLog'); |
|
61 | - |
|
62 | - return; |
|
63 | - } |
|
64 | - |
|
65 | - // note: at this point we've done sufficient sanity checks that we can be confident this value is safe to echo |
|
66 | - // back to the user. |
|
67 | - $this->assign('id', $requestedErrorId); |
|
68 | - $this->assign('date', date('Y-m-d H:i:s', filemtime($safeFilename))); |
|
69 | - |
|
70 | - $data = unserialize(file_get_contents($safeFilename)); |
|
71 | - $this->assign('server', $data['server']); |
|
72 | - $this->assign('get', $data['get']); |
|
73 | - $this->assign('post', $data['post']); |
|
74 | - |
|
75 | - $this->assign('globalHandler', $data['globalHandler']); |
|
76 | - |
|
77 | - $exceptionList = []; |
|
78 | - $current = $data; |
|
79 | - do { |
|
80 | - $ex = [ |
|
81 | - 'exception' => $current['exception'], |
|
82 | - 'message' => str_replace($this->getSiteConfiguration()->getFilePath(), '.', $current['message']), |
|
83 | - 'stack' => str_replace($this->getSiteConfiguration()->getFilePath(), '.', $current['stack']), |
|
84 | - ]; |
|
85 | - $exceptionList[] = $ex; |
|
86 | - |
|
87 | - $current = $current['previous']; |
|
88 | - } |
|
89 | - while ($current !== null); |
|
90 | - |
|
91 | - $this->assign('exceptionList', $exceptionList); |
|
92 | - |
|
93 | - $this->setTemplate('errorlog/details.tpl'); |
|
94 | - } |
|
95 | - |
|
96 | - public function remove() |
|
97 | - { |
|
98 | - $safeFilename = $this->safetyCheck(WebRequest::getString('id')); |
|
99 | - |
|
100 | - if ($safeFilename === false) { |
|
101 | - $this->redirect('errorLog'); |
|
102 | - |
|
103 | - return; |
|
104 | - } |
|
105 | - |
|
106 | - unlink($safeFilename); |
|
107 | - |
|
108 | - $this->redirect('errorLog'); |
|
109 | - |
|
110 | - return; |
|
111 | - } |
|
112 | - |
|
113 | - /** |
|
114 | - * @param string|null $requestedErrorId |
|
115 | - * |
|
116 | - * @return bool|string |
|
117 | - */ |
|
118 | - protected function safetyCheck(?string $requestedErrorId) |
|
119 | - { |
|
120 | - if ($requestedErrorId === null) { |
|
121 | - return false; |
|
122 | - } |
|
123 | - |
|
124 | - // security - only allow hex-encoded filenames, as this is what is generated. |
|
125 | - // This is prefixed with the configured directory. Path traversal is protected against due to . and / not being |
|
126 | - // part of the hex character set. |
|
127 | - if (!preg_match('/^[a-f0-9]{40}$/', $requestedErrorId)) { |
|
128 | - return false; |
|
129 | - } |
|
130 | - |
|
131 | - $errorLogDirectory = $this->getSiteConfiguration()->getErrorLog(); |
|
132 | - $filename = realpath($errorLogDirectory) . DIRECTORY_SEPARATOR . $requestedErrorId . '.log'; |
|
133 | - |
|
134 | - if (!file_exists($filename)) { |
|
135 | - return false; |
|
136 | - } |
|
137 | - |
|
138 | - return $filename; |
|
139 | - } |
|
17 | + /** |
|
18 | + * @inheritDoc |
|
19 | + */ |
|
20 | + protected function main() |
|
21 | + { |
|
22 | + $this->setHtmlTitle('Exception viewer'); |
|
23 | + |
|
24 | + $user = User::getCurrent($this->getDatabase()); |
|
25 | + $this->assign('canView', $this->barrierTest('view', $user)); |
|
26 | + $this->assign('canRemove', $this->barrierTest('remove', $user)); |
|
27 | + |
|
28 | + // Get the list of exception logs from the error log directory |
|
29 | + $errorLogDirectory = $this->getSiteConfiguration()->getErrorLog(); |
|
30 | + $files = scandir($errorLogDirectory); |
|
31 | + |
|
32 | + // Exclude the files we know should be there |
|
33 | + $filteredFiles = array_filter($files, function($file) { |
|
34 | + return !in_array($file, ['.', '..', 'README.md']); |
|
35 | + }); |
|
36 | + |
|
37 | + $exceptionDetails = array_map(function($item) use ($errorLogDirectory) { |
|
38 | + $filename = realpath($errorLogDirectory) . DIRECTORY_SEPARATOR . $item; |
|
39 | + |
|
40 | + return [ |
|
41 | + 'id' => str_replace('.log', '', $item), |
|
42 | + 'date' => date('Y-m-d H:i:s', filemtime($filename)), |
|
43 | + 'data' => str_replace($this->getSiteConfiguration()->getFilePath(), '.', |
|
44 | + unserialize(file_get_contents($filename))), |
|
45 | + ]; |
|
46 | + }, $filteredFiles); |
|
47 | + |
|
48 | + $this->assign('exceptionEntries', $exceptionDetails); |
|
49 | + $this->setTemplate('errorlog/main.tpl'); |
|
50 | + } |
|
51 | + |
|
52 | + protected function view() |
|
53 | + { |
|
54 | + $this->setHtmlTitle('Exception viewer'); |
|
55 | + |
|
56 | + $requestedErrorId = WebRequest::getString('id'); |
|
57 | + $safeFilename = $this->safetyCheck($requestedErrorId); |
|
58 | + |
|
59 | + if ($safeFilename === false) { |
|
60 | + $this->redirect('errorLog'); |
|
61 | + |
|
62 | + return; |
|
63 | + } |
|
64 | + |
|
65 | + // note: at this point we've done sufficient sanity checks that we can be confident this value is safe to echo |
|
66 | + // back to the user. |
|
67 | + $this->assign('id', $requestedErrorId); |
|
68 | + $this->assign('date', date('Y-m-d H:i:s', filemtime($safeFilename))); |
|
69 | + |
|
70 | + $data = unserialize(file_get_contents($safeFilename)); |
|
71 | + $this->assign('server', $data['server']); |
|
72 | + $this->assign('get', $data['get']); |
|
73 | + $this->assign('post', $data['post']); |
|
74 | + |
|
75 | + $this->assign('globalHandler', $data['globalHandler']); |
|
76 | + |
|
77 | + $exceptionList = []; |
|
78 | + $current = $data; |
|
79 | + do { |
|
80 | + $ex = [ |
|
81 | + 'exception' => $current['exception'], |
|
82 | + 'message' => str_replace($this->getSiteConfiguration()->getFilePath(), '.', $current['message']), |
|
83 | + 'stack' => str_replace($this->getSiteConfiguration()->getFilePath(), '.', $current['stack']), |
|
84 | + ]; |
|
85 | + $exceptionList[] = $ex; |
|
86 | + |
|
87 | + $current = $current['previous']; |
|
88 | + } |
|
89 | + while ($current !== null); |
|
90 | + |
|
91 | + $this->assign('exceptionList', $exceptionList); |
|
92 | + |
|
93 | + $this->setTemplate('errorlog/details.tpl'); |
|
94 | + } |
|
95 | + |
|
96 | + public function remove() |
|
97 | + { |
|
98 | + $safeFilename = $this->safetyCheck(WebRequest::getString('id')); |
|
99 | + |
|
100 | + if ($safeFilename === false) { |
|
101 | + $this->redirect('errorLog'); |
|
102 | + |
|
103 | + return; |
|
104 | + } |
|
105 | + |
|
106 | + unlink($safeFilename); |
|
107 | + |
|
108 | + $this->redirect('errorLog'); |
|
109 | + |
|
110 | + return; |
|
111 | + } |
|
112 | + |
|
113 | + /** |
|
114 | + * @param string|null $requestedErrorId |
|
115 | + * |
|
116 | + * @return bool|string |
|
117 | + */ |
|
118 | + protected function safetyCheck(?string $requestedErrorId) |
|
119 | + { |
|
120 | + if ($requestedErrorId === null) { |
|
121 | + return false; |
|
122 | + } |
|
123 | + |
|
124 | + // security - only allow hex-encoded filenames, as this is what is generated. |
|
125 | + // This is prefixed with the configured directory. Path traversal is protected against due to . and / not being |
|
126 | + // part of the hex character set. |
|
127 | + if (!preg_match('/^[a-f0-9]{40}$/', $requestedErrorId)) { |
|
128 | + return false; |
|
129 | + } |
|
130 | + |
|
131 | + $errorLogDirectory = $this->getSiteConfiguration()->getErrorLog(); |
|
132 | + $filename = realpath($errorLogDirectory) . DIRECTORY_SEPARATOR . $requestedErrorId . '.log'; |
|
133 | + |
|
134 | + if (!file_exists($filename)) { |
|
135 | + return false; |
|
136 | + } |
|
137 | + |
|
138 | + return $filename; |
|
139 | + } |
|
140 | 140 | } |
141 | 141 | \ No newline at end of file |
@@ -30,11 +30,13 @@ |
||
30 | 30 | $files = scandir($errorLogDirectory); |
31 | 31 | |
32 | 32 | // Exclude the files we know should be there |
33 | - $filteredFiles = array_filter($files, function($file) { |
|
33 | + $filteredFiles = array_filter($files, function($file) |
|
34 | + { |
|
34 | 35 | return !in_array($file, ['.', '..', 'README.md']); |
35 | 36 | }); |
36 | 37 | |
37 | - $exceptionDetails = array_map(function($item) use ($errorLogDirectory) { |
|
38 | + $exceptionDetails = array_map(function($item) use ($errorLogDirectory) |
|
39 | + { |
|
38 | 40 | $filename = realpath($errorLogDirectory) . DIRECTORY_SEPARATOR . $item; |
39 | 41 | |
40 | 42 | return [ |
@@ -187,7 +187,8 @@ |
||
187 | 187 | |
188 | 188 | // FIXME: domains! |
189 | 189 | $requestQueues = RequestQueue::getAllQueues($database); |
190 | - $queuesById = array_reduce($requestQueues, function($result, RequestQueue $item) { |
|
190 | + $queuesById = array_reduce($requestQueues, function($result, RequestQueue $item) |
|
191 | + { |
|
191 | 192 | $result[$item->getId()] = $item; |
192 | 193 | return $result; |
193 | 194 | }, array()); |
@@ -23,69 +23,69 @@ discard block |
||
23 | 23 | |
24 | 24 | class PageMain extends InternalPageBase |
25 | 25 | { |
26 | - use RequestListData; |
|
27 | - |
|
28 | - /** |
|
29 | - * Main function for this page, when no actions are called. |
|
30 | - */ |
|
31 | - protected function main() |
|
32 | - { |
|
33 | - $this->assignCSRFToken(); |
|
34 | - |
|
35 | - $config = $this->getSiteConfiguration(); |
|
36 | - $database = $this->getDatabase(); |
|
37 | - $currentUser = User::getCurrent($database); |
|
38 | - $preferencesManager = PreferenceManager::getForCurrent($database); |
|
39 | - |
|
40 | - // general template configuration |
|
41 | - // FIXME: domains! |
|
42 | - $defaultQueue = RequestQueue::getDefaultQueue($database, 1); |
|
43 | - $this->assign('defaultRequestState', $defaultQueue->getApiName()); |
|
44 | - $this->assign('requestLimitShowOnly', $config->getMiserModeLimit()); |
|
45 | - |
|
46 | - $seeAllRequests = $this->barrierTest('seeAllRequests', $currentUser, PageViewRequest::class); |
|
47 | - |
|
48 | - list($defaultSort, $defaultSortDirection) = WebRequest::requestListDefaultSort(); |
|
49 | - $this->assign('defaultSort', $defaultSort); |
|
50 | - $this->assign('defaultSortDirection', $defaultSortDirection); |
|
51 | - $showQueueHelp = $preferencesManager->getPreference(PreferenceManager::PREF_QUEUE_HELP) ?? true; |
|
52 | - $this->assign('showQueueHelp', $showQueueHelp); |
|
53 | - |
|
54 | - // Fetch request data |
|
55 | - $requestSectionData = array(); |
|
56 | - if ($seeAllRequests) { |
|
57 | - $this->setupStatusSections($database, $config, $requestSectionData); |
|
58 | - $this->setupHospitalQueue($database, $config, $requestSectionData); |
|
59 | - $this->setupJobQueue($database, $config, $requestSectionData); |
|
60 | - } |
|
61 | - $this->setupLastFiveClosedData($database, $seeAllRequests); |
|
62 | - |
|
63 | - // Assign data to template |
|
64 | - $this->assign('requestSectionData', $requestSectionData); |
|
65 | - |
|
66 | - $this->setTemplate('mainpage/mainpage.tpl'); |
|
67 | - } |
|
68 | - |
|
69 | - /** |
|
70 | - * @param PdoDatabase $database |
|
71 | - * @param bool $seeAllRequests |
|
72 | - * |
|
73 | - * @internal param User $currentUser |
|
74 | - */ |
|
75 | - private function setupLastFiveClosedData(PdoDatabase $database, $seeAllRequests) |
|
76 | - { |
|
77 | - $config = $this->getSiteConfiguration(); |
|
78 | - $this->assign('showLastFive', $seeAllRequests); |
|
79 | - if (!$seeAllRequests) { |
|
80 | - return; |
|
81 | - } |
|
82 | - |
|
83 | - $queryExcludeDropped = ""; |
|
84 | - if ($config->getEmailConfirmationEnabled()) { |
|
85 | - $queryExcludeDropped = "AND request.emailConfirm = 'Confirmed'"; |
|
86 | - } |
|
87 | - |
|
88 | - $query = <<<SQL |
|
26 | + use RequestListData; |
|
27 | + |
|
28 | + /** |
|
29 | + * Main function for this page, when no actions are called. |
|
30 | + */ |
|
31 | + protected function main() |
|
32 | + { |
|
33 | + $this->assignCSRFToken(); |
|
34 | + |
|
35 | + $config = $this->getSiteConfiguration(); |
|
36 | + $database = $this->getDatabase(); |
|
37 | + $currentUser = User::getCurrent($database); |
|
38 | + $preferencesManager = PreferenceManager::getForCurrent($database); |
|
39 | + |
|
40 | + // general template configuration |
|
41 | + // FIXME: domains! |
|
42 | + $defaultQueue = RequestQueue::getDefaultQueue($database, 1); |
|
43 | + $this->assign('defaultRequestState', $defaultQueue->getApiName()); |
|
44 | + $this->assign('requestLimitShowOnly', $config->getMiserModeLimit()); |
|
45 | + |
|
46 | + $seeAllRequests = $this->barrierTest('seeAllRequests', $currentUser, PageViewRequest::class); |
|
47 | + |
|
48 | + list($defaultSort, $defaultSortDirection) = WebRequest::requestListDefaultSort(); |
|
49 | + $this->assign('defaultSort', $defaultSort); |
|
50 | + $this->assign('defaultSortDirection', $defaultSortDirection); |
|
51 | + $showQueueHelp = $preferencesManager->getPreference(PreferenceManager::PREF_QUEUE_HELP) ?? true; |
|
52 | + $this->assign('showQueueHelp', $showQueueHelp); |
|
53 | + |
|
54 | + // Fetch request data |
|
55 | + $requestSectionData = array(); |
|
56 | + if ($seeAllRequests) { |
|
57 | + $this->setupStatusSections($database, $config, $requestSectionData); |
|
58 | + $this->setupHospitalQueue($database, $config, $requestSectionData); |
|
59 | + $this->setupJobQueue($database, $config, $requestSectionData); |
|
60 | + } |
|
61 | + $this->setupLastFiveClosedData($database, $seeAllRequests); |
|
62 | + |
|
63 | + // Assign data to template |
|
64 | + $this->assign('requestSectionData', $requestSectionData); |
|
65 | + |
|
66 | + $this->setTemplate('mainpage/mainpage.tpl'); |
|
67 | + } |
|
68 | + |
|
69 | + /** |
|
70 | + * @param PdoDatabase $database |
|
71 | + * @param bool $seeAllRequests |
|
72 | + * |
|
73 | + * @internal param User $currentUser |
|
74 | + */ |
|
75 | + private function setupLastFiveClosedData(PdoDatabase $database, $seeAllRequests) |
|
76 | + { |
|
77 | + $config = $this->getSiteConfiguration(); |
|
78 | + $this->assign('showLastFive', $seeAllRequests); |
|
79 | + if (!$seeAllRequests) { |
|
80 | + return; |
|
81 | + } |
|
82 | + |
|
83 | + $queryExcludeDropped = ""; |
|
84 | + if ($config->getEmailConfirmationEnabled()) { |
|
85 | + $queryExcludeDropped = "AND request.emailConfirm = 'Confirmed'"; |
|
86 | + } |
|
87 | + |
|
88 | + $query = <<<SQL |
|
89 | 89 | SELECT request.id, request.name, request.updateversion |
90 | 90 | FROM request /* PageMain::main() */ |
91 | 91 | JOIN log ON log.objectid = request.id AND log.objecttype = 'Request' |
@@ -95,124 +95,124 @@ discard block |
||
95 | 95 | LIMIT 5; |
96 | 96 | SQL; |
97 | 97 | |
98 | - $statement = $database->prepare($query); |
|
99 | - $statement->execute(); |
|
100 | - |
|
101 | - $last5result = $statement->fetchAll(PDO::FETCH_ASSOC); |
|
102 | - |
|
103 | - $this->assign('lastFive', $last5result); |
|
104 | - } |
|
105 | - |
|
106 | - /** |
|
107 | - * @param PdoDatabase $database |
|
108 | - * @param SiteConfiguration $config |
|
109 | - * @param $requestSectionData |
|
110 | - */ |
|
111 | - private function setupHospitalQueue( |
|
112 | - PdoDatabase $database, |
|
113 | - SiteConfiguration $config, |
|
114 | - &$requestSectionData |
|
115 | - ) { |
|
116 | - // FIXME: domains! |
|
117 | - $search = RequestSearchHelper::get($database, 1) |
|
118 | - ->limit($config->getMiserModeLimit()) |
|
119 | - ->excludingStatus('Closed') |
|
120 | - ->isHospitalised(); |
|
121 | - |
|
122 | - if ($config->getEmailConfirmationEnabled()) { |
|
123 | - $search->withConfirmedEmail(); |
|
124 | - } |
|
125 | - |
|
126 | - /** @var Request[] $results */ |
|
127 | - $results = $search->getRecordCount($requestCount)->fetch(); |
|
128 | - |
|
129 | - if ($requestCount > 0) { |
|
130 | - $requestSectionData['Hospital - Requests failed auto-creation'] = array( |
|
131 | - 'requests' => $this->prepareRequestData($results), |
|
132 | - 'total' => $requestCount, |
|
133 | - 'api' => 'hospital', |
|
134 | - 'type' => 'hospital', |
|
135 | - 'special' => 'Job Queue', |
|
136 | - 'help' => 'This queue lists all the requests which have been attempted to be created in the background, but for which this has failed for one reason or another. Check the job queue to find the error. Requests here may need to be created manually, or it may be possible to re-queue the request for auto-creation by the tool, or it may have been created already. Use your own technical discretion here.', |
|
137 | - 'showAll' => false |
|
138 | - ); |
|
139 | - } |
|
140 | - } |
|
141 | - |
|
142 | - /** |
|
143 | - * @param PdoDatabase $database |
|
144 | - * @param SiteConfiguration $config |
|
145 | - * @param $requestSectionData |
|
146 | - */ |
|
147 | - private function setupJobQueue( |
|
148 | - PdoDatabase $database, |
|
149 | - SiteConfiguration $config, |
|
150 | - &$requestSectionData |
|
151 | - ) { |
|
152 | - // FIXME: domains! |
|
153 | - $search = RequestSearchHelper::get($database, 1) |
|
154 | - ->limit($config->getMiserModeLimit()) |
|
155 | - ->byStatus(RequestStatus::JOBQUEUE); |
|
156 | - |
|
157 | - if ($config->getEmailConfirmationEnabled()) { |
|
158 | - $search->withConfirmedEmail(); |
|
159 | - } |
|
160 | - |
|
161 | - /** @var Request[] $results */ |
|
162 | - $results = $search->getRecordCount($requestCount)->fetch(); |
|
163 | - |
|
164 | - if ($requestCount > 0) { |
|
165 | - $requestSectionData['Requests queued in the Job Queue'] = array( |
|
166 | - 'requests' => $this->prepareRequestData($results), |
|
167 | - 'total' => $requestCount, |
|
168 | - 'api' => 'JobQueue', |
|
169 | - 'type' => 'JobQueue', |
|
170 | - 'special' => 'Job Queue', |
|
171 | - 'help' => 'This section lists all the requests which are currently waiting to be created by the tool. Requests should automatically disappear from here within a few minutes.', |
|
172 | - 'showAll' => false |
|
173 | - ); |
|
174 | - } |
|
175 | - } |
|
176 | - |
|
177 | - /** |
|
178 | - * @param PdoDatabase $database |
|
179 | - * @param SiteConfiguration $config |
|
180 | - * @param $requestSectionData |
|
181 | - */ |
|
182 | - private function setupStatusSections( |
|
183 | - PdoDatabase $database, |
|
184 | - SiteConfiguration $config, |
|
185 | - &$requestSectionData |
|
186 | - ) { |
|
187 | - // FIXME: domains! |
|
188 | - $search = RequestSearchHelper::get($database, 1)->limit($config->getMiserModeLimit()); |
|
189 | - $search->byStatus(RequestStatus::OPEN); |
|
190 | - |
|
191 | - if ($config->getEmailConfirmationEnabled()) { |
|
192 | - $search->withConfirmedEmail(); |
|
193 | - } |
|
194 | - |
|
195 | - // FIXME: domains! |
|
196 | - $requestQueues = RequestQueue::getAllQueues($database); |
|
197 | - $queuesById = array_reduce($requestQueues, function($result, RequestQueue $item) { |
|
198 | - $result[$item->getId()] = $item; |
|
199 | - return $result; |
|
200 | - }, array()); |
|
201 | - |
|
202 | - $requestsByQueue = $search->fetchByQueue(array_keys($queuesById)); |
|
203 | - |
|
204 | - foreach ($requestsByQueue as $queueId => $queueData) { |
|
205 | - if ($queueData['count'] > 0 || $queuesById[$queueId]->isEnabled()) { |
|
206 | - $requestSectionData[$queuesById[$queueId]->getHeader()] = array( |
|
207 | - 'requests' => $this->prepareRequestData($queueData['data']), |
|
208 | - 'total' => $queueData['count'], |
|
209 | - 'api' => $queuesById[$queueId]->getApiName(), |
|
210 | - 'type' => $queueId, |
|
211 | - 'special' => null, |
|
212 | - 'help' => $queuesById[$queueId]->getHelp(), |
|
213 | - 'showAll' => true |
|
214 | - ); |
|
215 | - } |
|
216 | - } |
|
217 | - } |
|
98 | + $statement = $database->prepare($query); |
|
99 | + $statement->execute(); |
|
100 | + |
|
101 | + $last5result = $statement->fetchAll(PDO::FETCH_ASSOC); |
|
102 | + |
|
103 | + $this->assign('lastFive', $last5result); |
|
104 | + } |
|
105 | + |
|
106 | + /** |
|
107 | + * @param PdoDatabase $database |
|
108 | + * @param SiteConfiguration $config |
|
109 | + * @param $requestSectionData |
|
110 | + */ |
|
111 | + private function setupHospitalQueue( |
|
112 | + PdoDatabase $database, |
|
113 | + SiteConfiguration $config, |
|
114 | + &$requestSectionData |
|
115 | + ) { |
|
116 | + // FIXME: domains! |
|
117 | + $search = RequestSearchHelper::get($database, 1) |
|
118 | + ->limit($config->getMiserModeLimit()) |
|
119 | + ->excludingStatus('Closed') |
|
120 | + ->isHospitalised(); |
|
121 | + |
|
122 | + if ($config->getEmailConfirmationEnabled()) { |
|
123 | + $search->withConfirmedEmail(); |
|
124 | + } |
|
125 | + |
|
126 | + /** @var Request[] $results */ |
|
127 | + $results = $search->getRecordCount($requestCount)->fetch(); |
|
128 | + |
|
129 | + if ($requestCount > 0) { |
|
130 | + $requestSectionData['Hospital - Requests failed auto-creation'] = array( |
|
131 | + 'requests' => $this->prepareRequestData($results), |
|
132 | + 'total' => $requestCount, |
|
133 | + 'api' => 'hospital', |
|
134 | + 'type' => 'hospital', |
|
135 | + 'special' => 'Job Queue', |
|
136 | + 'help' => 'This queue lists all the requests which have been attempted to be created in the background, but for which this has failed for one reason or another. Check the job queue to find the error. Requests here may need to be created manually, or it may be possible to re-queue the request for auto-creation by the tool, or it may have been created already. Use your own technical discretion here.', |
|
137 | + 'showAll' => false |
|
138 | + ); |
|
139 | + } |
|
140 | + } |
|
141 | + |
|
142 | + /** |
|
143 | + * @param PdoDatabase $database |
|
144 | + * @param SiteConfiguration $config |
|
145 | + * @param $requestSectionData |
|
146 | + */ |
|
147 | + private function setupJobQueue( |
|
148 | + PdoDatabase $database, |
|
149 | + SiteConfiguration $config, |
|
150 | + &$requestSectionData |
|
151 | + ) { |
|
152 | + // FIXME: domains! |
|
153 | + $search = RequestSearchHelper::get($database, 1) |
|
154 | + ->limit($config->getMiserModeLimit()) |
|
155 | + ->byStatus(RequestStatus::JOBQUEUE); |
|
156 | + |
|
157 | + if ($config->getEmailConfirmationEnabled()) { |
|
158 | + $search->withConfirmedEmail(); |
|
159 | + } |
|
160 | + |
|
161 | + /** @var Request[] $results */ |
|
162 | + $results = $search->getRecordCount($requestCount)->fetch(); |
|
163 | + |
|
164 | + if ($requestCount > 0) { |
|
165 | + $requestSectionData['Requests queued in the Job Queue'] = array( |
|
166 | + 'requests' => $this->prepareRequestData($results), |
|
167 | + 'total' => $requestCount, |
|
168 | + 'api' => 'JobQueue', |
|
169 | + 'type' => 'JobQueue', |
|
170 | + 'special' => 'Job Queue', |
|
171 | + 'help' => 'This section lists all the requests which are currently waiting to be created by the tool. Requests should automatically disappear from here within a few minutes.', |
|
172 | + 'showAll' => false |
|
173 | + ); |
|
174 | + } |
|
175 | + } |
|
176 | + |
|
177 | + /** |
|
178 | + * @param PdoDatabase $database |
|
179 | + * @param SiteConfiguration $config |
|
180 | + * @param $requestSectionData |
|
181 | + */ |
|
182 | + private function setupStatusSections( |
|
183 | + PdoDatabase $database, |
|
184 | + SiteConfiguration $config, |
|
185 | + &$requestSectionData |
|
186 | + ) { |
|
187 | + // FIXME: domains! |
|
188 | + $search = RequestSearchHelper::get($database, 1)->limit($config->getMiserModeLimit()); |
|
189 | + $search->byStatus(RequestStatus::OPEN); |
|
190 | + |
|
191 | + if ($config->getEmailConfirmationEnabled()) { |
|
192 | + $search->withConfirmedEmail(); |
|
193 | + } |
|
194 | + |
|
195 | + // FIXME: domains! |
|
196 | + $requestQueues = RequestQueue::getAllQueues($database); |
|
197 | + $queuesById = array_reduce($requestQueues, function($result, RequestQueue $item) { |
|
198 | + $result[$item->getId()] = $item; |
|
199 | + return $result; |
|
200 | + }, array()); |
|
201 | + |
|
202 | + $requestsByQueue = $search->fetchByQueue(array_keys($queuesById)); |
|
203 | + |
|
204 | + foreach ($requestsByQueue as $queueId => $queueData) { |
|
205 | + if ($queueData['count'] > 0 || $queuesById[$queueId]->isEnabled()) { |
|
206 | + $requestSectionData[$queuesById[$queueId]->getHeader()] = array( |
|
207 | + 'requests' => $this->prepareRequestData($queueData['data']), |
|
208 | + 'total' => $queueData['count'], |
|
209 | + 'api' => $queuesById[$queueId]->getApiName(), |
|
210 | + 'type' => $queueId, |
|
211 | + 'special' => null, |
|
212 | + 'help' => $queuesById[$queueId]->getHelp(), |
|
213 | + 'showAll' => true |
|
214 | + ); |
|
215 | + } |
|
216 | + } |
|
217 | + } |
|
218 | 218 | } |
@@ -136,8 +136,7 @@ discard block |
||
136 | 136 | $this->setTemplate('view-request/main-with-checkuser-data.tpl'); |
137 | 137 | $this->setupCheckUserData($request); |
138 | 138 | } |
139 | - } |
|
140 | - else { |
|
139 | + } else { |
|
141 | 140 | $this->setTemplate('view-request/main.tpl'); |
142 | 141 | } |
143 | 142 | } |
@@ -151,8 +150,7 @@ discard block |
||
151 | 150 | if ($request->getStatus() === RequestStatus::CLOSED) { |
152 | 151 | if ($request->getWasCreated()) { |
153 | 152 | $statusSymbol = self::STATUS_SYMBOL_ACCEPTED; |
154 | - } |
|
155 | - else { |
|
153 | + } else { |
|
156 | 154 | $statusSymbol = self::STATUS_SYMBOL_REJECTED; |
157 | 155 | } |
158 | 156 | } |
@@ -304,8 +302,7 @@ discard block |
||
304 | 302 | 'jobId' => $job->getId(), |
305 | 303 | 'jobDesc' => JobQueue::getTaskDescriptions()[$job->getTask()], |
306 | 304 | ); |
307 | - } |
|
308 | - else { |
|
305 | + } else { |
|
309 | 306 | $requestLogs[] = array( |
310 | 307 | 'type' => 'log', |
311 | 308 | 'security' => 'user', |
@@ -33,369 +33,369 @@ |
||
33 | 33 | |
34 | 34 | class PageViewRequest extends InternalPageBase |
35 | 35 | { |
36 | - use RequestData; |
|
37 | - |
|
38 | - const STATUS_SYMBOL_OPEN = 'Ο'; |
|
39 | - const STATUS_SYMBOL_ACCEPTED = '☑'; |
|
40 | - const STATUS_SYMBOL_REJECTED = '☒'; |
|
41 | - |
|
42 | - /** |
|
43 | - * Main function for this page, when no specific actions are called. |
|
44 | - * @throws ApplicationLogicException |
|
45 | - */ |
|
46 | - protected function main() |
|
47 | - { |
|
48 | - // set up csrf protection |
|
49 | - $this->assignCSRFToken(); |
|
50 | - |
|
51 | - // get some useful objects |
|
52 | - $database = $this->getDatabase(); |
|
53 | - $request = $this->getRequest($database, WebRequest::getInt('id')); |
|
54 | - $config = $this->getSiteConfiguration(); |
|
55 | - $currentUser = User::getCurrent($database); |
|
56 | - |
|
57 | - // FIXME: domains! |
|
58 | - /** @var Domain $domain */ |
|
59 | - $domain = Domain::getById(1, $this->getDatabase()); |
|
60 | - $this->assign('mediawikiScriptPath', $domain->getWikiArticlePath()); |
|
61 | - |
|
62 | - // Shows a page if the email is not confirmed. |
|
63 | - if ($request->getEmailConfirm() !== 'Confirmed') { |
|
64 | - // Show a banner if the user can manually confirm the request |
|
65 | - $viewConfirm = $this->barrierTest(RoleConfigurationBase::MAIN, $currentUser, PageManuallyConfirm::class); |
|
66 | - |
|
67 | - // If the request is purged, there's nothing to confirm! |
|
68 | - if ($request->getEmail() === $this->getSiteConfiguration()->getDataClearEmail()) { |
|
69 | - $viewConfirm = false; |
|
70 | - } |
|
71 | - |
|
72 | - // Render |
|
73 | - $this->setTemplate("view-request/not-confirmed.tpl"); |
|
74 | - $this->assign("requestId", $request->getId()); |
|
75 | - $this->assign("requestVersion", $request->getUpdateVersion()); |
|
76 | - $this->assign('canViewConfirmButton', $viewConfirm); |
|
77 | - |
|
78 | - // Make sure to return, to prevent the leaking of other information. |
|
79 | - return; |
|
80 | - } |
|
81 | - |
|
82 | - $this->setupBasicData($request, $config); |
|
83 | - |
|
84 | - $this->setupUsernameData($request); |
|
85 | - |
|
86 | - $this->setupTitle($request); |
|
87 | - |
|
88 | - $this->setupReservationDetails($request->getReserved(), $database, $currentUser); |
|
89 | - $this->setupGeneralData($database); |
|
90 | - |
|
91 | - $this->assign('requestDataCleared', false); |
|
92 | - if ($request->getEmail() === $this->getSiteConfiguration()->getDataClearEmail()) { |
|
93 | - $this->assign('requestDataCleared', true); |
|
94 | - } |
|
95 | - |
|
96 | - $allowedPrivateData = $this->isAllowedPrivateData($request, $currentUser); |
|
97 | - |
|
98 | - $this->setupCreationTypes($currentUser); |
|
99 | - |
|
100 | - $this->setupLogData($request, $database, $allowedPrivateData); |
|
101 | - |
|
102 | - $this->addJs("/api.php?action=templates&targetVariable=templateconfirms"); |
|
103 | - |
|
104 | - $this->assign('showRevealLink', false); |
|
105 | - if ($request->getReserved() === $currentUser->getId() || |
|
106 | - $this->barrierTest('alwaysSeeHash', $currentUser, 'RequestData') |
|
107 | - ) { |
|
108 | - $this->assign('showRevealLink', true); |
|
109 | - $this->assign('revealHash', $request->getRevealHash()); |
|
110 | - } |
|
111 | - |
|
112 | - $this->assign('canSeeRelatedRequests', false); |
|
113 | - if ($allowedPrivateData || $this->barrierTest('seeRelatedRequests', $currentUser, 'RequestData')) { |
|
114 | - $this->setupRelatedRequests($request, $config, $database); |
|
115 | - } |
|
116 | - |
|
117 | - $this->assign('canCreateLocalAccount', $this->barrierTest('createLocalAccount', $currentUser, 'RequestData')); |
|
118 | - |
|
119 | - $closureDate = $request->getClosureDate(); |
|
120 | - $date = new DateTime(); |
|
121 | - $date->modify("-7 days"); |
|
122 | - if ($request->getStatus() == "Closed" && $closureDate < $date) { |
|
123 | - $this->assign('isOldRequest', true); |
|
124 | - } |
|
125 | - $this->assign('canResetOldRequest', $this->barrierTest('reopenOldRequest', $currentUser, 'RequestData')); |
|
126 | - $this->assign('canResetPurgedRequest', $this->barrierTest('reopenClearedRequest', $currentUser, 'RequestData')); |
|
127 | - |
|
128 | - $this->assign('requestEmailSent', $request->getEmailSent()); |
|
129 | - |
|
130 | - if ($allowedPrivateData) { |
|
131 | - $this->setTemplate('view-request/main-with-data.tpl'); |
|
132 | - $this->setupPrivateData($request, $config); |
|
133 | - $this->assign('canSetBan', $this->barrierTest('set', $currentUser, PageBan::class)); |
|
134 | - $this->assign('canSeeCheckuserData', $this->barrierTest('seeUserAgentData', $currentUser, 'RequestData')); |
|
135 | - |
|
136 | - if ($this->barrierTest('seeUserAgentData', $currentUser, 'RequestData')) { |
|
137 | - $this->setTemplate('view-request/main-with-checkuser-data.tpl'); |
|
138 | - $this->setupCheckUserData($request); |
|
139 | - } |
|
140 | - } |
|
141 | - else { |
|
142 | - $this->setTemplate('view-request/main.tpl'); |
|
143 | - } |
|
144 | - } |
|
145 | - |
|
146 | - /** |
|
147 | - * @param Request $request |
|
148 | - */ |
|
149 | - protected function setupTitle(Request $request) |
|
150 | - { |
|
151 | - $statusSymbol = self::STATUS_SYMBOL_OPEN; |
|
152 | - if ($request->getStatus() === RequestStatus::CLOSED) { |
|
153 | - if ($request->getWasCreated()) { |
|
154 | - $statusSymbol = self::STATUS_SYMBOL_ACCEPTED; |
|
155 | - } |
|
156 | - else { |
|
157 | - $statusSymbol = self::STATUS_SYMBOL_REJECTED; |
|
158 | - } |
|
159 | - } |
|
160 | - |
|
161 | - $this->setHtmlTitle($statusSymbol . ' #' . $request->getId()); |
|
162 | - } |
|
163 | - |
|
164 | - /** |
|
165 | - * Sets up data unrelated to the request, such as the email template information |
|
166 | - * |
|
167 | - * @param PdoDatabase $database |
|
168 | - */ |
|
169 | - protected function setupGeneralData(PdoDatabase $database) |
|
170 | - { |
|
171 | - $this->assign('createAccountReason', 'Requested account at [[WP:ACC]], request #'); |
|
172 | - |
|
173 | - // FIXME: domains |
|
174 | - /** @var Domain $domain */ |
|
175 | - $domain = Domain::getById(1, $database); |
|
176 | - $this->assign('defaultRequestState', RequestQueue::getDefaultQueue($database, 1)->getApiName()); |
|
177 | - $this->assign('activeRequestQueues', RequestQueue::getEnabledQueues($database)); |
|
178 | - |
|
179 | - /** @var EmailTemplate $createdTemplate */ |
|
180 | - $createdTemplate = EmailTemplate::getById($domain->getDefaultClose(), $database); |
|
181 | - |
|
182 | - $this->assign('createdHasJsQuestion', $createdTemplate->getJsquestion() != ''); |
|
183 | - $this->assign('createdId', $createdTemplate->getId()); |
|
184 | - $this->assign('createdName', $createdTemplate->getName()); |
|
185 | - |
|
186 | - $preferenceManager = PreferenceManager::getForCurrent($database); |
|
187 | - $skipJsAborts = $preferenceManager->getPreference(PreferenceManager::PREF_SKIP_JS_ABORT); |
|
188 | - $preferredCreationMode = (int)$preferenceManager->getPreference(PreferenceManager::PREF_CREATION_MODE); |
|
189 | - $this->assign('skipJsAborts', $skipJsAborts); |
|
190 | - $this->assign('preferredCreationMode', $preferredCreationMode); |
|
191 | - |
|
192 | - $createReasons = EmailTemplate::getActiveNonpreloadTemplates( |
|
193 | - EmailTemplate::ACTION_CREATED, |
|
194 | - $database, |
|
195 | - $domain->getId(), |
|
196 | - $domain->getDefaultClose()); |
|
197 | - $this->assign("createReasons", $createReasons); |
|
198 | - |
|
199 | - $declineReasons = EmailTemplate::getActiveNonpreloadTemplates( |
|
200 | - EmailTemplate::ACTION_NOT_CREATED, |
|
201 | - $database, |
|
202 | - $domain->getId()); |
|
203 | - $this->assign("declineReasons", $declineReasons); |
|
204 | - |
|
205 | - $allCreateReasons = EmailTemplate::getAllActiveTemplates( |
|
206 | - EmailTemplate::ACTION_CREATED, |
|
207 | - $database, |
|
208 | - $domain->getId()); |
|
209 | - $this->assign("allCreateReasons", $allCreateReasons); |
|
210 | - |
|
211 | - $allDeclineReasons = EmailTemplate::getAllActiveTemplates( |
|
212 | - EmailTemplate::ACTION_NOT_CREATED, |
|
213 | - $database, |
|
214 | - $domain->getId()); |
|
215 | - $this->assign("allDeclineReasons", $allDeclineReasons); |
|
216 | - |
|
217 | - $allOtherReasons = EmailTemplate::getAllActiveTemplates( |
|
218 | - false, |
|
219 | - $database, |
|
220 | - $domain->getId()); |
|
221 | - $this->assign("allOtherReasons", $allOtherReasons); |
|
222 | - } |
|
223 | - |
|
224 | - private function setupLogData(Request $request, PdoDatabase $database, bool $allowedPrivateData) |
|
225 | - { |
|
226 | - $currentUser = User::getCurrent($database); |
|
227 | - |
|
228 | - $logs = LogHelper::getRequestLogsWithComments($request->getId(), $database, $this->getSecurityManager()); |
|
229 | - $requestLogs = array(); |
|
230 | - |
|
231 | - /** @var User[] $nameCache */ |
|
232 | - $nameCache = array(); |
|
233 | - |
|
234 | - $editableComments = $this->barrierTest('editOthers', $currentUser, PageEditComment::class); |
|
235 | - |
|
236 | - $canFlag = $this->barrierTest(RoleConfigurationBase::MAIN, $currentUser, PageFlagComment::class); |
|
237 | - $canUnflag = $this->barrierTest('unflag', $currentUser, PageFlagComment::class); |
|
238 | - |
|
239 | - /** @var Log|Comment $entry */ |
|
240 | - foreach ($logs as $entry) { |
|
241 | - // both log and comment have a 'user' field |
|
242 | - if (!array_key_exists($entry->getUser(), $nameCache)) { |
|
243 | - $entryUser = User::getById($entry->getUser(), $database); |
|
244 | - $nameCache[$entry->getUser()] = $entryUser; |
|
245 | - } |
|
246 | - |
|
247 | - if ($entry instanceof Comment) { |
|
248 | - // Determine if the comment contains private information. |
|
249 | - // Private defined as flagged or restricted visibility, but only when the user isn't allowed |
|
250 | - // to see private data |
|
251 | - $commentIsRestricted = |
|
252 | - ($entry->getFlagged() |
|
253 | - || $entry->getVisibility() == 'admin' || $entry->getVisibility() == 'checkuser') |
|
254 | - && !$allowedPrivateData; |
|
255 | - |
|
256 | - // Only allow comment editing if the user is able to edit comments or this is the user's own comment, |
|
257 | - // but only when they're allowed to see the comment itself. |
|
258 | - $commentIsEditable = ($editableComments || $entry->getUser() == $currentUser->getId()) |
|
259 | - && !$commentIsRestricted; |
|
260 | - |
|
261 | - // Flagging/unflagging can only be done if you can see the comment |
|
262 | - $canFlagThisComment = $canFlag |
|
263 | - && ( |
|
264 | - (!$entry->getFlagged() && !$commentIsRestricted) |
|
265 | - || ($entry->getFlagged() && $canUnflag && $commentIsEditable) |
|
266 | - ); |
|
267 | - |
|
268 | - $requestLogs[] = array( |
|
269 | - 'type' => 'comment', |
|
270 | - 'security' => $entry->getVisibility(), |
|
271 | - 'user' => $entry->getVisibility() == 'requester' ? $request->getName() : $nameCache[$entry->getUser()]->getUsername(), |
|
272 | - 'userid' => $entry->getUser() == -1 ? null : $entry->getUser(), |
|
273 | - 'entry' => null, |
|
274 | - 'time' => $entry->getTime(), |
|
275 | - 'canedit' => $commentIsEditable, |
|
276 | - 'id' => $entry->getId(), |
|
277 | - 'comment' => $entry->getComment(), |
|
278 | - 'flagged' => $entry->getFlagged(), |
|
279 | - 'canflag' => $canFlagThisComment, |
|
280 | - 'updateversion' => $entry->getUpdateVersion(), |
|
281 | - 'edited' => $entry->getEdited(), |
|
282 | - 'hidden' => $commentIsRestricted |
|
283 | - ); |
|
284 | - } |
|
285 | - |
|
286 | - if ($entry instanceof Log) { |
|
287 | - $invalidUserId = $entry->getUser() === -1 || $entry->getUser() === 0; |
|
288 | - $entryUser = $invalidUserId ? User::getCommunity() : $nameCache[$entry->getUser()]; |
|
289 | - |
|
290 | - $entryComment = $entry->getComment(); |
|
291 | - |
|
292 | - if ($entry->getAction() === 'JobIssueRequest' || $entry->getAction() === 'JobCompletedRequest') { |
|
293 | - $data = unserialize($entry->getComment()); |
|
294 | - /** @var JobQueue $job */ |
|
295 | - $job = JobQueue::getById($data['job'], $database); |
|
296 | - $requestLogs[] = array( |
|
297 | - 'type' => 'joblog', |
|
298 | - 'security' => 'user', |
|
299 | - 'userid' => $entry->getUser() == -1 ? null : $entry->getUser(), |
|
300 | - 'user' => $entryUser->getUsername(), |
|
301 | - 'entry' => LogHelper::getLogDescription($entry), |
|
302 | - 'time' => $entry->getTimestamp(), |
|
303 | - 'canedit' => false, |
|
304 | - 'id' => $entry->getId(), |
|
305 | - 'jobId' => $job->getId(), |
|
306 | - 'jobDesc' => JobQueue::getTaskDescriptions()[$job->getTask()], |
|
307 | - ); |
|
308 | - } |
|
309 | - else { |
|
310 | - $requestLogs[] = array( |
|
311 | - 'type' => 'log', |
|
312 | - 'security' => 'user', |
|
313 | - 'userid' => $entry->getUser() == -1 ? null : $entry->getUser(), |
|
314 | - 'user' => $entryUser->getUsername(), |
|
315 | - 'entry' => LogHelper::getLogDescription($entry), |
|
316 | - 'time' => $entry->getTimestamp(), |
|
317 | - 'canedit' => false, |
|
318 | - 'id' => $entry->getId(), |
|
319 | - 'comment' => $entryComment, |
|
320 | - ); |
|
321 | - } |
|
322 | - } |
|
323 | - } |
|
324 | - |
|
325 | - $this->addJs("/api.php?action=users&targetVariable=typeaheaddata"); |
|
326 | - |
|
327 | - $this->assign("requestLogs", $requestLogs); |
|
328 | - } |
|
329 | - |
|
330 | - /** |
|
331 | - * @param Request $request |
|
332 | - */ |
|
333 | - protected function setupUsernameData(Request $request) |
|
334 | - { |
|
335 | - $blacklistData = $this->getBlacklistHelper()->isBlacklisted($request->getName()); |
|
336 | - |
|
337 | - $this->assign('requestIsBlacklisted', $blacklistData !== false); |
|
338 | - $this->assign('requestBlacklist', $blacklistData); |
|
339 | - |
|
340 | - try { |
|
341 | - $spoofs = $this->getAntiSpoofProvider()->getSpoofs($request->getName()); |
|
342 | - } |
|
343 | - catch (Exception $ex) { |
|
344 | - $spoofs = $ex->getMessage(); |
|
345 | - } |
|
346 | - |
|
347 | - $this->assign("spoofs", $spoofs); |
|
348 | - } |
|
349 | - |
|
350 | - private function setupCreationTypes(User $user) |
|
351 | - { |
|
352 | - $this->assign('allowWelcomeSkip', false); |
|
353 | - $this->assign('forceWelcomeSkip', false); |
|
354 | - |
|
355 | - $database = $this->getDatabase(); |
|
356 | - $preferenceManager = PreferenceManager::getForCurrent($database); |
|
357 | - |
|
358 | - $oauth = new OAuthUserHelper($user, $database, $this->getOAuthProtocolHelper(), $this->getSiteConfiguration()); |
|
359 | - |
|
360 | - $welcomeTemplate = $preferenceManager->getPreference(PreferenceManager::PREF_WELCOMETEMPLATE); |
|
361 | - |
|
362 | - if ($welcomeTemplate != null) { |
|
363 | - $this->assign('allowWelcomeSkip', true); |
|
364 | - |
|
365 | - if (!$oauth->canWelcome()) { |
|
366 | - $this->assign('forceWelcomeSkip', true); |
|
367 | - } |
|
368 | - } |
|
369 | - |
|
370 | - // test credentials |
|
371 | - $canManualCreate = $this->barrierTest(PreferenceManager::CREATION_MANUAL, $user, 'RequestCreation'); |
|
372 | - $canOauthCreate = $this->barrierTest(PreferenceManager::CREATION_OAUTH, $user, 'RequestCreation'); |
|
373 | - $canBotCreate = $this->barrierTest(PreferenceManager::CREATION_BOT, $user, 'RequestCreation'); |
|
374 | - |
|
375 | - $this->assign('canManualCreate', $canManualCreate); |
|
376 | - $this->assign('canOauthCreate', $canOauthCreate); |
|
377 | - $this->assign('canBotCreate', $canBotCreate); |
|
378 | - |
|
379 | - // show/hide the type radio buttons |
|
380 | - $creationHasChoice = count(array_filter([$canManualCreate, $canOauthCreate, $canBotCreate])) > 1; |
|
381 | - |
|
382 | - $creationModePreference = $preferenceManager->getPreference(PreferenceManager::PREF_CREATION_MODE); |
|
383 | - if (!$this->barrierTest($creationModePreference, $user, 'RequestCreation')) { |
|
384 | - // user is not allowed to use their default. Force a choice. |
|
385 | - $creationHasChoice = true; |
|
386 | - } |
|
387 | - |
|
388 | - $this->assign('creationHasChoice', $creationHasChoice); |
|
389 | - |
|
390 | - // determine problems in creation types |
|
391 | - $this->assign('botProblem', false); |
|
392 | - if ($canBotCreate && $this->getSiteConfiguration()->getCreationBotPassword() === null) { |
|
393 | - $this->assign('botProblem', true); |
|
394 | - } |
|
395 | - |
|
396 | - $this->assign('oauthProblem', false); |
|
397 | - if ($canOauthCreate && !$oauth->canCreateAccount()) { |
|
398 | - $this->assign('oauthProblem', true); |
|
399 | - } |
|
400 | - } |
|
36 | + use RequestData; |
|
37 | + |
|
38 | + const STATUS_SYMBOL_OPEN = 'Ο'; |
|
39 | + const STATUS_SYMBOL_ACCEPTED = '☑'; |
|
40 | + const STATUS_SYMBOL_REJECTED = '☒'; |
|
41 | + |
|
42 | + /** |
|
43 | + * Main function for this page, when no specific actions are called. |
|
44 | + * @throws ApplicationLogicException |
|
45 | + */ |
|
46 | + protected function main() |
|
47 | + { |
|
48 | + // set up csrf protection |
|
49 | + $this->assignCSRFToken(); |
|
50 | + |
|
51 | + // get some useful objects |
|
52 | + $database = $this->getDatabase(); |
|
53 | + $request = $this->getRequest($database, WebRequest::getInt('id')); |
|
54 | + $config = $this->getSiteConfiguration(); |
|
55 | + $currentUser = User::getCurrent($database); |
|
56 | + |
|
57 | + // FIXME: domains! |
|
58 | + /** @var Domain $domain */ |
|
59 | + $domain = Domain::getById(1, $this->getDatabase()); |
|
60 | + $this->assign('mediawikiScriptPath', $domain->getWikiArticlePath()); |
|
61 | + |
|
62 | + // Shows a page if the email is not confirmed. |
|
63 | + if ($request->getEmailConfirm() !== 'Confirmed') { |
|
64 | + // Show a banner if the user can manually confirm the request |
|
65 | + $viewConfirm = $this->barrierTest(RoleConfigurationBase::MAIN, $currentUser, PageManuallyConfirm::class); |
|
66 | + |
|
67 | + // If the request is purged, there's nothing to confirm! |
|
68 | + if ($request->getEmail() === $this->getSiteConfiguration()->getDataClearEmail()) { |
|
69 | + $viewConfirm = false; |
|
70 | + } |
|
71 | + |
|
72 | + // Render |
|
73 | + $this->setTemplate("view-request/not-confirmed.tpl"); |
|
74 | + $this->assign("requestId", $request->getId()); |
|
75 | + $this->assign("requestVersion", $request->getUpdateVersion()); |
|
76 | + $this->assign('canViewConfirmButton', $viewConfirm); |
|
77 | + |
|
78 | + // Make sure to return, to prevent the leaking of other information. |
|
79 | + return; |
|
80 | + } |
|
81 | + |
|
82 | + $this->setupBasicData($request, $config); |
|
83 | + |
|
84 | + $this->setupUsernameData($request); |
|
85 | + |
|
86 | + $this->setupTitle($request); |
|
87 | + |
|
88 | + $this->setupReservationDetails($request->getReserved(), $database, $currentUser); |
|
89 | + $this->setupGeneralData($database); |
|
90 | + |
|
91 | + $this->assign('requestDataCleared', false); |
|
92 | + if ($request->getEmail() === $this->getSiteConfiguration()->getDataClearEmail()) { |
|
93 | + $this->assign('requestDataCleared', true); |
|
94 | + } |
|
95 | + |
|
96 | + $allowedPrivateData = $this->isAllowedPrivateData($request, $currentUser); |
|
97 | + |
|
98 | + $this->setupCreationTypes($currentUser); |
|
99 | + |
|
100 | + $this->setupLogData($request, $database, $allowedPrivateData); |
|
101 | + |
|
102 | + $this->addJs("/api.php?action=templates&targetVariable=templateconfirms"); |
|
103 | + |
|
104 | + $this->assign('showRevealLink', false); |
|
105 | + if ($request->getReserved() === $currentUser->getId() || |
|
106 | + $this->barrierTest('alwaysSeeHash', $currentUser, 'RequestData') |
|
107 | + ) { |
|
108 | + $this->assign('showRevealLink', true); |
|
109 | + $this->assign('revealHash', $request->getRevealHash()); |
|
110 | + } |
|
111 | + |
|
112 | + $this->assign('canSeeRelatedRequests', false); |
|
113 | + if ($allowedPrivateData || $this->barrierTest('seeRelatedRequests', $currentUser, 'RequestData')) { |
|
114 | + $this->setupRelatedRequests($request, $config, $database); |
|
115 | + } |
|
116 | + |
|
117 | + $this->assign('canCreateLocalAccount', $this->barrierTest('createLocalAccount', $currentUser, 'RequestData')); |
|
118 | + |
|
119 | + $closureDate = $request->getClosureDate(); |
|
120 | + $date = new DateTime(); |
|
121 | + $date->modify("-7 days"); |
|
122 | + if ($request->getStatus() == "Closed" && $closureDate < $date) { |
|
123 | + $this->assign('isOldRequest', true); |
|
124 | + } |
|
125 | + $this->assign('canResetOldRequest', $this->barrierTest('reopenOldRequest', $currentUser, 'RequestData')); |
|
126 | + $this->assign('canResetPurgedRequest', $this->barrierTest('reopenClearedRequest', $currentUser, 'RequestData')); |
|
127 | + |
|
128 | + $this->assign('requestEmailSent', $request->getEmailSent()); |
|
129 | + |
|
130 | + if ($allowedPrivateData) { |
|
131 | + $this->setTemplate('view-request/main-with-data.tpl'); |
|
132 | + $this->setupPrivateData($request, $config); |
|
133 | + $this->assign('canSetBan', $this->barrierTest('set', $currentUser, PageBan::class)); |
|
134 | + $this->assign('canSeeCheckuserData', $this->barrierTest('seeUserAgentData', $currentUser, 'RequestData')); |
|
135 | + |
|
136 | + if ($this->barrierTest('seeUserAgentData', $currentUser, 'RequestData')) { |
|
137 | + $this->setTemplate('view-request/main-with-checkuser-data.tpl'); |
|
138 | + $this->setupCheckUserData($request); |
|
139 | + } |
|
140 | + } |
|
141 | + else { |
|
142 | + $this->setTemplate('view-request/main.tpl'); |
|
143 | + } |
|
144 | + } |
|
145 | + |
|
146 | + /** |
|
147 | + * @param Request $request |
|
148 | + */ |
|
149 | + protected function setupTitle(Request $request) |
|
150 | + { |
|
151 | + $statusSymbol = self::STATUS_SYMBOL_OPEN; |
|
152 | + if ($request->getStatus() === RequestStatus::CLOSED) { |
|
153 | + if ($request->getWasCreated()) { |
|
154 | + $statusSymbol = self::STATUS_SYMBOL_ACCEPTED; |
|
155 | + } |
|
156 | + else { |
|
157 | + $statusSymbol = self::STATUS_SYMBOL_REJECTED; |
|
158 | + } |
|
159 | + } |
|
160 | + |
|
161 | + $this->setHtmlTitle($statusSymbol . ' #' . $request->getId()); |
|
162 | + } |
|
163 | + |
|
164 | + /** |
|
165 | + * Sets up data unrelated to the request, such as the email template information |
|
166 | + * |
|
167 | + * @param PdoDatabase $database |
|
168 | + */ |
|
169 | + protected function setupGeneralData(PdoDatabase $database) |
|
170 | + { |
|
171 | + $this->assign('createAccountReason', 'Requested account at [[WP:ACC]], request #'); |
|
172 | + |
|
173 | + // FIXME: domains |
|
174 | + /** @var Domain $domain */ |
|
175 | + $domain = Domain::getById(1, $database); |
|
176 | + $this->assign('defaultRequestState', RequestQueue::getDefaultQueue($database, 1)->getApiName()); |
|
177 | + $this->assign('activeRequestQueues', RequestQueue::getEnabledQueues($database)); |
|
178 | + |
|
179 | + /** @var EmailTemplate $createdTemplate */ |
|
180 | + $createdTemplate = EmailTemplate::getById($domain->getDefaultClose(), $database); |
|
181 | + |
|
182 | + $this->assign('createdHasJsQuestion', $createdTemplate->getJsquestion() != ''); |
|
183 | + $this->assign('createdId', $createdTemplate->getId()); |
|
184 | + $this->assign('createdName', $createdTemplate->getName()); |
|
185 | + |
|
186 | + $preferenceManager = PreferenceManager::getForCurrent($database); |
|
187 | + $skipJsAborts = $preferenceManager->getPreference(PreferenceManager::PREF_SKIP_JS_ABORT); |
|
188 | + $preferredCreationMode = (int)$preferenceManager->getPreference(PreferenceManager::PREF_CREATION_MODE); |
|
189 | + $this->assign('skipJsAborts', $skipJsAborts); |
|
190 | + $this->assign('preferredCreationMode', $preferredCreationMode); |
|
191 | + |
|
192 | + $createReasons = EmailTemplate::getActiveNonpreloadTemplates( |
|
193 | + EmailTemplate::ACTION_CREATED, |
|
194 | + $database, |
|
195 | + $domain->getId(), |
|
196 | + $domain->getDefaultClose()); |
|
197 | + $this->assign("createReasons", $createReasons); |
|
198 | + |
|
199 | + $declineReasons = EmailTemplate::getActiveNonpreloadTemplates( |
|
200 | + EmailTemplate::ACTION_NOT_CREATED, |
|
201 | + $database, |
|
202 | + $domain->getId()); |
|
203 | + $this->assign("declineReasons", $declineReasons); |
|
204 | + |
|
205 | + $allCreateReasons = EmailTemplate::getAllActiveTemplates( |
|
206 | + EmailTemplate::ACTION_CREATED, |
|
207 | + $database, |
|
208 | + $domain->getId()); |
|
209 | + $this->assign("allCreateReasons", $allCreateReasons); |
|
210 | + |
|
211 | + $allDeclineReasons = EmailTemplate::getAllActiveTemplates( |
|
212 | + EmailTemplate::ACTION_NOT_CREATED, |
|
213 | + $database, |
|
214 | + $domain->getId()); |
|
215 | + $this->assign("allDeclineReasons", $allDeclineReasons); |
|
216 | + |
|
217 | + $allOtherReasons = EmailTemplate::getAllActiveTemplates( |
|
218 | + false, |
|
219 | + $database, |
|
220 | + $domain->getId()); |
|
221 | + $this->assign("allOtherReasons", $allOtherReasons); |
|
222 | + } |
|
223 | + |
|
224 | + private function setupLogData(Request $request, PdoDatabase $database, bool $allowedPrivateData) |
|
225 | + { |
|
226 | + $currentUser = User::getCurrent($database); |
|
227 | + |
|
228 | + $logs = LogHelper::getRequestLogsWithComments($request->getId(), $database, $this->getSecurityManager()); |
|
229 | + $requestLogs = array(); |
|
230 | + |
|
231 | + /** @var User[] $nameCache */ |
|
232 | + $nameCache = array(); |
|
233 | + |
|
234 | + $editableComments = $this->barrierTest('editOthers', $currentUser, PageEditComment::class); |
|
235 | + |
|
236 | + $canFlag = $this->barrierTest(RoleConfigurationBase::MAIN, $currentUser, PageFlagComment::class); |
|
237 | + $canUnflag = $this->barrierTest('unflag', $currentUser, PageFlagComment::class); |
|
238 | + |
|
239 | + /** @var Log|Comment $entry */ |
|
240 | + foreach ($logs as $entry) { |
|
241 | + // both log and comment have a 'user' field |
|
242 | + if (!array_key_exists($entry->getUser(), $nameCache)) { |
|
243 | + $entryUser = User::getById($entry->getUser(), $database); |
|
244 | + $nameCache[$entry->getUser()] = $entryUser; |
|
245 | + } |
|
246 | + |
|
247 | + if ($entry instanceof Comment) { |
|
248 | + // Determine if the comment contains private information. |
|
249 | + // Private defined as flagged or restricted visibility, but only when the user isn't allowed |
|
250 | + // to see private data |
|
251 | + $commentIsRestricted = |
|
252 | + ($entry->getFlagged() |
|
253 | + || $entry->getVisibility() == 'admin' || $entry->getVisibility() == 'checkuser') |
|
254 | + && !$allowedPrivateData; |
|
255 | + |
|
256 | + // Only allow comment editing if the user is able to edit comments or this is the user's own comment, |
|
257 | + // but only when they're allowed to see the comment itself. |
|
258 | + $commentIsEditable = ($editableComments || $entry->getUser() == $currentUser->getId()) |
|
259 | + && !$commentIsRestricted; |
|
260 | + |
|
261 | + // Flagging/unflagging can only be done if you can see the comment |
|
262 | + $canFlagThisComment = $canFlag |
|
263 | + && ( |
|
264 | + (!$entry->getFlagged() && !$commentIsRestricted) |
|
265 | + || ($entry->getFlagged() && $canUnflag && $commentIsEditable) |
|
266 | + ); |
|
267 | + |
|
268 | + $requestLogs[] = array( |
|
269 | + 'type' => 'comment', |
|
270 | + 'security' => $entry->getVisibility(), |
|
271 | + 'user' => $entry->getVisibility() == 'requester' ? $request->getName() : $nameCache[$entry->getUser()]->getUsername(), |
|
272 | + 'userid' => $entry->getUser() == -1 ? null : $entry->getUser(), |
|
273 | + 'entry' => null, |
|
274 | + 'time' => $entry->getTime(), |
|
275 | + 'canedit' => $commentIsEditable, |
|
276 | + 'id' => $entry->getId(), |
|
277 | + 'comment' => $entry->getComment(), |
|
278 | + 'flagged' => $entry->getFlagged(), |
|
279 | + 'canflag' => $canFlagThisComment, |
|
280 | + 'updateversion' => $entry->getUpdateVersion(), |
|
281 | + 'edited' => $entry->getEdited(), |
|
282 | + 'hidden' => $commentIsRestricted |
|
283 | + ); |
|
284 | + } |
|
285 | + |
|
286 | + if ($entry instanceof Log) { |
|
287 | + $invalidUserId = $entry->getUser() === -1 || $entry->getUser() === 0; |
|
288 | + $entryUser = $invalidUserId ? User::getCommunity() : $nameCache[$entry->getUser()]; |
|
289 | + |
|
290 | + $entryComment = $entry->getComment(); |
|
291 | + |
|
292 | + if ($entry->getAction() === 'JobIssueRequest' || $entry->getAction() === 'JobCompletedRequest') { |
|
293 | + $data = unserialize($entry->getComment()); |
|
294 | + /** @var JobQueue $job */ |
|
295 | + $job = JobQueue::getById($data['job'], $database); |
|
296 | + $requestLogs[] = array( |
|
297 | + 'type' => 'joblog', |
|
298 | + 'security' => 'user', |
|
299 | + 'userid' => $entry->getUser() == -1 ? null : $entry->getUser(), |
|
300 | + 'user' => $entryUser->getUsername(), |
|
301 | + 'entry' => LogHelper::getLogDescription($entry), |
|
302 | + 'time' => $entry->getTimestamp(), |
|
303 | + 'canedit' => false, |
|
304 | + 'id' => $entry->getId(), |
|
305 | + 'jobId' => $job->getId(), |
|
306 | + 'jobDesc' => JobQueue::getTaskDescriptions()[$job->getTask()], |
|
307 | + ); |
|
308 | + } |
|
309 | + else { |
|
310 | + $requestLogs[] = array( |
|
311 | + 'type' => 'log', |
|
312 | + 'security' => 'user', |
|
313 | + 'userid' => $entry->getUser() == -1 ? null : $entry->getUser(), |
|
314 | + 'user' => $entryUser->getUsername(), |
|
315 | + 'entry' => LogHelper::getLogDescription($entry), |
|
316 | + 'time' => $entry->getTimestamp(), |
|
317 | + 'canedit' => false, |
|
318 | + 'id' => $entry->getId(), |
|
319 | + 'comment' => $entryComment, |
|
320 | + ); |
|
321 | + } |
|
322 | + } |
|
323 | + } |
|
324 | + |
|
325 | + $this->addJs("/api.php?action=users&targetVariable=typeaheaddata"); |
|
326 | + |
|
327 | + $this->assign("requestLogs", $requestLogs); |
|
328 | + } |
|
329 | + |
|
330 | + /** |
|
331 | + * @param Request $request |
|
332 | + */ |
|
333 | + protected function setupUsernameData(Request $request) |
|
334 | + { |
|
335 | + $blacklistData = $this->getBlacklistHelper()->isBlacklisted($request->getName()); |
|
336 | + |
|
337 | + $this->assign('requestIsBlacklisted', $blacklistData !== false); |
|
338 | + $this->assign('requestBlacklist', $blacklistData); |
|
339 | + |
|
340 | + try { |
|
341 | + $spoofs = $this->getAntiSpoofProvider()->getSpoofs($request->getName()); |
|
342 | + } |
|
343 | + catch (Exception $ex) { |
|
344 | + $spoofs = $ex->getMessage(); |
|
345 | + } |
|
346 | + |
|
347 | + $this->assign("spoofs", $spoofs); |
|
348 | + } |
|
349 | + |
|
350 | + private function setupCreationTypes(User $user) |
|
351 | + { |
|
352 | + $this->assign('allowWelcomeSkip', false); |
|
353 | + $this->assign('forceWelcomeSkip', false); |
|
354 | + |
|
355 | + $database = $this->getDatabase(); |
|
356 | + $preferenceManager = PreferenceManager::getForCurrent($database); |
|
357 | + |
|
358 | + $oauth = new OAuthUserHelper($user, $database, $this->getOAuthProtocolHelper(), $this->getSiteConfiguration()); |
|
359 | + |
|
360 | + $welcomeTemplate = $preferenceManager->getPreference(PreferenceManager::PREF_WELCOMETEMPLATE); |
|
361 | + |
|
362 | + if ($welcomeTemplate != null) { |
|
363 | + $this->assign('allowWelcomeSkip', true); |
|
364 | + |
|
365 | + if (!$oauth->canWelcome()) { |
|
366 | + $this->assign('forceWelcomeSkip', true); |
|
367 | + } |
|
368 | + } |
|
369 | + |
|
370 | + // test credentials |
|
371 | + $canManualCreate = $this->barrierTest(PreferenceManager::CREATION_MANUAL, $user, 'RequestCreation'); |
|
372 | + $canOauthCreate = $this->barrierTest(PreferenceManager::CREATION_OAUTH, $user, 'RequestCreation'); |
|
373 | + $canBotCreate = $this->barrierTest(PreferenceManager::CREATION_BOT, $user, 'RequestCreation'); |
|
374 | + |
|
375 | + $this->assign('canManualCreate', $canManualCreate); |
|
376 | + $this->assign('canOauthCreate', $canOauthCreate); |
|
377 | + $this->assign('canBotCreate', $canBotCreate); |
|
378 | + |
|
379 | + // show/hide the type radio buttons |
|
380 | + $creationHasChoice = count(array_filter([$canManualCreate, $canOauthCreate, $canBotCreate])) > 1; |
|
381 | + |
|
382 | + $creationModePreference = $preferenceManager->getPreference(PreferenceManager::PREF_CREATION_MODE); |
|
383 | + if (!$this->barrierTest($creationModePreference, $user, 'RequestCreation')) { |
|
384 | + // user is not allowed to use their default. Force a choice. |
|
385 | + $creationHasChoice = true; |
|
386 | + } |
|
387 | + |
|
388 | + $this->assign('creationHasChoice', $creationHasChoice); |
|
389 | + |
|
390 | + // determine problems in creation types |
|
391 | + $this->assign('botProblem', false); |
|
392 | + if ($canBotCreate && $this->getSiteConfiguration()->getCreationBotPassword() === null) { |
|
393 | + $this->assign('botProblem', true); |
|
394 | + } |
|
395 | + |
|
396 | + $this->assign('oauthProblem', false); |
|
397 | + if ($canOauthCreate && !$oauth->canCreateAccount()) { |
|
398 | + $this->assign('oauthProblem', true); |
|
399 | + } |
|
400 | + } |
|
401 | 401 | } |