@@ -23,228 +23,228 @@ |
||
23 | 23 | |
24 | 24 | abstract class InternalPageBase extends PageBase |
25 | 25 | { |
26 | - use NavigationMenuAccessControl; |
|
27 | - |
|
28 | - /** @var IdentificationVerifier */ |
|
29 | - private $identificationVerifier; |
|
30 | - /** @var ITypeAheadHelper */ |
|
31 | - private $typeAheadHelper; |
|
32 | - /** @var SecurityManager */ |
|
33 | - private $securityManager; |
|
34 | - /** @var IBlacklistHelper */ |
|
35 | - private $blacklistHelper; |
|
36 | - |
|
37 | - /** |
|
38 | - * @return ITypeAheadHelper |
|
39 | - */ |
|
40 | - public function getTypeAheadHelper() |
|
41 | - { |
|
42 | - return $this->typeAheadHelper; |
|
43 | - } |
|
44 | - |
|
45 | - /** |
|
46 | - * Sets up the internal IdentificationVerifier instance. Intended to be called from WebStart::setupHelpers(). |
|
47 | - * |
|
48 | - * @param IdentificationVerifier $identificationVerifier |
|
49 | - * |
|
50 | - * @return void |
|
51 | - */ |
|
52 | - public function setIdentificationVerifier(IdentificationVerifier $identificationVerifier) |
|
53 | - { |
|
54 | - $this->identificationVerifier = $identificationVerifier; |
|
55 | - } |
|
56 | - |
|
57 | - /** |
|
58 | - * @param ITypeAheadHelper $typeAheadHelper |
|
59 | - */ |
|
60 | - public function setTypeAheadHelper(ITypeAheadHelper $typeAheadHelper) |
|
61 | - { |
|
62 | - $this->typeAheadHelper = $typeAheadHelper; |
|
63 | - } |
|
64 | - |
|
65 | - /** |
|
66 | - * Runs the page code |
|
67 | - * |
|
68 | - * @throws Exception |
|
69 | - * @category Security-Critical |
|
70 | - */ |
|
71 | - final public function execute() |
|
72 | - { |
|
73 | - if ($this->getRouteName() === null) { |
|
74 | - throw new Exception("Request is unrouted."); |
|
75 | - } |
|
76 | - |
|
77 | - if ($this->getSiteConfiguration() === null) { |
|
78 | - throw new Exception("Page has no configuration!"); |
|
79 | - } |
|
80 | - |
|
81 | - $this->setupPage(); |
|
82 | - |
|
83 | - $this->touchUserLastActive(); |
|
84 | - |
|
85 | - $currentUser = User::getCurrent($this->getDatabase()); |
|
86 | - |
|
87 | - // Hey, this is also a security barrier, in addition to the below. Separated out for readability. |
|
88 | - if (!$this->isProtectedPage()) { |
|
89 | - // This page is /not/ a protected page, as such we can just run it. |
|
90 | - $this->runPage(); |
|
91 | - |
|
92 | - return; |
|
93 | - } |
|
94 | - |
|
95 | - // Security barrier. |
|
96 | - // |
|
97 | - // This code essentially doesn't care if the user is logged in or not, as the security manager hides all that |
|
98 | - // away for us |
|
99 | - $securityResult = $this->getSecurityManager()->allows(get_called_class(), $this->getRouteName(), $currentUser); |
|
100 | - if ($securityResult === SecurityManager::ALLOWED) { |
|
101 | - // We're allowed to run the page, so let's run it. |
|
102 | - $this->runPage(); |
|
103 | - } |
|
104 | - else { |
|
105 | - $this->handleAccessDenied($securityResult); |
|
106 | - |
|
107 | - // Send the headers |
|
108 | - $this->sendResponseHeaders(); |
|
109 | - } |
|
110 | - } |
|
111 | - |
|
112 | - /** |
|
113 | - * Performs final tasks needed before rendering the page. |
|
114 | - */ |
|
115 | - final public function finalisePage() |
|
116 | - { |
|
117 | - parent::finalisePage(); |
|
118 | - |
|
119 | - $database = $this->getDatabase(); |
|
120 | - $currentUser = User::getCurrent($database); |
|
121 | - |
|
122 | - if ($this->barrierTest('viewSiteNotice', User::getCurrent($database), 'GlobalInfo')) { |
|
123 | - $siteNoticeText = SiteNotice::get($this->getDatabase()); |
|
124 | - $this->assign('siteNoticeText', $siteNoticeText); |
|
125 | - } |
|
126 | - |
|
127 | - if ($this->barrierTest('viewOnlineUsers', User::getCurrent($database), 'GlobalInfo')) { |
|
128 | - $sql = 'SELECT * FROM user WHERE lastactive > DATE_SUB(CURRENT_TIMESTAMP(), INTERVAL 5 MINUTE);'; |
|
129 | - $statement = $database->query($sql); |
|
130 | - $activeUsers = $statement->fetchAll(PDO::FETCH_CLASS, User::class); |
|
131 | - $this->assign('onlineusers', $activeUsers); |
|
132 | - } |
|
133 | - |
|
134 | - $this->setupNavMenuAccess($currentUser); |
|
135 | - } |
|
136 | - |
|
137 | - /** |
|
138 | - * Configures whether the page respects roles or not. You probably want this to return true. |
|
139 | - * |
|
140 | - * Set to false for public pages. You probably want this to return true. |
|
141 | - * |
|
142 | - * This defaults to true unless you explicitly set it to false. Setting it to false means anybody can do anything |
|
143 | - * on this page, so you probably want this to return true. |
|
144 | - * |
|
145 | - * @return bool |
|
146 | - * @category Security-Critical |
|
147 | - */ |
|
148 | - protected function isProtectedPage() |
|
149 | - { |
|
150 | - return true; |
|
151 | - } |
|
152 | - |
|
153 | - protected function handleAccessDenied($denyReason) |
|
154 | - { |
|
155 | - $currentUser = User::getCurrent($this->getDatabase()); |
|
156 | - |
|
157 | - // Not allowed to access this resource. |
|
158 | - // Firstly, let's check if we're even logged in. |
|
159 | - if ($currentUser->isCommunityUser()) { |
|
160 | - // Not logged in, redirect to login page |
|
161 | - WebRequest::setPostLoginRedirect(); |
|
162 | - $this->redirect("login"); |
|
163 | - |
|
164 | - return; |
|
165 | - } |
|
166 | - else { |
|
167 | - // Decide whether this was a rights failure, or an identification failure. |
|
168 | - |
|
169 | - if ($denyReason === SecurityManager::ERROR_NOT_IDENTIFIED) { |
|
170 | - // Not identified |
|
171 | - throw new NotIdentifiedException($this->getSecurityManager()); |
|
172 | - } |
|
173 | - elseif ($denyReason === SecurityManager::ERROR_DENIED) { |
|
174 | - // Nope, plain old access denied |
|
175 | - throw new AccessDeniedException($this->getSecurityManager()); |
|
176 | - } |
|
177 | - else { |
|
178 | - throw new Exception('Unknown response from security manager.'); |
|
179 | - } |
|
180 | - } |
|
181 | - } |
|
182 | - |
|
183 | - /** |
|
184 | - * Tests the security barrier for a specified action. |
|
185 | - * |
|
186 | - * Don't use within templates |
|
187 | - * |
|
188 | - * @param string $action |
|
189 | - * |
|
190 | - * @param User $user |
|
191 | - * @param null|string $pageName |
|
192 | - * |
|
193 | - * @return bool |
|
194 | - * @category Security-Critical |
|
195 | - */ |
|
196 | - final public function barrierTest($action, User $user, $pageName = null) |
|
197 | - { |
|
198 | - $page = get_called_class(); |
|
199 | - if ($pageName !== null) { |
|
200 | - $page = $pageName; |
|
201 | - } |
|
202 | - |
|
203 | - $securityResult = $this->getSecurityManager()->allows($page, $action, $user); |
|
204 | - |
|
205 | - return $securityResult === SecurityManager::ALLOWED; |
|
206 | - } |
|
207 | - |
|
208 | - /** |
|
209 | - * Updates the lastactive timestamp |
|
210 | - */ |
|
211 | - private function touchUserLastActive() |
|
212 | - { |
|
213 | - if (WebRequest::getSessionUserId() !== null) { |
|
214 | - $query = 'UPDATE user SET lastactive = CURRENT_TIMESTAMP() WHERE id = :id;'; |
|
215 | - $this->getDatabase()->prepare($query)->execute(array(":id" => WebRequest::getSessionUserId())); |
|
216 | - } |
|
217 | - } |
|
218 | - |
|
219 | - /** |
|
220 | - * @return SecurityManager |
|
221 | - */ |
|
222 | - public function getSecurityManager() |
|
223 | - { |
|
224 | - return $this->securityManager; |
|
225 | - } |
|
226 | - |
|
227 | - /** |
|
228 | - * @param SecurityManager $securityManager |
|
229 | - */ |
|
230 | - public function setSecurityManager(SecurityManager $securityManager) |
|
231 | - { |
|
232 | - $this->securityManager = $securityManager; |
|
233 | - } |
|
234 | - |
|
235 | - /** |
|
236 | - * @return IBlacklistHelper |
|
237 | - */ |
|
238 | - public function getBlacklistHelper() |
|
239 | - { |
|
240 | - return $this->blacklistHelper; |
|
241 | - } |
|
242 | - |
|
243 | - /** |
|
244 | - * @param IBlacklistHelper $blacklistHelper |
|
245 | - */ |
|
246 | - public function setBlacklistHelper(IBlacklistHelper $blacklistHelper) |
|
247 | - { |
|
248 | - $this->blacklistHelper = $blacklistHelper; |
|
249 | - } |
|
26 | + use NavigationMenuAccessControl; |
|
27 | + |
|
28 | + /** @var IdentificationVerifier */ |
|
29 | + private $identificationVerifier; |
|
30 | + /** @var ITypeAheadHelper */ |
|
31 | + private $typeAheadHelper; |
|
32 | + /** @var SecurityManager */ |
|
33 | + private $securityManager; |
|
34 | + /** @var IBlacklistHelper */ |
|
35 | + private $blacklistHelper; |
|
36 | + |
|
37 | + /** |
|
38 | + * @return ITypeAheadHelper |
|
39 | + */ |
|
40 | + public function getTypeAheadHelper() |
|
41 | + { |
|
42 | + return $this->typeAheadHelper; |
|
43 | + } |
|
44 | + |
|
45 | + /** |
|
46 | + * Sets up the internal IdentificationVerifier instance. Intended to be called from WebStart::setupHelpers(). |
|
47 | + * |
|
48 | + * @param IdentificationVerifier $identificationVerifier |
|
49 | + * |
|
50 | + * @return void |
|
51 | + */ |
|
52 | + public function setIdentificationVerifier(IdentificationVerifier $identificationVerifier) |
|
53 | + { |
|
54 | + $this->identificationVerifier = $identificationVerifier; |
|
55 | + } |
|
56 | + |
|
57 | + /** |
|
58 | + * @param ITypeAheadHelper $typeAheadHelper |
|
59 | + */ |
|
60 | + public function setTypeAheadHelper(ITypeAheadHelper $typeAheadHelper) |
|
61 | + { |
|
62 | + $this->typeAheadHelper = $typeAheadHelper; |
|
63 | + } |
|
64 | + |
|
65 | + /** |
|
66 | + * Runs the page code |
|
67 | + * |
|
68 | + * @throws Exception |
|
69 | + * @category Security-Critical |
|
70 | + */ |
|
71 | + final public function execute() |
|
72 | + { |
|
73 | + if ($this->getRouteName() === null) { |
|
74 | + throw new Exception("Request is unrouted."); |
|
75 | + } |
|
76 | + |
|
77 | + if ($this->getSiteConfiguration() === null) { |
|
78 | + throw new Exception("Page has no configuration!"); |
|
79 | + } |
|
80 | + |
|
81 | + $this->setupPage(); |
|
82 | + |
|
83 | + $this->touchUserLastActive(); |
|
84 | + |
|
85 | + $currentUser = User::getCurrent($this->getDatabase()); |
|
86 | + |
|
87 | + // Hey, this is also a security barrier, in addition to the below. Separated out for readability. |
|
88 | + if (!$this->isProtectedPage()) { |
|
89 | + // This page is /not/ a protected page, as such we can just run it. |
|
90 | + $this->runPage(); |
|
91 | + |
|
92 | + return; |
|
93 | + } |
|
94 | + |
|
95 | + // Security barrier. |
|
96 | + // |
|
97 | + // This code essentially doesn't care if the user is logged in or not, as the security manager hides all that |
|
98 | + // away for us |
|
99 | + $securityResult = $this->getSecurityManager()->allows(get_called_class(), $this->getRouteName(), $currentUser); |
|
100 | + if ($securityResult === SecurityManager::ALLOWED) { |
|
101 | + // We're allowed to run the page, so let's run it. |
|
102 | + $this->runPage(); |
|
103 | + } |
|
104 | + else { |
|
105 | + $this->handleAccessDenied($securityResult); |
|
106 | + |
|
107 | + // Send the headers |
|
108 | + $this->sendResponseHeaders(); |
|
109 | + } |
|
110 | + } |
|
111 | + |
|
112 | + /** |
|
113 | + * Performs final tasks needed before rendering the page. |
|
114 | + */ |
|
115 | + final public function finalisePage() |
|
116 | + { |
|
117 | + parent::finalisePage(); |
|
118 | + |
|
119 | + $database = $this->getDatabase(); |
|
120 | + $currentUser = User::getCurrent($database); |
|
121 | + |
|
122 | + if ($this->barrierTest('viewSiteNotice', User::getCurrent($database), 'GlobalInfo')) { |
|
123 | + $siteNoticeText = SiteNotice::get($this->getDatabase()); |
|
124 | + $this->assign('siteNoticeText', $siteNoticeText); |
|
125 | + } |
|
126 | + |
|
127 | + if ($this->barrierTest('viewOnlineUsers', User::getCurrent($database), 'GlobalInfo')) { |
|
128 | + $sql = 'SELECT * FROM user WHERE lastactive > DATE_SUB(CURRENT_TIMESTAMP(), INTERVAL 5 MINUTE);'; |
|
129 | + $statement = $database->query($sql); |
|
130 | + $activeUsers = $statement->fetchAll(PDO::FETCH_CLASS, User::class); |
|
131 | + $this->assign('onlineusers', $activeUsers); |
|
132 | + } |
|
133 | + |
|
134 | + $this->setupNavMenuAccess($currentUser); |
|
135 | + } |
|
136 | + |
|
137 | + /** |
|
138 | + * Configures whether the page respects roles or not. You probably want this to return true. |
|
139 | + * |
|
140 | + * Set to false for public pages. You probably want this to return true. |
|
141 | + * |
|
142 | + * This defaults to true unless you explicitly set it to false. Setting it to false means anybody can do anything |
|
143 | + * on this page, so you probably want this to return true. |
|
144 | + * |
|
145 | + * @return bool |
|
146 | + * @category Security-Critical |
|
147 | + */ |
|
148 | + protected function isProtectedPage() |
|
149 | + { |
|
150 | + return true; |
|
151 | + } |
|
152 | + |
|
153 | + protected function handleAccessDenied($denyReason) |
|
154 | + { |
|
155 | + $currentUser = User::getCurrent($this->getDatabase()); |
|
156 | + |
|
157 | + // Not allowed to access this resource. |
|
158 | + // Firstly, let's check if we're even logged in. |
|
159 | + if ($currentUser->isCommunityUser()) { |
|
160 | + // Not logged in, redirect to login page |
|
161 | + WebRequest::setPostLoginRedirect(); |
|
162 | + $this->redirect("login"); |
|
163 | + |
|
164 | + return; |
|
165 | + } |
|
166 | + else { |
|
167 | + // Decide whether this was a rights failure, or an identification failure. |
|
168 | + |
|
169 | + if ($denyReason === SecurityManager::ERROR_NOT_IDENTIFIED) { |
|
170 | + // Not identified |
|
171 | + throw new NotIdentifiedException($this->getSecurityManager()); |
|
172 | + } |
|
173 | + elseif ($denyReason === SecurityManager::ERROR_DENIED) { |
|
174 | + // Nope, plain old access denied |
|
175 | + throw new AccessDeniedException($this->getSecurityManager()); |
|
176 | + } |
|
177 | + else { |
|
178 | + throw new Exception('Unknown response from security manager.'); |
|
179 | + } |
|
180 | + } |
|
181 | + } |
|
182 | + |
|
183 | + /** |
|
184 | + * Tests the security barrier for a specified action. |
|
185 | + * |
|
186 | + * Don't use within templates |
|
187 | + * |
|
188 | + * @param string $action |
|
189 | + * |
|
190 | + * @param User $user |
|
191 | + * @param null|string $pageName |
|
192 | + * |
|
193 | + * @return bool |
|
194 | + * @category Security-Critical |
|
195 | + */ |
|
196 | + final public function barrierTest($action, User $user, $pageName = null) |
|
197 | + { |
|
198 | + $page = get_called_class(); |
|
199 | + if ($pageName !== null) { |
|
200 | + $page = $pageName; |
|
201 | + } |
|
202 | + |
|
203 | + $securityResult = $this->getSecurityManager()->allows($page, $action, $user); |
|
204 | + |
|
205 | + return $securityResult === SecurityManager::ALLOWED; |
|
206 | + } |
|
207 | + |
|
208 | + /** |
|
209 | + * Updates the lastactive timestamp |
|
210 | + */ |
|
211 | + private function touchUserLastActive() |
|
212 | + { |
|
213 | + if (WebRequest::getSessionUserId() !== null) { |
|
214 | + $query = 'UPDATE user SET lastactive = CURRENT_TIMESTAMP() WHERE id = :id;'; |
|
215 | + $this->getDatabase()->prepare($query)->execute(array(":id" => WebRequest::getSessionUserId())); |
|
216 | + } |
|
217 | + } |
|
218 | + |
|
219 | + /** |
|
220 | + * @return SecurityManager |
|
221 | + */ |
|
222 | + public function getSecurityManager() |
|
223 | + { |
|
224 | + return $this->securityManager; |
|
225 | + } |
|
226 | + |
|
227 | + /** |
|
228 | + * @param SecurityManager $securityManager |
|
229 | + */ |
|
230 | + public function setSecurityManager(SecurityManager $securityManager) |
|
231 | + { |
|
232 | + $this->securityManager = $securityManager; |
|
233 | + } |
|
234 | + |
|
235 | + /** |
|
236 | + * @return IBlacklistHelper |
|
237 | + */ |
|
238 | + public function getBlacklistHelper() |
|
239 | + { |
|
240 | + return $this->blacklistHelper; |
|
241 | + } |
|
242 | + |
|
243 | + /** |
|
244 | + * @param IBlacklistHelper $blacklistHelper |
|
245 | + */ |
|
246 | + public function setBlacklistHelper(IBlacklistHelper $blacklistHelper) |
|
247 | + { |
|
248 | + $this->blacklistHelper = $blacklistHelper; |
|
249 | + } |
|
250 | 250 | } |
@@ -23,357 +23,357 @@ |
||
23 | 23 | |
24 | 24 | abstract class PageBase extends TaskBase implements IRoutedTask |
25 | 25 | { |
26 | - use TemplateOutput; |
|
27 | - /** @var string Smarty template to display */ |
|
28 | - protected $template = "base.tpl"; |
|
29 | - /** @var string HTML title. Currently unused. */ |
|
30 | - protected $htmlTitle; |
|
31 | - /** @var bool Determines if the page is a redirect or not */ |
|
32 | - protected $isRedirecting = false; |
|
33 | - /** @var array Queue of headers to be sent on successful completion */ |
|
34 | - protected $headerQueue = array(); |
|
35 | - /** @var string The name of the route to use, as determined by the request router. */ |
|
36 | - private $routeName = null; |
|
37 | - /** @var TokenManager */ |
|
38 | - protected $tokenManager; |
|
39 | - /** @var ContentSecurityPolicyManager */ |
|
40 | - private $cspManager; |
|
41 | - /** @var string[] Extra JS files to include */ |
|
42 | - private $extraJs = array(); |
|
43 | - |
|
44 | - /** |
|
45 | - * Sets the route the request will take. Only should be called from the request router or barrier test. |
|
46 | - * |
|
47 | - * @param string $routeName The name of the route |
|
48 | - * @param bool $skipCallableTest Don't use this unless you know what you're doing, and what the implications are. |
|
49 | - * |
|
50 | - * @throws Exception |
|
51 | - * @category Security-Critical |
|
52 | - */ |
|
53 | - final public function setRoute($routeName, $skipCallableTest = false) |
|
54 | - { |
|
55 | - // Test the new route is callable before adopting it. |
|
56 | - if (!$skipCallableTest && !is_callable(array($this, $routeName))) { |
|
57 | - throw new Exception("Proposed route '$routeName' is not callable."); |
|
58 | - } |
|
59 | - |
|
60 | - // Adopt the new route |
|
61 | - $this->routeName = $routeName; |
|
62 | - } |
|
63 | - |
|
64 | - /** |
|
65 | - * Gets the name of the route that has been passed from the request router. |
|
66 | - * @return string |
|
67 | - */ |
|
68 | - final public function getRouteName() |
|
69 | - { |
|
70 | - return $this->routeName; |
|
71 | - } |
|
72 | - |
|
73 | - /** |
|
74 | - * Performs generic page setup actions |
|
75 | - */ |
|
76 | - final protected function setupPage() |
|
77 | - { |
|
78 | - $this->setUpSmarty(); |
|
79 | - |
|
80 | - $currentUser = User::getCurrent($this->getDatabase()); |
|
81 | - $this->assign('currentUser', $currentUser); |
|
82 | - $this->assign('loggedIn', (!$currentUser->isCommunityUser())); |
|
83 | - } |
|
84 | - |
|
85 | - /** |
|
86 | - * Runs the page logic as routed by the RequestRouter |
|
87 | - * |
|
88 | - * Only should be called after a security barrier! That means only from execute(). |
|
89 | - */ |
|
90 | - final protected function runPage() |
|
91 | - { |
|
92 | - $database = $this->getDatabase(); |
|
93 | - |
|
94 | - // initialise a database transaction |
|
95 | - if (!$database->beginTransaction()) { |
|
96 | - throw new Exception('Failed to start transaction on primary database.'); |
|
97 | - } |
|
98 | - |
|
99 | - try { |
|
100 | - // run the page code |
|
101 | - $this->{$this->getRouteName()}(); |
|
102 | - |
|
103 | - $database->commit(); |
|
104 | - } |
|
105 | - catch (ApplicationLogicException $ex) { |
|
106 | - // it's an application logic exception, so nothing went seriously wrong with the site. We can use the |
|
107 | - // standard templating system for this. |
|
108 | - |
|
109 | - // Firstly, let's undo anything that happened to the database. |
|
110 | - $database->rollBack(); |
|
111 | - |
|
112 | - // Reset smarty |
|
113 | - $this->setupPage(); |
|
114 | - |
|
115 | - // Set the template |
|
116 | - $this->setTemplate('exception/application-logic.tpl'); |
|
117 | - $this->assign('message', $ex->getMessage()); |
|
118 | - |
|
119 | - // Force this back to false |
|
120 | - $this->isRedirecting = false; |
|
121 | - $this->headerQueue = array(); |
|
122 | - } |
|
123 | - catch (OptimisticLockFailedException $ex) { |
|
124 | - // it's an optimistic lock failure exception, so nothing went seriously wrong with the site. We can use the |
|
125 | - // standard templating system for this. |
|
126 | - |
|
127 | - // Firstly, let's undo anything that happened to the database. |
|
128 | - $database->rollBack(); |
|
129 | - |
|
130 | - // Reset smarty |
|
131 | - $this->setupPage(); |
|
132 | - |
|
133 | - // Set the template |
|
134 | - $this->setTemplate('exception/optimistic-lock-failure.tpl'); |
|
135 | - $this->assign('message', $ex->getMessage()); |
|
136 | - |
|
137 | - $this->assign('debugTrace', false); |
|
138 | - |
|
139 | - if ($this->getSiteConfiguration()->getDebuggingTraceEnabled()) { |
|
140 | - ob_start(); |
|
141 | - var_dump(ExceptionHandler::getExceptionData($ex)); |
|
142 | - $textErrorData = ob_get_contents(); |
|
143 | - ob_end_clean(); |
|
144 | - |
|
145 | - $this->assign('exceptionData', $textErrorData); |
|
146 | - $this->assign('debugTrace', true); |
|
147 | - } |
|
148 | - |
|
149 | - // Force this back to false |
|
150 | - $this->isRedirecting = false; |
|
151 | - $this->headerQueue = array(); |
|
152 | - } |
|
153 | - finally { |
|
154 | - // Catch any hanging on transactions |
|
155 | - if ($database->hasActiveTransaction()) { |
|
156 | - $database->rollBack(); |
|
157 | - } |
|
158 | - } |
|
159 | - |
|
160 | - // run any finalisation code needed before we send the output to the browser. |
|
161 | - $this->finalisePage(); |
|
162 | - |
|
163 | - // Send the headers |
|
164 | - $this->sendResponseHeaders(); |
|
165 | - |
|
166 | - // Check we have a template to use! |
|
167 | - if ($this->template !== null) { |
|
168 | - $content = $this->fetchTemplate($this->template); |
|
169 | - ob_clean(); |
|
170 | - print($content); |
|
171 | - ob_flush(); |
|
172 | - |
|
173 | - return; |
|
174 | - } |
|
175 | - } |
|
176 | - |
|
177 | - /** |
|
178 | - * Performs final tasks needed before rendering the page. |
|
179 | - */ |
|
180 | - protected function finalisePage() |
|
181 | - { |
|
182 | - if ($this->isRedirecting) { |
|
183 | - $this->template = null; |
|
184 | - |
|
185 | - return; |
|
186 | - } |
|
187 | - |
|
188 | - $this->assign('extraJs', $this->extraJs); |
|
189 | - |
|
190 | - // If we're actually displaying content, we want to add the session alerts here! |
|
191 | - $this->assign('alerts', SessionAlert::getAlerts()); |
|
192 | - SessionAlert::clearAlerts(); |
|
193 | - |
|
194 | - $this->assign('htmlTitle', $this->htmlTitle); |
|
195 | - } |
|
196 | - |
|
197 | - /** |
|
198 | - * @return TokenManager |
|
199 | - */ |
|
200 | - public function getTokenManager() |
|
201 | - { |
|
202 | - return $this->tokenManager; |
|
203 | - } |
|
204 | - |
|
205 | - /** |
|
206 | - * @param TokenManager $tokenManager |
|
207 | - */ |
|
208 | - public function setTokenManager($tokenManager) |
|
209 | - { |
|
210 | - $this->tokenManager = $tokenManager; |
|
211 | - } |
|
212 | - |
|
213 | - /** |
|
214 | - * @return ContentSecurityPolicyManager |
|
215 | - */ |
|
216 | - public function getCspManager(): ContentSecurityPolicyManager |
|
217 | - { |
|
218 | - return $this->cspManager; |
|
219 | - } |
|
220 | - |
|
221 | - /** |
|
222 | - * @param ContentSecurityPolicyManager $cspManager |
|
223 | - */ |
|
224 | - public function setCspManager(ContentSecurityPolicyManager $cspManager): void |
|
225 | - { |
|
226 | - $this->cspManager = $cspManager; |
|
227 | - } |
|
228 | - |
|
229 | - /** |
|
230 | - * Sends the redirect headers to perform a GET at the destination page. |
|
231 | - * |
|
232 | - * Also nullifies the set template so Smarty does not render it. |
|
233 | - * |
|
234 | - * @param string $page The page to redirect requests to (as used in the UR) |
|
235 | - * @param null|string $action The action to use on the page. |
|
236 | - * @param null|array $parameters |
|
237 | - * @param null|string $script The script (relative to index.php) to redirect to |
|
238 | - */ |
|
239 | - final protected function redirect($page = '', $action = null, $parameters = null, $script = null) |
|
240 | - { |
|
241 | - $currentScriptName = WebRequest::scriptName(); |
|
242 | - |
|
243 | - // Are we changing script? |
|
244 | - if ($script === null || substr($currentScriptName, -1 * count($script)) === $script) { |
|
245 | - $targetScriptName = $currentScriptName; |
|
246 | - } |
|
247 | - else { |
|
248 | - $targetScriptName = $this->getSiteConfiguration()->getBaseUrl() . '/' . $script; |
|
249 | - } |
|
250 | - |
|
251 | - $pathInfo = array($targetScriptName); |
|
252 | - |
|
253 | - $pathInfo[1] = $page; |
|
254 | - |
|
255 | - if ($action !== null) { |
|
256 | - $pathInfo[2] = $action; |
|
257 | - } |
|
258 | - |
|
259 | - $url = implode('/', $pathInfo); |
|
260 | - |
|
261 | - if (is_array($parameters) && count($parameters) > 0) { |
|
262 | - $url .= '?' . http_build_query($parameters); |
|
263 | - } |
|
264 | - |
|
265 | - $this->redirectUrl($url); |
|
266 | - } |
|
267 | - |
|
268 | - /** |
|
269 | - * Sends the redirect headers to perform a GET at the new address. |
|
270 | - * |
|
271 | - * Also nullifies the set template so Smarty does not render it. |
|
272 | - * |
|
273 | - * @param string $path URL to redirect to |
|
274 | - */ |
|
275 | - final protected function redirectUrl($path) |
|
276 | - { |
|
277 | - // 303 See Other = re-request at new address with a GET. |
|
278 | - $this->headerQueue[] = 'HTTP/1.1 303 See Other'; |
|
279 | - $this->headerQueue[] = "Location: $path"; |
|
280 | - |
|
281 | - $this->setTemplate(null); |
|
282 | - $this->isRedirecting = true; |
|
283 | - } |
|
284 | - |
|
285 | - /** |
|
286 | - * Sets the name of the template this page should display. |
|
287 | - * |
|
288 | - * @param string $name |
|
289 | - * |
|
290 | - * @throws Exception |
|
291 | - */ |
|
292 | - final protected function setTemplate($name) |
|
293 | - { |
|
294 | - if ($this->isRedirecting) { |
|
295 | - throw new Exception('This page has been set as a redirect, no template can be displayed!'); |
|
296 | - } |
|
297 | - |
|
298 | - $this->template = $name; |
|
299 | - } |
|
300 | - |
|
301 | - /** |
|
302 | - * Adds an extra JS file to to the page |
|
303 | - * |
|
304 | - * @param string $path The path (relative to the application root) of the file |
|
305 | - */ |
|
306 | - final protected function addJs($path){ |
|
307 | - if(in_array($path, $this->extraJs)){ |
|
308 | - // nothing to do |
|
309 | - return; |
|
310 | - } |
|
311 | - |
|
312 | - $this->extraJs[] = $path; |
|
313 | - } |
|
314 | - |
|
315 | - /** |
|
316 | - * Main function for this page, when no specific actions are called. |
|
317 | - * @return void |
|
318 | - */ |
|
319 | - abstract protected function main(); |
|
320 | - |
|
321 | - /** |
|
322 | - * Takes a smarty template string and sets the HTML title to that value |
|
323 | - * |
|
324 | - * @param string $title |
|
325 | - * |
|
326 | - * @throws SmartyException |
|
327 | - */ |
|
328 | - final protected function setHtmlTitle($title) |
|
329 | - { |
|
330 | - $this->htmlTitle = $this->smarty->fetch('string:' . $title); |
|
331 | - } |
|
332 | - |
|
333 | - public function execute() |
|
334 | - { |
|
335 | - if ($this->getRouteName() === null) { |
|
336 | - throw new Exception('Request is unrouted.'); |
|
337 | - } |
|
338 | - |
|
339 | - if ($this->getSiteConfiguration() === null) { |
|
340 | - throw new Exception('Page has no configuration!'); |
|
341 | - } |
|
342 | - |
|
343 | - $this->setupPage(); |
|
344 | - |
|
345 | - $this->runPage(); |
|
346 | - } |
|
347 | - |
|
348 | - public function assignCSRFToken() |
|
349 | - { |
|
350 | - $token = $this->tokenManager->getNewToken(); |
|
351 | - $this->assign('csrfTokenData', $token->getTokenData()); |
|
352 | - } |
|
353 | - |
|
354 | - public function validateCSRFToken() |
|
355 | - { |
|
356 | - if (!$this->tokenManager->validateToken(WebRequest::postString('csrfTokenData'))) { |
|
357 | - throw new ApplicationLogicException('Form token is not valid, please reload and try again'); |
|
358 | - } |
|
359 | - } |
|
360 | - |
|
361 | - protected function sendResponseHeaders() |
|
362 | - { |
|
363 | - if (headers_sent()) { |
|
364 | - throw new ApplicationLogicException('Headers have already been sent! This is likely a bug in the application.'); |
|
365 | - } |
|
366 | - |
|
367 | - // send the CSP headers now |
|
368 | - header($this->getCspManager()->getHeader()); |
|
369 | - |
|
370 | - foreach ($this->headerQueue as $item) { |
|
371 | - if (mb_strpos($item, "\r") !== false || mb_strpos($item, "\n") !== false) { |
|
372 | - // Oops. We're not allowed to do this. |
|
373 | - throw new Exception('Unable to split header'); |
|
374 | - } |
|
375 | - |
|
376 | - header($item); |
|
377 | - } |
|
378 | - } |
|
26 | + use TemplateOutput; |
|
27 | + /** @var string Smarty template to display */ |
|
28 | + protected $template = "base.tpl"; |
|
29 | + /** @var string HTML title. Currently unused. */ |
|
30 | + protected $htmlTitle; |
|
31 | + /** @var bool Determines if the page is a redirect or not */ |
|
32 | + protected $isRedirecting = false; |
|
33 | + /** @var array Queue of headers to be sent on successful completion */ |
|
34 | + protected $headerQueue = array(); |
|
35 | + /** @var string The name of the route to use, as determined by the request router. */ |
|
36 | + private $routeName = null; |
|
37 | + /** @var TokenManager */ |
|
38 | + protected $tokenManager; |
|
39 | + /** @var ContentSecurityPolicyManager */ |
|
40 | + private $cspManager; |
|
41 | + /** @var string[] Extra JS files to include */ |
|
42 | + private $extraJs = array(); |
|
43 | + |
|
44 | + /** |
|
45 | + * Sets the route the request will take. Only should be called from the request router or barrier test. |
|
46 | + * |
|
47 | + * @param string $routeName The name of the route |
|
48 | + * @param bool $skipCallableTest Don't use this unless you know what you're doing, and what the implications are. |
|
49 | + * |
|
50 | + * @throws Exception |
|
51 | + * @category Security-Critical |
|
52 | + */ |
|
53 | + final public function setRoute($routeName, $skipCallableTest = false) |
|
54 | + { |
|
55 | + // Test the new route is callable before adopting it. |
|
56 | + if (!$skipCallableTest && !is_callable(array($this, $routeName))) { |
|
57 | + throw new Exception("Proposed route '$routeName' is not callable."); |
|
58 | + } |
|
59 | + |
|
60 | + // Adopt the new route |
|
61 | + $this->routeName = $routeName; |
|
62 | + } |
|
63 | + |
|
64 | + /** |
|
65 | + * Gets the name of the route that has been passed from the request router. |
|
66 | + * @return string |
|
67 | + */ |
|
68 | + final public function getRouteName() |
|
69 | + { |
|
70 | + return $this->routeName; |
|
71 | + } |
|
72 | + |
|
73 | + /** |
|
74 | + * Performs generic page setup actions |
|
75 | + */ |
|
76 | + final protected function setupPage() |
|
77 | + { |
|
78 | + $this->setUpSmarty(); |
|
79 | + |
|
80 | + $currentUser = User::getCurrent($this->getDatabase()); |
|
81 | + $this->assign('currentUser', $currentUser); |
|
82 | + $this->assign('loggedIn', (!$currentUser->isCommunityUser())); |
|
83 | + } |
|
84 | + |
|
85 | + /** |
|
86 | + * Runs the page logic as routed by the RequestRouter |
|
87 | + * |
|
88 | + * Only should be called after a security barrier! That means only from execute(). |
|
89 | + */ |
|
90 | + final protected function runPage() |
|
91 | + { |
|
92 | + $database = $this->getDatabase(); |
|
93 | + |
|
94 | + // initialise a database transaction |
|
95 | + if (!$database->beginTransaction()) { |
|
96 | + throw new Exception('Failed to start transaction on primary database.'); |
|
97 | + } |
|
98 | + |
|
99 | + try { |
|
100 | + // run the page code |
|
101 | + $this->{$this->getRouteName()}(); |
|
102 | + |
|
103 | + $database->commit(); |
|
104 | + } |
|
105 | + catch (ApplicationLogicException $ex) { |
|
106 | + // it's an application logic exception, so nothing went seriously wrong with the site. We can use the |
|
107 | + // standard templating system for this. |
|
108 | + |
|
109 | + // Firstly, let's undo anything that happened to the database. |
|
110 | + $database->rollBack(); |
|
111 | + |
|
112 | + // Reset smarty |
|
113 | + $this->setupPage(); |
|
114 | + |
|
115 | + // Set the template |
|
116 | + $this->setTemplate('exception/application-logic.tpl'); |
|
117 | + $this->assign('message', $ex->getMessage()); |
|
118 | + |
|
119 | + // Force this back to false |
|
120 | + $this->isRedirecting = false; |
|
121 | + $this->headerQueue = array(); |
|
122 | + } |
|
123 | + catch (OptimisticLockFailedException $ex) { |
|
124 | + // it's an optimistic lock failure exception, so nothing went seriously wrong with the site. We can use the |
|
125 | + // standard templating system for this. |
|
126 | + |
|
127 | + // Firstly, let's undo anything that happened to the database. |
|
128 | + $database->rollBack(); |
|
129 | + |
|
130 | + // Reset smarty |
|
131 | + $this->setupPage(); |
|
132 | + |
|
133 | + // Set the template |
|
134 | + $this->setTemplate('exception/optimistic-lock-failure.tpl'); |
|
135 | + $this->assign('message', $ex->getMessage()); |
|
136 | + |
|
137 | + $this->assign('debugTrace', false); |
|
138 | + |
|
139 | + if ($this->getSiteConfiguration()->getDebuggingTraceEnabled()) { |
|
140 | + ob_start(); |
|
141 | + var_dump(ExceptionHandler::getExceptionData($ex)); |
|
142 | + $textErrorData = ob_get_contents(); |
|
143 | + ob_end_clean(); |
|
144 | + |
|
145 | + $this->assign('exceptionData', $textErrorData); |
|
146 | + $this->assign('debugTrace', true); |
|
147 | + } |
|
148 | + |
|
149 | + // Force this back to false |
|
150 | + $this->isRedirecting = false; |
|
151 | + $this->headerQueue = array(); |
|
152 | + } |
|
153 | + finally { |
|
154 | + // Catch any hanging on transactions |
|
155 | + if ($database->hasActiveTransaction()) { |
|
156 | + $database->rollBack(); |
|
157 | + } |
|
158 | + } |
|
159 | + |
|
160 | + // run any finalisation code needed before we send the output to the browser. |
|
161 | + $this->finalisePage(); |
|
162 | + |
|
163 | + // Send the headers |
|
164 | + $this->sendResponseHeaders(); |
|
165 | + |
|
166 | + // Check we have a template to use! |
|
167 | + if ($this->template !== null) { |
|
168 | + $content = $this->fetchTemplate($this->template); |
|
169 | + ob_clean(); |
|
170 | + print($content); |
|
171 | + ob_flush(); |
|
172 | + |
|
173 | + return; |
|
174 | + } |
|
175 | + } |
|
176 | + |
|
177 | + /** |
|
178 | + * Performs final tasks needed before rendering the page. |
|
179 | + */ |
|
180 | + protected function finalisePage() |
|
181 | + { |
|
182 | + if ($this->isRedirecting) { |
|
183 | + $this->template = null; |
|
184 | + |
|
185 | + return; |
|
186 | + } |
|
187 | + |
|
188 | + $this->assign('extraJs', $this->extraJs); |
|
189 | + |
|
190 | + // If we're actually displaying content, we want to add the session alerts here! |
|
191 | + $this->assign('alerts', SessionAlert::getAlerts()); |
|
192 | + SessionAlert::clearAlerts(); |
|
193 | + |
|
194 | + $this->assign('htmlTitle', $this->htmlTitle); |
|
195 | + } |
|
196 | + |
|
197 | + /** |
|
198 | + * @return TokenManager |
|
199 | + */ |
|
200 | + public function getTokenManager() |
|
201 | + { |
|
202 | + return $this->tokenManager; |
|
203 | + } |
|
204 | + |
|
205 | + /** |
|
206 | + * @param TokenManager $tokenManager |
|
207 | + */ |
|
208 | + public function setTokenManager($tokenManager) |
|
209 | + { |
|
210 | + $this->tokenManager = $tokenManager; |
|
211 | + } |
|
212 | + |
|
213 | + /** |
|
214 | + * @return ContentSecurityPolicyManager |
|
215 | + */ |
|
216 | + public function getCspManager(): ContentSecurityPolicyManager |
|
217 | + { |
|
218 | + return $this->cspManager; |
|
219 | + } |
|
220 | + |
|
221 | + /** |
|
222 | + * @param ContentSecurityPolicyManager $cspManager |
|
223 | + */ |
|
224 | + public function setCspManager(ContentSecurityPolicyManager $cspManager): void |
|
225 | + { |
|
226 | + $this->cspManager = $cspManager; |
|
227 | + } |
|
228 | + |
|
229 | + /** |
|
230 | + * Sends the redirect headers to perform a GET at the destination page. |
|
231 | + * |
|
232 | + * Also nullifies the set template so Smarty does not render it. |
|
233 | + * |
|
234 | + * @param string $page The page to redirect requests to (as used in the UR) |
|
235 | + * @param null|string $action The action to use on the page. |
|
236 | + * @param null|array $parameters |
|
237 | + * @param null|string $script The script (relative to index.php) to redirect to |
|
238 | + */ |
|
239 | + final protected function redirect($page = '', $action = null, $parameters = null, $script = null) |
|
240 | + { |
|
241 | + $currentScriptName = WebRequest::scriptName(); |
|
242 | + |
|
243 | + // Are we changing script? |
|
244 | + if ($script === null || substr($currentScriptName, -1 * count($script)) === $script) { |
|
245 | + $targetScriptName = $currentScriptName; |
|
246 | + } |
|
247 | + else { |
|
248 | + $targetScriptName = $this->getSiteConfiguration()->getBaseUrl() . '/' . $script; |
|
249 | + } |
|
250 | + |
|
251 | + $pathInfo = array($targetScriptName); |
|
252 | + |
|
253 | + $pathInfo[1] = $page; |
|
254 | + |
|
255 | + if ($action !== null) { |
|
256 | + $pathInfo[2] = $action; |
|
257 | + } |
|
258 | + |
|
259 | + $url = implode('/', $pathInfo); |
|
260 | + |
|
261 | + if (is_array($parameters) && count($parameters) > 0) { |
|
262 | + $url .= '?' . http_build_query($parameters); |
|
263 | + } |
|
264 | + |
|
265 | + $this->redirectUrl($url); |
|
266 | + } |
|
267 | + |
|
268 | + /** |
|
269 | + * Sends the redirect headers to perform a GET at the new address. |
|
270 | + * |
|
271 | + * Also nullifies the set template so Smarty does not render it. |
|
272 | + * |
|
273 | + * @param string $path URL to redirect to |
|
274 | + */ |
|
275 | + final protected function redirectUrl($path) |
|
276 | + { |
|
277 | + // 303 See Other = re-request at new address with a GET. |
|
278 | + $this->headerQueue[] = 'HTTP/1.1 303 See Other'; |
|
279 | + $this->headerQueue[] = "Location: $path"; |
|
280 | + |
|
281 | + $this->setTemplate(null); |
|
282 | + $this->isRedirecting = true; |
|
283 | + } |
|
284 | + |
|
285 | + /** |
|
286 | + * Sets the name of the template this page should display. |
|
287 | + * |
|
288 | + * @param string $name |
|
289 | + * |
|
290 | + * @throws Exception |
|
291 | + */ |
|
292 | + final protected function setTemplate($name) |
|
293 | + { |
|
294 | + if ($this->isRedirecting) { |
|
295 | + throw new Exception('This page has been set as a redirect, no template can be displayed!'); |
|
296 | + } |
|
297 | + |
|
298 | + $this->template = $name; |
|
299 | + } |
|
300 | + |
|
301 | + /** |
|
302 | + * Adds an extra JS file to to the page |
|
303 | + * |
|
304 | + * @param string $path The path (relative to the application root) of the file |
|
305 | + */ |
|
306 | + final protected function addJs($path){ |
|
307 | + if(in_array($path, $this->extraJs)){ |
|
308 | + // nothing to do |
|
309 | + return; |
|
310 | + } |
|
311 | + |
|
312 | + $this->extraJs[] = $path; |
|
313 | + } |
|
314 | + |
|
315 | + /** |
|
316 | + * Main function for this page, when no specific actions are called. |
|
317 | + * @return void |
|
318 | + */ |
|
319 | + abstract protected function main(); |
|
320 | + |
|
321 | + /** |
|
322 | + * Takes a smarty template string and sets the HTML title to that value |
|
323 | + * |
|
324 | + * @param string $title |
|
325 | + * |
|
326 | + * @throws SmartyException |
|
327 | + */ |
|
328 | + final protected function setHtmlTitle($title) |
|
329 | + { |
|
330 | + $this->htmlTitle = $this->smarty->fetch('string:' . $title); |
|
331 | + } |
|
332 | + |
|
333 | + public function execute() |
|
334 | + { |
|
335 | + if ($this->getRouteName() === null) { |
|
336 | + throw new Exception('Request is unrouted.'); |
|
337 | + } |
|
338 | + |
|
339 | + if ($this->getSiteConfiguration() === null) { |
|
340 | + throw new Exception('Page has no configuration!'); |
|
341 | + } |
|
342 | + |
|
343 | + $this->setupPage(); |
|
344 | + |
|
345 | + $this->runPage(); |
|
346 | + } |
|
347 | + |
|
348 | + public function assignCSRFToken() |
|
349 | + { |
|
350 | + $token = $this->tokenManager->getNewToken(); |
|
351 | + $this->assign('csrfTokenData', $token->getTokenData()); |
|
352 | + } |
|
353 | + |
|
354 | + public function validateCSRFToken() |
|
355 | + { |
|
356 | + if (!$this->tokenManager->validateToken(WebRequest::postString('csrfTokenData'))) { |
|
357 | + throw new ApplicationLogicException('Form token is not valid, please reload and try again'); |
|
358 | + } |
|
359 | + } |
|
360 | + |
|
361 | + protected function sendResponseHeaders() |
|
362 | + { |
|
363 | + if (headers_sent()) { |
|
364 | + throw new ApplicationLogicException('Headers have already been sent! This is likely a bug in the application.'); |
|
365 | + } |
|
366 | + |
|
367 | + // send the CSP headers now |
|
368 | + header($this->getCspManager()->getHeader()); |
|
369 | + |
|
370 | + foreach ($this->headerQueue as $item) { |
|
371 | + if (mb_strpos($item, "\r") !== false || mb_strpos($item, "\n") !== false) { |
|
372 | + // Oops. We're not allowed to do this. |
|
373 | + throw new Exception('Unable to split header'); |
|
374 | + } |
|
375 | + |
|
376 | + header($item); |
|
377 | + } |
|
378 | + } |
|
379 | 379 | } |
@@ -22,116 +22,116 @@ |
||
22 | 22 | |
23 | 23 | class RunJobQueueTask extends ConsoleTaskBase |
24 | 24 | { |
25 | - private $taskList = array( |
|
26 | - WelcomeUserTask::class, |
|
27 | - BotCreationTask::class, |
|
28 | - UserCreationTask::class |
|
29 | - ); |
|
30 | - |
|
31 | - public function execute() |
|
32 | - { |
|
33 | - $database = $this->getDatabase(); |
|
34 | - |
|
35 | - // ensure we're running inside a tx here. |
|
36 | - if (!$database->hasActiveTransaction()) { |
|
37 | - $database->beginTransaction(); |
|
38 | - } |
|
39 | - |
|
40 | - $sql = 'SELECT * FROM jobqueue WHERE status = :status ORDER BY enqueue LIMIT :lim'; |
|
41 | - $statement = $database->prepare($sql); |
|
42 | - $statement->execute(array(':status' => JobQueue::STATUS_READY, ':lim' => 10)); |
|
43 | - /** @var JobQueue[] $queuedJobs */ |
|
44 | - $queuedJobs = $statement->fetchAll(PDO::FETCH_CLASS, JobQueue::class); |
|
45 | - |
|
46 | - // mark all the jobs as running, and commit the txn so we're not holding onto long-running transactions. |
|
47 | - // We'll re-lock the row when we get to it. |
|
48 | - foreach ($queuedJobs as $job) { |
|
49 | - $job->setDatabase($database); |
|
50 | - $job->setStatus(JobQueue::STATUS_WAITING); |
|
51 | - $job->setError(null); |
|
52 | - $job->setAcknowledged(null); |
|
53 | - $job->save(); |
|
54 | - } |
|
55 | - |
|
56 | - $database->commit(); |
|
57 | - |
|
58 | - set_error_handler(array(RunJobQueueTask::class, 'errorHandler'), E_ALL); |
|
59 | - |
|
60 | - foreach ($queuedJobs as $job) { |
|
61 | - try { |
|
62 | - $database->beginTransaction(); |
|
63 | - $job->setStatus(JobQueue::STATUS_RUNNING); |
|
64 | - $job->save(); |
|
65 | - $database->commit(); |
|
66 | - |
|
67 | - $database->beginTransaction(); |
|
68 | - |
|
69 | - // re-lock the job |
|
70 | - $job->setStatus(JobQueue::STATUS_RUNNING); |
|
71 | - $job->save(); |
|
72 | - |
|
73 | - // validate we're allowed to run the requested task (whitelist) |
|
74 | - if (!in_array($job->getTask(), $this->taskList)) { |
|
75 | - throw new ApplicationLogicException('Job task not registered'); |
|
76 | - } |
|
77 | - |
|
78 | - // Create a task. |
|
79 | - $taskName = $job->getTask(); |
|
80 | - |
|
81 | - if(!class_exists($taskName)) { |
|
82 | - throw new ApplicationLogicException('Job task does not exist'); |
|
83 | - } |
|
84 | - |
|
85 | - /** @var BackgroundTaskBase $task */ |
|
86 | - $task = new $taskName; |
|
87 | - |
|
88 | - $this->setupTask($task, $job); |
|
89 | - $task->run(); |
|
90 | - } |
|
91 | - catch (Exception $ex) { |
|
92 | - $database->rollBack(); |
|
93 | - $database->beginTransaction(); |
|
94 | - |
|
95 | - /** @var JobQueue $job */ |
|
96 | - $job = JobQueue::getById($job->getId(), $database); |
|
97 | - $job->setDatabase($database); |
|
98 | - $job->setStatus(JobQueue::STATUS_FAILED); |
|
99 | - $job->setError($ex->getMessage()); |
|
100 | - $job->setAcknowledged(0); |
|
101 | - $job->save(); |
|
102 | - |
|
103 | - /** @var Request $request */ |
|
104 | - $request = Request::getById($job->getRequest(), $database); |
|
105 | - if ($request === false) { |
|
106 | - $request = null; |
|
107 | - } |
|
108 | - |
|
109 | - Logger::backgroundJobIssue($this->getDatabase(), $job); |
|
110 | - |
|
111 | - $database->commit(); |
|
112 | - } |
|
113 | - finally { |
|
114 | - $database->commit(); |
|
115 | - } |
|
116 | - } |
|
117 | - } |
|
118 | - |
|
119 | - /** |
|
120 | - * @param BackgroundTaskBase $task |
|
121 | - * @param JobQueue $job |
|
122 | - */ |
|
123 | - private function setupTask(BackgroundTaskBase $task, JobQueue $job) |
|
124 | - { |
|
125 | - $task->setJob($job); |
|
126 | - $task->setDatabase($this->getDatabase()); |
|
127 | - $task->setHttpHelper($this->getHttpHelper()); |
|
128 | - $task->setOauthProtocolHelper($this->getOAuthProtocolHelper()); |
|
129 | - $task->setEmailHelper($this->getEmailHelper()); |
|
130 | - $task->setSiteConfiguration($this->getSiteConfiguration()); |
|
131 | - $task->setNotificationHelper($this->getNotificationHelper()); |
|
132 | - } |
|
133 | - |
|
134 | - public static function errorHandler($errno, $errstr, $errfile, $errline) { |
|
135 | - throw new Exception($errfile . "@" . $errline . ": " . $errstr); |
|
136 | - } |
|
25 | + private $taskList = array( |
|
26 | + WelcomeUserTask::class, |
|
27 | + BotCreationTask::class, |
|
28 | + UserCreationTask::class |
|
29 | + ); |
|
30 | + |
|
31 | + public function execute() |
|
32 | + { |
|
33 | + $database = $this->getDatabase(); |
|
34 | + |
|
35 | + // ensure we're running inside a tx here. |
|
36 | + if (!$database->hasActiveTransaction()) { |
|
37 | + $database->beginTransaction(); |
|
38 | + } |
|
39 | + |
|
40 | + $sql = 'SELECT * FROM jobqueue WHERE status = :status ORDER BY enqueue LIMIT :lim'; |
|
41 | + $statement = $database->prepare($sql); |
|
42 | + $statement->execute(array(':status' => JobQueue::STATUS_READY, ':lim' => 10)); |
|
43 | + /** @var JobQueue[] $queuedJobs */ |
|
44 | + $queuedJobs = $statement->fetchAll(PDO::FETCH_CLASS, JobQueue::class); |
|
45 | + |
|
46 | + // mark all the jobs as running, and commit the txn so we're not holding onto long-running transactions. |
|
47 | + // We'll re-lock the row when we get to it. |
|
48 | + foreach ($queuedJobs as $job) { |
|
49 | + $job->setDatabase($database); |
|
50 | + $job->setStatus(JobQueue::STATUS_WAITING); |
|
51 | + $job->setError(null); |
|
52 | + $job->setAcknowledged(null); |
|
53 | + $job->save(); |
|
54 | + } |
|
55 | + |
|
56 | + $database->commit(); |
|
57 | + |
|
58 | + set_error_handler(array(RunJobQueueTask::class, 'errorHandler'), E_ALL); |
|
59 | + |
|
60 | + foreach ($queuedJobs as $job) { |
|
61 | + try { |
|
62 | + $database->beginTransaction(); |
|
63 | + $job->setStatus(JobQueue::STATUS_RUNNING); |
|
64 | + $job->save(); |
|
65 | + $database->commit(); |
|
66 | + |
|
67 | + $database->beginTransaction(); |
|
68 | + |
|
69 | + // re-lock the job |
|
70 | + $job->setStatus(JobQueue::STATUS_RUNNING); |
|
71 | + $job->save(); |
|
72 | + |
|
73 | + // validate we're allowed to run the requested task (whitelist) |
|
74 | + if (!in_array($job->getTask(), $this->taskList)) { |
|
75 | + throw new ApplicationLogicException('Job task not registered'); |
|
76 | + } |
|
77 | + |
|
78 | + // Create a task. |
|
79 | + $taskName = $job->getTask(); |
|
80 | + |
|
81 | + if(!class_exists($taskName)) { |
|
82 | + throw new ApplicationLogicException('Job task does not exist'); |
|
83 | + } |
|
84 | + |
|
85 | + /** @var BackgroundTaskBase $task */ |
|
86 | + $task = new $taskName; |
|
87 | + |
|
88 | + $this->setupTask($task, $job); |
|
89 | + $task->run(); |
|
90 | + } |
|
91 | + catch (Exception $ex) { |
|
92 | + $database->rollBack(); |
|
93 | + $database->beginTransaction(); |
|
94 | + |
|
95 | + /** @var JobQueue $job */ |
|
96 | + $job = JobQueue::getById($job->getId(), $database); |
|
97 | + $job->setDatabase($database); |
|
98 | + $job->setStatus(JobQueue::STATUS_FAILED); |
|
99 | + $job->setError($ex->getMessage()); |
|
100 | + $job->setAcknowledged(0); |
|
101 | + $job->save(); |
|
102 | + |
|
103 | + /** @var Request $request */ |
|
104 | + $request = Request::getById($job->getRequest(), $database); |
|
105 | + if ($request === false) { |
|
106 | + $request = null; |
|
107 | + } |
|
108 | + |
|
109 | + Logger::backgroundJobIssue($this->getDatabase(), $job); |
|
110 | + |
|
111 | + $database->commit(); |
|
112 | + } |
|
113 | + finally { |
|
114 | + $database->commit(); |
|
115 | + } |
|
116 | + } |
|
117 | + } |
|
118 | + |
|
119 | + /** |
|
120 | + * @param BackgroundTaskBase $task |
|
121 | + * @param JobQueue $job |
|
122 | + */ |
|
123 | + private function setupTask(BackgroundTaskBase $task, JobQueue $job) |
|
124 | + { |
|
125 | + $task->setJob($job); |
|
126 | + $task->setDatabase($this->getDatabase()); |
|
127 | + $task->setHttpHelper($this->getHttpHelper()); |
|
128 | + $task->setOauthProtocolHelper($this->getOAuthProtocolHelper()); |
|
129 | + $task->setEmailHelper($this->getEmailHelper()); |
|
130 | + $task->setSiteConfiguration($this->getSiteConfiguration()); |
|
131 | + $task->setNotificationHelper($this->getNotificationHelper()); |
|
132 | + } |
|
133 | + |
|
134 | + public static function errorHandler($errno, $errstr, $errfile, $errline) { |
|
135 | + throw new Exception($errfile . "@" . $errline . ": " . $errstr); |
|
136 | + } |
|
137 | 137 | } |
@@ -78,7 +78,7 @@ discard block |
||
78 | 78 | // Create a task. |
79 | 79 | $taskName = $job->getTask(); |
80 | 80 | |
81 | - if(!class_exists($taskName)) { |
|
81 | + if (!class_exists($taskName)) { |
|
82 | 82 | throw new ApplicationLogicException('Job task does not exist'); |
83 | 83 | } |
84 | 84 | |
@@ -132,6 +132,6 @@ discard block |
||
132 | 132 | } |
133 | 133 | |
134 | 134 | public static function errorHandler($errno, $errstr, $errfile, $errline) { |
135 | - throw new Exception($errfile . "@" . $errline . ": " . $errstr); |
|
135 | + throw new Exception($errfile."@".$errline.": ".$errstr); |
|
136 | 136 | } |
137 | 137 | } |
@@ -131,7 +131,8 @@ |
||
131 | 131 | $task->setNotificationHelper($this->getNotificationHelper()); |
132 | 132 | } |
133 | 133 | |
134 | - public static function errorHandler($errno, $errstr, $errfile, $errline) { |
|
134 | + public static function errorHandler($errno, $errstr, $errfile, $errline) |
|
135 | + { |
|
135 | 136 | throw new Exception($errfile . "@" . $errline . ": " . $errstr); |
136 | 137 | } |
137 | 138 | } |
@@ -202,27 +202,27 @@ discard block |
||
202 | 202 | |
203 | 203 | // request states |
204 | 204 | $availableRequestStates = array( |
205 | - 'Open' => array( |
|
206 | - 'defertolog' => 'users', // don't change or you'll break old logs |
|
207 | - 'deferto' => 'users', |
|
208 | - 'header' => 'Open requests', |
|
209 | - 'api' => "open", |
|
210 | - 'queuehelp' => null |
|
211 | - ), |
|
212 | - 'Flagged users' => array( |
|
213 | - 'defertolog' => 'flagged users', // don't change or you'll break old logs |
|
214 | - 'deferto' => 'flagged users', |
|
215 | - 'header' => 'Flagged user needed', |
|
216 | - 'api' => "admin", |
|
217 | - 'queuehelp' => 'This queue lists the requests which require a user with the <code>accountcreator</code> flag to create.<br />If creation is determined to be the correct course of action, requests here will require the overriding the AntiSpoof checks or the title blacklist in order to create. It is recommended to try to create the account <em>without</em> checking the flags to validate the results of the AntiSpoof and/or title blacklist hits.' |
|
218 | - ), |
|
219 | - 'Checkuser' => array( |
|
220 | - 'defertolog' => 'checkusers', // don't change or you'll break old logs |
|
221 | - 'deferto' => 'checkusers', |
|
222 | - 'header' => 'Checkuser needed', |
|
223 | - 'api' => "checkuser", |
|
224 | - 'queuehelp' => null |
|
225 | - ), |
|
205 | + 'Open' => array( |
|
206 | + 'defertolog' => 'users', // don't change or you'll break old logs |
|
207 | + 'deferto' => 'users', |
|
208 | + 'header' => 'Open requests', |
|
209 | + 'api' => "open", |
|
210 | + 'queuehelp' => null |
|
211 | + ), |
|
212 | + 'Flagged users' => array( |
|
213 | + 'defertolog' => 'flagged users', // don't change or you'll break old logs |
|
214 | + 'deferto' => 'flagged users', |
|
215 | + 'header' => 'Flagged user needed', |
|
216 | + 'api' => "admin", |
|
217 | + 'queuehelp' => 'This queue lists the requests which require a user with the <code>accountcreator</code> flag to create.<br />If creation is determined to be the correct course of action, requests here will require the overriding the AntiSpoof checks or the title blacklist in order to create. It is recommended to try to create the account <em>without</em> checking the flags to validate the results of the AntiSpoof and/or title blacklist hits.' |
|
218 | + ), |
|
219 | + 'Checkuser' => array( |
|
220 | + 'defertolog' => 'checkusers', // don't change or you'll break old logs |
|
221 | + 'deferto' => 'checkusers', |
|
222 | + 'header' => 'Checkuser needed', |
|
223 | + 'api' => "checkuser", |
|
224 | + 'queuehelp' => null |
|
225 | + ), |
|
226 | 226 | ); |
227 | 227 | |
228 | 228 | $defaultRequestStateKey = 'Open'; |
@@ -272,24 +272,24 @@ discard block |
||
272 | 272 | require_once('config.local.inc.php'); |
273 | 273 | |
274 | 274 | $cDatabaseConfig = array( |
275 | - "acc" => array( |
|
276 | - "dsrcname" => "mysql:host=" . $toolserver_host . ";dbname=" . $toolserver_database, |
|
277 | - "username" => $toolserver_username, |
|
278 | - "password" => $toolserver_password, |
|
275 | + "acc" => array( |
|
276 | + "dsrcname" => "mysql:host=" . $toolserver_host . ";dbname=" . $toolserver_database, |
|
277 | + "username" => $toolserver_username, |
|
278 | + "password" => $toolserver_password, |
|
279 | 279 | "options" => array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4'), |
280 | - ), |
|
281 | - "wikipedia" => array( |
|
282 | - "dsrcname" => "mysql:host=" . $antispoof_host . ";dbname=" . $antispoof_db, |
|
283 | - "username" => $toolserver_username, |
|
284 | - "password" => $toolserver_password, |
|
285 | - "options" => array(), |
|
286 | - ), |
|
287 | - "notifications" => array( |
|
288 | - "dsrcname" => "mysql:host=" . $toolserver_notification_dbhost . ";dbname=" . $toolserver_notification_database, |
|
289 | - "username" => $notifications_username, |
|
290 | - "password" => $notifications_password, |
|
291 | - "options" => array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4'), |
|
292 | - ), |
|
280 | + ), |
|
281 | + "wikipedia" => array( |
|
282 | + "dsrcname" => "mysql:host=" . $antispoof_host . ";dbname=" . $antispoof_db, |
|
283 | + "username" => $toolserver_username, |
|
284 | + "password" => $toolserver_password, |
|
285 | + "options" => array(), |
|
286 | + ), |
|
287 | + "notifications" => array( |
|
288 | + "dsrcname" => "mysql:host=" . $toolserver_notification_dbhost . ";dbname=" . $toolserver_notification_database, |
|
289 | + "username" => $notifications_username, |
|
290 | + "password" => $notifications_password, |
|
291 | + "options" => array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4'), |
|
292 | + ), |
|
293 | 293 | ); |
294 | 294 | |
295 | 295 | // //Keep the included files from being executed. |
@@ -301,18 +301,18 @@ discard block |
||
301 | 301 | ini_set('user_agent', $toolUserAgent); |
302 | 302 | |
303 | 303 | foreach (array( |
304 | - "mbstring", // unicode and stuff |
|
305 | - "pdo", |
|
306 | - "pdo_mysql", // new database module |
|
307 | - "session", |
|
308 | - "date", |
|
309 | - "pcre", // core stuff |
|
310 | - "curl", // mediawiki api access etc |
|
311 | - "openssl", // token generation |
|
304 | + "mbstring", // unicode and stuff |
|
305 | + "pdo", |
|
306 | + "pdo_mysql", // new database module |
|
307 | + "session", |
|
308 | + "date", |
|
309 | + "pcre", // core stuff |
|
310 | + "curl", // mediawiki api access etc |
|
311 | + "openssl", // token generation |
|
312 | 312 | ) as $x) { |
313 | - if (!extension_loaded($x)) { |
|
314 | - die("extension $x is required."); |
|
315 | - } |
|
313 | + if (!extension_loaded($x)) { |
|
314 | + die("extension $x is required."); |
|
315 | + } |
|
316 | 316 | } |
317 | 317 | |
318 | 318 | // Set up the AutoLoader |
@@ -339,41 +339,41 @@ discard block |
||
339 | 339 | $siteConfiguration = new \Waca\SiteConfiguration(); |
340 | 340 | |
341 | 341 | $siteConfiguration->setBaseUrl($baseurl) |
342 | - ->setFilePath(__DIR__) |
|
343 | - ->setDebuggingTraceEnabled($enableErrorTrace) |
|
344 | - ->setForceIdentification($forceIdentification) |
|
345 | - ->setIdentificationCacheExpiry($identificationCacheExpiry) |
|
346 | - ->setMediawikiScriptPath($mediawikiScriptPath) |
|
347 | - ->setMediawikiWebServiceEndpoint($mediawikiWebServiceEndpoint) |
|
348 | - ->setMetaWikimediaWebServiceEndpoint($metaWikimediaWebServiceEndpoint) |
|
349 | - ->setEnforceOAuth($enforceOAuth) |
|
350 | - ->setEmailConfirmationEnabled($enableEmailConfirm == 1) |
|
351 | - ->setEmailConfirmationExpiryDays($emailConfirmationExpiryDays) |
|
352 | - ->setMiserModeLimit($requestLimitShowOnly) |
|
353 | - ->setRequestStates($availableRequestStates) |
|
354 | - ->setSquidList($squidIpList) |
|
355 | - ->setDefaultCreatedTemplateId($createdid) |
|
356 | - ->setDefaultRequestStateKey($defaultRequestStateKey) |
|
357 | - ->setUseStrictTransportSecurity($strictTransportSecurityExpiry) |
|
358 | - ->setUserAgent($toolUserAgent) |
|
359 | - ->setCurlDisableVerifyPeer($curlDisableSSLVerifyPeer) |
|
360 | - ->setUseOAuthSignup($useOauthSignup) |
|
361 | - ->setOAuthBaseUrl($oauthBaseUrl) |
|
362 | - ->setOAuthConsumerToken($oauthConsumerToken) |
|
363 | - ->setOAuthConsumerSecret($oauthSecretToken) |
|
364 | - ->setOauthMediaWikiCanonicalServer($oauthMediaWikiCanonicalServer) |
|
365 | - ->setDataClearInterval($dataclear_interval) |
|
366 | - ->setXffTrustedHostsFile($xff_trusted_hosts_file) |
|
367 | - ->setIrcNotificationsEnabled($ircBotNotificationsEnabled == 1) |
|
368 | - ->setIrcNotificationType($ircBotNotificationType) |
|
369 | - ->setIrcNotificationsInstance($whichami) |
|
370 | - ->setTitleBlacklistEnabled($enableTitleblacklist == 1) |
|
371 | - ->setTorExitPaths(array_merge(gethostbynamel('en.wikipedia.org'), gethostbynamel('accounts.wmflabs.org'))) |
|
372 | - ->setCreationBotUsername($creationBotUsername) |
|
373 | - ->setCreationBotPassword($creationBotPassword) |
|
374 | - ->setCurlCookieJar($curlCookieJar) |
|
375 | - ->setYubicoApiId($yubicoApiId) |
|
376 | - ->setYubicoApiKey($yubicoApiKey) |
|
377 | - ->setTotpEncryptionKey($totpEncryptionKey) |
|
378 | - ->setRegistrationAllowed($allowRegistration) |
|
379 | - ->setCspReportUri($cspReportUri); |
|
342 | + ->setFilePath(__DIR__) |
|
343 | + ->setDebuggingTraceEnabled($enableErrorTrace) |
|
344 | + ->setForceIdentification($forceIdentification) |
|
345 | + ->setIdentificationCacheExpiry($identificationCacheExpiry) |
|
346 | + ->setMediawikiScriptPath($mediawikiScriptPath) |
|
347 | + ->setMediawikiWebServiceEndpoint($mediawikiWebServiceEndpoint) |
|
348 | + ->setMetaWikimediaWebServiceEndpoint($metaWikimediaWebServiceEndpoint) |
|
349 | + ->setEnforceOAuth($enforceOAuth) |
|
350 | + ->setEmailConfirmationEnabled($enableEmailConfirm == 1) |
|
351 | + ->setEmailConfirmationExpiryDays($emailConfirmationExpiryDays) |
|
352 | + ->setMiserModeLimit($requestLimitShowOnly) |
|
353 | + ->setRequestStates($availableRequestStates) |
|
354 | + ->setSquidList($squidIpList) |
|
355 | + ->setDefaultCreatedTemplateId($createdid) |
|
356 | + ->setDefaultRequestStateKey($defaultRequestStateKey) |
|
357 | + ->setUseStrictTransportSecurity($strictTransportSecurityExpiry) |
|
358 | + ->setUserAgent($toolUserAgent) |
|
359 | + ->setCurlDisableVerifyPeer($curlDisableSSLVerifyPeer) |
|
360 | + ->setUseOAuthSignup($useOauthSignup) |
|
361 | + ->setOAuthBaseUrl($oauthBaseUrl) |
|
362 | + ->setOAuthConsumerToken($oauthConsumerToken) |
|
363 | + ->setOAuthConsumerSecret($oauthSecretToken) |
|
364 | + ->setOauthMediaWikiCanonicalServer($oauthMediaWikiCanonicalServer) |
|
365 | + ->setDataClearInterval($dataclear_interval) |
|
366 | + ->setXffTrustedHostsFile($xff_trusted_hosts_file) |
|
367 | + ->setIrcNotificationsEnabled($ircBotNotificationsEnabled == 1) |
|
368 | + ->setIrcNotificationType($ircBotNotificationType) |
|
369 | + ->setIrcNotificationsInstance($whichami) |
|
370 | + ->setTitleBlacklistEnabled($enableTitleblacklist == 1) |
|
371 | + ->setTorExitPaths(array_merge(gethostbynamel('en.wikipedia.org'), gethostbynamel('accounts.wmflabs.org'))) |
|
372 | + ->setCreationBotUsername($creationBotUsername) |
|
373 | + ->setCreationBotPassword($creationBotPassword) |
|
374 | + ->setCurlCookieJar($curlCookieJar) |
|
375 | + ->setYubicoApiId($yubicoApiId) |
|
376 | + ->setYubicoApiKey($yubicoApiKey) |
|
377 | + ->setTotpEncryptionKey($totpEncryptionKey) |
|
378 | + ->setRegistrationAllowed($allowRegistration) |
|
379 | + ->setCspReportUri($cspReportUri); |
@@ -17,20 +17,20 @@ |
||
17 | 17 | |
18 | 18 | class JsTemplateConfirmsAction extends JsonApiPageBase implements IJsonApiAction |
19 | 19 | { |
20 | - public function executeApiAction() |
|
21 | - { |
|
22 | - $this->getDatabase(); |
|
20 | + public function executeApiAction() |
|
21 | + { |
|
22 | + $this->getDatabase(); |
|
23 | 23 | |
24 | - /** @var EmailTemplate[] $templates */ |
|
25 | - $templates = EmailTemplate::getAllActiveTemplates(null, $this->getDatabase()); |
|
24 | + /** @var EmailTemplate[] $templates */ |
|
25 | + $templates = EmailTemplate::getAllActiveTemplates(null, $this->getDatabase()); |
|
26 | 26 | |
27 | - $dataset = []; |
|
28 | - foreach ($templates as $tpl) { |
|
29 | - if($tpl->getJsquestion() != "") { |
|
30 | - $dataset[$tpl->getId()] = $tpl->getJsquestion(); |
|
31 | - } |
|
32 | - } |
|
27 | + $dataset = []; |
|
28 | + foreach ($templates as $tpl) { |
|
29 | + if($tpl->getJsquestion() != "") { |
|
30 | + $dataset[$tpl->getId()] = $tpl->getJsquestion(); |
|
31 | + } |
|
32 | + } |
|
33 | 33 | |
34 | - return $dataset; |
|
35 | - } |
|
34 | + return $dataset; |
|
35 | + } |
|
36 | 36 | } |
@@ -26,7 +26,7 @@ |
||
26 | 26 | |
27 | 27 | $dataset = []; |
28 | 28 | foreach ($templates as $tpl) { |
29 | - if($tpl->getJsquestion() != "") { |
|
29 | + if ($tpl->getJsquestion() != "") { |
|
30 | 30 | $dataset[$tpl->getId()] = $tpl->getJsquestion(); |
31 | 31 | } |
32 | 32 | } |
@@ -25,280 +25,280 @@ |
||
25 | 25 | |
26 | 26 | class PageViewRequest extends InternalPageBase |
27 | 27 | { |
28 | - use RequestData; |
|
29 | - const STATUS_SYMBOL_OPEN = '☐'; |
|
30 | - const STATUS_SYMBOL_ACCEPTED = '☑'; |
|
31 | - const STATUS_SYMBOL_REJECTED = '☒'; |
|
32 | - |
|
33 | - /** |
|
34 | - * Main function for this page, when no specific actions are called. |
|
35 | - * @throws ApplicationLogicException |
|
36 | - */ |
|
37 | - protected function main() |
|
38 | - { |
|
39 | - // set up csrf protection |
|
40 | - $this->assignCSRFToken(); |
|
41 | - |
|
42 | - // get some useful objects |
|
43 | - $database = $this->getDatabase(); |
|
44 | - $request = $this->getRequest($database, WebRequest::getInt('id')); |
|
45 | - $config = $this->getSiteConfiguration(); |
|
46 | - $currentUser = User::getCurrent($database); |
|
47 | - |
|
48 | - // Test we should be able to look at this request |
|
49 | - if ($config->getEmailConfirmationEnabled()) { |
|
50 | - if ($request->getEmailConfirm() !== 'Confirmed') { |
|
51 | - // Not allowed to look at this yet. |
|
52 | - throw new ApplicationLogicException('The email address has not yet been confirmed for this request.'); |
|
53 | - } |
|
54 | - } |
|
55 | - |
|
56 | - $this->setupBasicData($request, $config); |
|
57 | - |
|
58 | - $this->setupUsernameData($request); |
|
59 | - |
|
60 | - $this->setupTitle($request); |
|
61 | - |
|
62 | - $this->setupReservationDetails($request->getReserved(), $database, $currentUser); |
|
63 | - $this->setupGeneralData($database); |
|
64 | - |
|
65 | - $this->assign('requestDataCleared', false); |
|
66 | - if ($request->getEmail() === $this->getSiteConfiguration()->getDataClearEmail()) { |
|
67 | - $this->assign('requestDataCleared', true); |
|
68 | - } |
|
69 | - |
|
70 | - $allowedPrivateData = $this->isAllowedPrivateData($request, $currentUser); |
|
71 | - |
|
72 | - $this->setupCreationTypes($currentUser); |
|
73 | - |
|
74 | - $this->setupLogData($request, $database); |
|
75 | - |
|
76 | - $this->addJs("/api.php?action=templates&targetVariable=templateconfirms"); |
|
77 | - |
|
78 | - if ($allowedPrivateData) { |
|
79 | - $this->setTemplate('view-request/main-with-data.tpl'); |
|
80 | - $this->setupPrivateData($request, $currentUser, $this->getSiteConfiguration(), $database); |
|
81 | - |
|
82 | - $this->assign('canSetBan', $this->barrierTest('set', $currentUser, PageBan::class)); |
|
83 | - $this->assign('canSeeCheckuserData', $this->barrierTest('seeUserAgentData', $currentUser, 'RequestData')); |
|
84 | - |
|
85 | - if ($this->barrierTest('seeUserAgentData', $currentUser, 'RequestData')) { |
|
86 | - $this->setTemplate('view-request/main-with-checkuser-data.tpl'); |
|
87 | - $this->setupCheckUserData($request); |
|
88 | - } |
|
89 | - } |
|
90 | - else { |
|
91 | - $this->setTemplate('view-request/main.tpl'); |
|
92 | - } |
|
93 | - } |
|
94 | - |
|
95 | - /** |
|
96 | - * @param Request $request |
|
97 | - */ |
|
98 | - protected function setupTitle(Request $request) |
|
99 | - { |
|
100 | - $statusSymbol = self::STATUS_SYMBOL_OPEN; |
|
101 | - if ($request->getStatus() === 'Closed') { |
|
102 | - if ($request->getWasCreated()) { |
|
103 | - $statusSymbol = self::STATUS_SYMBOL_ACCEPTED; |
|
104 | - } |
|
105 | - else { |
|
106 | - $statusSymbol = self::STATUS_SYMBOL_REJECTED; |
|
107 | - } |
|
108 | - } |
|
109 | - |
|
110 | - $this->setHtmlTitle($statusSymbol . ' #' . $request->getId()); |
|
111 | - } |
|
112 | - |
|
113 | - /** |
|
114 | - * Sets up data unrelated to the request, such as the email template information |
|
115 | - * |
|
116 | - * @param PdoDatabase $database |
|
117 | - */ |
|
118 | - protected function setupGeneralData(PdoDatabase $database) |
|
119 | - { |
|
120 | - $config = $this->getSiteConfiguration(); |
|
121 | - |
|
122 | - $this->assign('createAccountReason', 'Requested account at [[WP:ACC]], request #'); |
|
123 | - |
|
124 | - $this->assign('defaultRequestState', $config->getDefaultRequestStateKey()); |
|
125 | - |
|
126 | - $this->assign('requestStates', $config->getRequestStates()); |
|
127 | - |
|
128 | - /** @var EmailTemplate $createdTemplate */ |
|
129 | - $createdTemplate = EmailTemplate::getById($config->getDefaultCreatedTemplateId(), $database); |
|
130 | - |
|
131 | - $this->assign('createdHasJsQuestion', $createdTemplate->getJsquestion() != ''); |
|
132 | - $this->assign('createdId', $createdTemplate->getId()); |
|
133 | - $this->assign('createdName', $createdTemplate->getName()); |
|
134 | - |
|
135 | - $createReasons = EmailTemplate::getActiveTemplates(EmailTemplate::CREATED, $database); |
|
136 | - $this->assign("createReasons", $createReasons); |
|
137 | - $declineReasons = EmailTemplate::getActiveTemplates(EmailTemplate::NOT_CREATED, $database); |
|
138 | - $this->assign("declineReasons", $declineReasons); |
|
139 | - |
|
140 | - $allCreateReasons = EmailTemplate::getAllActiveTemplates(EmailTemplate::CREATED, $database); |
|
141 | - $this->assign("allCreateReasons", $allCreateReasons); |
|
142 | - $allDeclineReasons = EmailTemplate::getAllActiveTemplates(EmailTemplate::NOT_CREATED, $database); |
|
143 | - $this->assign("allDeclineReasons", $allDeclineReasons); |
|
144 | - $allOtherReasons = EmailTemplate::getAllActiveTemplates(false, $database); |
|
145 | - $this->assign("allOtherReasons", $allOtherReasons); |
|
146 | - } |
|
147 | - |
|
148 | - private function setupLogData(Request $request, PdoDatabase $database) |
|
149 | - { |
|
150 | - $currentUser = User::getCurrent($database); |
|
151 | - |
|
152 | - $logs = LogHelper::getRequestLogsWithComments($request->getId(), $database, $this->getSecurityManager()); |
|
153 | - $requestLogs = array(); |
|
154 | - |
|
155 | - if (trim($request->getComment()) !== "") { |
|
156 | - $requestLogs[] = array( |
|
157 | - 'type' => 'comment', |
|
158 | - 'security' => 'user', |
|
159 | - 'userid' => null, |
|
160 | - 'user' => $request->getName(), |
|
161 | - 'entry' => null, |
|
162 | - 'time' => $request->getDate(), |
|
163 | - 'canedit' => false, |
|
164 | - 'id' => $request->getId(), |
|
165 | - 'comment' => $request->getComment(), |
|
166 | - ); |
|
167 | - } |
|
168 | - |
|
169 | - /** @var User[] $nameCache */ |
|
170 | - $nameCache = array(); |
|
171 | - |
|
172 | - $editableComments = $this->barrierTest('editOthers', $currentUser, PageEditComment::class); |
|
173 | - |
|
174 | - /** @var Log|Comment $entry */ |
|
175 | - foreach ($logs as $entry) { |
|
176 | - // both log and comment have a 'user' field |
|
177 | - if (!array_key_exists($entry->getUser(), $nameCache)) { |
|
178 | - $entryUser = User::getById($entry->getUser(), $database); |
|
179 | - $nameCache[$entry->getUser()] = $entryUser; |
|
180 | - } |
|
181 | - |
|
182 | - if ($entry instanceof Comment) { |
|
183 | - $requestLogs[] = array( |
|
184 | - 'type' => 'comment', |
|
185 | - 'security' => $entry->getVisibility(), |
|
186 | - 'user' => $nameCache[$entry->getUser()]->getUsername(), |
|
187 | - 'userid' => $entry->getUser() == -1 ? null : $entry->getUser(), |
|
188 | - 'entry' => null, |
|
189 | - 'time' => $entry->getTime(), |
|
190 | - 'canedit' => ($editableComments || $entry->getUser() == $currentUser->getId()), |
|
191 | - 'id' => $entry->getId(), |
|
192 | - 'comment' => $entry->getComment(), |
|
193 | - ); |
|
194 | - } |
|
195 | - |
|
196 | - if ($entry instanceof Log) { |
|
197 | - $invalidUserId = $entry->getUser() === -1 || $entry->getUser() === 0; |
|
198 | - $entryUser = $invalidUserId ? User::getCommunity() : $nameCache[$entry->getUser()]; |
|
199 | - |
|
200 | - $entryComment = $entry->getComment(); |
|
201 | - |
|
202 | - if($entry->getAction() === 'JobIssueRequest' || $entry->getAction() === 'JobCompletedRequest'){ |
|
203 | - $data = unserialize($entry->getComment()); |
|
204 | - /** @var JobQueue $job */ |
|
205 | - $job = JobQueue::getById($data['job'], $database); |
|
206 | - $requestLogs[] = array( |
|
207 | - 'type' => 'joblog', |
|
208 | - 'security' => 'user', |
|
209 | - 'userid' => $entry->getUser() == -1 ? null : $entry->getUser(), |
|
210 | - 'user' => $entryUser->getUsername(), |
|
211 | - 'entry' => LogHelper::getLogDescription($entry), |
|
212 | - 'time' => $entry->getTimestamp(), |
|
213 | - 'canedit' => false, |
|
214 | - 'id' => $entry->getId(), |
|
215 | - 'jobId' => $job->getId(), |
|
216 | - 'jobDesc' => JobQueue::getTaskDescriptions()[$job->getTask()], |
|
217 | - ); |
|
218 | - } else { |
|
219 | - $requestLogs[] = array( |
|
220 | - 'type' => 'log', |
|
221 | - 'security' => 'user', |
|
222 | - 'userid' => $entry->getUser() == -1 ? null : $entry->getUser(), |
|
223 | - 'user' => $entryUser->getUsername(), |
|
224 | - 'entry' => LogHelper::getLogDescription($entry), |
|
225 | - 'time' => $entry->getTimestamp(), |
|
226 | - 'canedit' => false, |
|
227 | - 'id' => $entry->getId(), |
|
228 | - 'comment' => $entryComment, |
|
229 | - ); |
|
230 | - } |
|
231 | - } |
|
232 | - } |
|
233 | - |
|
234 | - $this->addJs("/api.php?action=users&targetVariable=typeaheaddata"); |
|
235 | - |
|
236 | - $this->assign("requestLogs", $requestLogs); |
|
237 | - } |
|
238 | - |
|
239 | - /** |
|
240 | - * @param Request $request |
|
241 | - */ |
|
242 | - protected function setupUsernameData(Request $request) |
|
243 | - { |
|
244 | - $blacklistData = $this->getBlacklistHelper()->isBlacklisted($request->getName()); |
|
245 | - |
|
246 | - $this->assign('requestIsBlacklisted', $blacklistData !== false); |
|
247 | - $this->assign('requestBlacklist', $blacklistData); |
|
248 | - |
|
249 | - try { |
|
250 | - $spoofs = $this->getAntiSpoofProvider()->getSpoofs($request->getName()); |
|
251 | - } |
|
252 | - catch (Exception $ex) { |
|
253 | - $spoofs = $ex->getMessage(); |
|
254 | - } |
|
255 | - |
|
256 | - $this->assign("spoofs", $spoofs); |
|
257 | - } |
|
258 | - |
|
259 | - private function setupCreationTypes(User $user) |
|
260 | - { |
|
261 | - $this->assign('allowWelcomeSkip', false); |
|
262 | - $this->assign('forceWelcomeSkip', false); |
|
263 | - |
|
264 | - $oauth = new OAuthUserHelper($user, $this->getDatabase(), $this->getOAuthProtocolHelper(), $this->getSiteConfiguration()); |
|
265 | - |
|
266 | - if ($user->getWelcomeTemplate() != 0) { |
|
267 | - $this->assign('allowWelcomeSkip', true); |
|
268 | - |
|
269 | - if (!$oauth->canWelcome()) { |
|
270 | - $this->assign('forceWelcomeSkip', true); |
|
271 | - } |
|
272 | - } |
|
273 | - |
|
274 | - // test credentials |
|
275 | - $canManualCreate = $this->barrierTest(User::CREATION_MANUAL, $user, 'RequestCreation'); |
|
276 | - $canOauthCreate = $this->barrierTest(User::CREATION_OAUTH, $user, 'RequestCreation'); |
|
277 | - $canBotCreate = $this->barrierTest(User::CREATION_BOT, $user, 'RequestCreation'); |
|
278 | - |
|
279 | - $this->assign('canManualCreate', $canManualCreate); |
|
280 | - $this->assign('canOauthCreate', $canOauthCreate); |
|
281 | - $this->assign('canBotCreate', $canBotCreate); |
|
282 | - |
|
283 | - // show/hide the type radio buttons |
|
284 | - $creationHasChoice = count(array_filter([$canManualCreate, $canOauthCreate, $canBotCreate])) > 1; |
|
285 | - |
|
286 | - if (!$this->barrierTest($user->getCreationMode(), $user, 'RequestCreation')) { |
|
287 | - // user is not allowed to use their default. Force a choice. |
|
288 | - $creationHasChoice = true; |
|
289 | - } |
|
290 | - |
|
291 | - $this->assign('creationHasChoice', $creationHasChoice); |
|
292 | - |
|
293 | - // determine problems in creation types |
|
294 | - $this->assign('botProblem', false); |
|
295 | - if ($canBotCreate && $this->getSiteConfiguration()->getCreationBotPassword() === null) { |
|
296 | - $this->assign('botProblem', true); |
|
297 | - } |
|
298 | - |
|
299 | - $this->assign('oauthProblem', false); |
|
300 | - if ($canOauthCreate && !$oauth->canCreateAccount()) { |
|
301 | - $this->assign('oauthProblem', true); |
|
302 | - } |
|
303 | - } |
|
28 | + use RequestData; |
|
29 | + const STATUS_SYMBOL_OPEN = '☐'; |
|
30 | + const STATUS_SYMBOL_ACCEPTED = '☑'; |
|
31 | + const STATUS_SYMBOL_REJECTED = '☒'; |
|
32 | + |
|
33 | + /** |
|
34 | + * Main function for this page, when no specific actions are called. |
|
35 | + * @throws ApplicationLogicException |
|
36 | + */ |
|
37 | + protected function main() |
|
38 | + { |
|
39 | + // set up csrf protection |
|
40 | + $this->assignCSRFToken(); |
|
41 | + |
|
42 | + // get some useful objects |
|
43 | + $database = $this->getDatabase(); |
|
44 | + $request = $this->getRequest($database, WebRequest::getInt('id')); |
|
45 | + $config = $this->getSiteConfiguration(); |
|
46 | + $currentUser = User::getCurrent($database); |
|
47 | + |
|
48 | + // Test we should be able to look at this request |
|
49 | + if ($config->getEmailConfirmationEnabled()) { |
|
50 | + if ($request->getEmailConfirm() !== 'Confirmed') { |
|
51 | + // Not allowed to look at this yet. |
|
52 | + throw new ApplicationLogicException('The email address has not yet been confirmed for this request.'); |
|
53 | + } |
|
54 | + } |
|
55 | + |
|
56 | + $this->setupBasicData($request, $config); |
|
57 | + |
|
58 | + $this->setupUsernameData($request); |
|
59 | + |
|
60 | + $this->setupTitle($request); |
|
61 | + |
|
62 | + $this->setupReservationDetails($request->getReserved(), $database, $currentUser); |
|
63 | + $this->setupGeneralData($database); |
|
64 | + |
|
65 | + $this->assign('requestDataCleared', false); |
|
66 | + if ($request->getEmail() === $this->getSiteConfiguration()->getDataClearEmail()) { |
|
67 | + $this->assign('requestDataCleared', true); |
|
68 | + } |
|
69 | + |
|
70 | + $allowedPrivateData = $this->isAllowedPrivateData($request, $currentUser); |
|
71 | + |
|
72 | + $this->setupCreationTypes($currentUser); |
|
73 | + |
|
74 | + $this->setupLogData($request, $database); |
|
75 | + |
|
76 | + $this->addJs("/api.php?action=templates&targetVariable=templateconfirms"); |
|
77 | + |
|
78 | + if ($allowedPrivateData) { |
|
79 | + $this->setTemplate('view-request/main-with-data.tpl'); |
|
80 | + $this->setupPrivateData($request, $currentUser, $this->getSiteConfiguration(), $database); |
|
81 | + |
|
82 | + $this->assign('canSetBan', $this->barrierTest('set', $currentUser, PageBan::class)); |
|
83 | + $this->assign('canSeeCheckuserData', $this->barrierTest('seeUserAgentData', $currentUser, 'RequestData')); |
|
84 | + |
|
85 | + if ($this->barrierTest('seeUserAgentData', $currentUser, 'RequestData')) { |
|
86 | + $this->setTemplate('view-request/main-with-checkuser-data.tpl'); |
|
87 | + $this->setupCheckUserData($request); |
|
88 | + } |
|
89 | + } |
|
90 | + else { |
|
91 | + $this->setTemplate('view-request/main.tpl'); |
|
92 | + } |
|
93 | + } |
|
94 | + |
|
95 | + /** |
|
96 | + * @param Request $request |
|
97 | + */ |
|
98 | + protected function setupTitle(Request $request) |
|
99 | + { |
|
100 | + $statusSymbol = self::STATUS_SYMBOL_OPEN; |
|
101 | + if ($request->getStatus() === 'Closed') { |
|
102 | + if ($request->getWasCreated()) { |
|
103 | + $statusSymbol = self::STATUS_SYMBOL_ACCEPTED; |
|
104 | + } |
|
105 | + else { |
|
106 | + $statusSymbol = self::STATUS_SYMBOL_REJECTED; |
|
107 | + } |
|
108 | + } |
|
109 | + |
|
110 | + $this->setHtmlTitle($statusSymbol . ' #' . $request->getId()); |
|
111 | + } |
|
112 | + |
|
113 | + /** |
|
114 | + * Sets up data unrelated to the request, such as the email template information |
|
115 | + * |
|
116 | + * @param PdoDatabase $database |
|
117 | + */ |
|
118 | + protected function setupGeneralData(PdoDatabase $database) |
|
119 | + { |
|
120 | + $config = $this->getSiteConfiguration(); |
|
121 | + |
|
122 | + $this->assign('createAccountReason', 'Requested account at [[WP:ACC]], request #'); |
|
123 | + |
|
124 | + $this->assign('defaultRequestState', $config->getDefaultRequestStateKey()); |
|
125 | + |
|
126 | + $this->assign('requestStates', $config->getRequestStates()); |
|
127 | + |
|
128 | + /** @var EmailTemplate $createdTemplate */ |
|
129 | + $createdTemplate = EmailTemplate::getById($config->getDefaultCreatedTemplateId(), $database); |
|
130 | + |
|
131 | + $this->assign('createdHasJsQuestion', $createdTemplate->getJsquestion() != ''); |
|
132 | + $this->assign('createdId', $createdTemplate->getId()); |
|
133 | + $this->assign('createdName', $createdTemplate->getName()); |
|
134 | + |
|
135 | + $createReasons = EmailTemplate::getActiveTemplates(EmailTemplate::CREATED, $database); |
|
136 | + $this->assign("createReasons", $createReasons); |
|
137 | + $declineReasons = EmailTemplate::getActiveTemplates(EmailTemplate::NOT_CREATED, $database); |
|
138 | + $this->assign("declineReasons", $declineReasons); |
|
139 | + |
|
140 | + $allCreateReasons = EmailTemplate::getAllActiveTemplates(EmailTemplate::CREATED, $database); |
|
141 | + $this->assign("allCreateReasons", $allCreateReasons); |
|
142 | + $allDeclineReasons = EmailTemplate::getAllActiveTemplates(EmailTemplate::NOT_CREATED, $database); |
|
143 | + $this->assign("allDeclineReasons", $allDeclineReasons); |
|
144 | + $allOtherReasons = EmailTemplate::getAllActiveTemplates(false, $database); |
|
145 | + $this->assign("allOtherReasons", $allOtherReasons); |
|
146 | + } |
|
147 | + |
|
148 | + private function setupLogData(Request $request, PdoDatabase $database) |
|
149 | + { |
|
150 | + $currentUser = User::getCurrent($database); |
|
151 | + |
|
152 | + $logs = LogHelper::getRequestLogsWithComments($request->getId(), $database, $this->getSecurityManager()); |
|
153 | + $requestLogs = array(); |
|
154 | + |
|
155 | + if (trim($request->getComment()) !== "") { |
|
156 | + $requestLogs[] = array( |
|
157 | + 'type' => 'comment', |
|
158 | + 'security' => 'user', |
|
159 | + 'userid' => null, |
|
160 | + 'user' => $request->getName(), |
|
161 | + 'entry' => null, |
|
162 | + 'time' => $request->getDate(), |
|
163 | + 'canedit' => false, |
|
164 | + 'id' => $request->getId(), |
|
165 | + 'comment' => $request->getComment(), |
|
166 | + ); |
|
167 | + } |
|
168 | + |
|
169 | + /** @var User[] $nameCache */ |
|
170 | + $nameCache = array(); |
|
171 | + |
|
172 | + $editableComments = $this->barrierTest('editOthers', $currentUser, PageEditComment::class); |
|
173 | + |
|
174 | + /** @var Log|Comment $entry */ |
|
175 | + foreach ($logs as $entry) { |
|
176 | + // both log and comment have a 'user' field |
|
177 | + if (!array_key_exists($entry->getUser(), $nameCache)) { |
|
178 | + $entryUser = User::getById($entry->getUser(), $database); |
|
179 | + $nameCache[$entry->getUser()] = $entryUser; |
|
180 | + } |
|
181 | + |
|
182 | + if ($entry instanceof Comment) { |
|
183 | + $requestLogs[] = array( |
|
184 | + 'type' => 'comment', |
|
185 | + 'security' => $entry->getVisibility(), |
|
186 | + 'user' => $nameCache[$entry->getUser()]->getUsername(), |
|
187 | + 'userid' => $entry->getUser() == -1 ? null : $entry->getUser(), |
|
188 | + 'entry' => null, |
|
189 | + 'time' => $entry->getTime(), |
|
190 | + 'canedit' => ($editableComments || $entry->getUser() == $currentUser->getId()), |
|
191 | + 'id' => $entry->getId(), |
|
192 | + 'comment' => $entry->getComment(), |
|
193 | + ); |
|
194 | + } |
|
195 | + |
|
196 | + if ($entry instanceof Log) { |
|
197 | + $invalidUserId = $entry->getUser() === -1 || $entry->getUser() === 0; |
|
198 | + $entryUser = $invalidUserId ? User::getCommunity() : $nameCache[$entry->getUser()]; |
|
199 | + |
|
200 | + $entryComment = $entry->getComment(); |
|
201 | + |
|
202 | + if($entry->getAction() === 'JobIssueRequest' || $entry->getAction() === 'JobCompletedRequest'){ |
|
203 | + $data = unserialize($entry->getComment()); |
|
204 | + /** @var JobQueue $job */ |
|
205 | + $job = JobQueue::getById($data['job'], $database); |
|
206 | + $requestLogs[] = array( |
|
207 | + 'type' => 'joblog', |
|
208 | + 'security' => 'user', |
|
209 | + 'userid' => $entry->getUser() == -1 ? null : $entry->getUser(), |
|
210 | + 'user' => $entryUser->getUsername(), |
|
211 | + 'entry' => LogHelper::getLogDescription($entry), |
|
212 | + 'time' => $entry->getTimestamp(), |
|
213 | + 'canedit' => false, |
|
214 | + 'id' => $entry->getId(), |
|
215 | + 'jobId' => $job->getId(), |
|
216 | + 'jobDesc' => JobQueue::getTaskDescriptions()[$job->getTask()], |
|
217 | + ); |
|
218 | + } else { |
|
219 | + $requestLogs[] = array( |
|
220 | + 'type' => 'log', |
|
221 | + 'security' => 'user', |
|
222 | + 'userid' => $entry->getUser() == -1 ? null : $entry->getUser(), |
|
223 | + 'user' => $entryUser->getUsername(), |
|
224 | + 'entry' => LogHelper::getLogDescription($entry), |
|
225 | + 'time' => $entry->getTimestamp(), |
|
226 | + 'canedit' => false, |
|
227 | + 'id' => $entry->getId(), |
|
228 | + 'comment' => $entryComment, |
|
229 | + ); |
|
230 | + } |
|
231 | + } |
|
232 | + } |
|
233 | + |
|
234 | + $this->addJs("/api.php?action=users&targetVariable=typeaheaddata"); |
|
235 | + |
|
236 | + $this->assign("requestLogs", $requestLogs); |
|
237 | + } |
|
238 | + |
|
239 | + /** |
|
240 | + * @param Request $request |
|
241 | + */ |
|
242 | + protected function setupUsernameData(Request $request) |
|
243 | + { |
|
244 | + $blacklistData = $this->getBlacklistHelper()->isBlacklisted($request->getName()); |
|
245 | + |
|
246 | + $this->assign('requestIsBlacklisted', $blacklistData !== false); |
|
247 | + $this->assign('requestBlacklist', $blacklistData); |
|
248 | + |
|
249 | + try { |
|
250 | + $spoofs = $this->getAntiSpoofProvider()->getSpoofs($request->getName()); |
|
251 | + } |
|
252 | + catch (Exception $ex) { |
|
253 | + $spoofs = $ex->getMessage(); |
|
254 | + } |
|
255 | + |
|
256 | + $this->assign("spoofs", $spoofs); |
|
257 | + } |
|
258 | + |
|
259 | + private function setupCreationTypes(User $user) |
|
260 | + { |
|
261 | + $this->assign('allowWelcomeSkip', false); |
|
262 | + $this->assign('forceWelcomeSkip', false); |
|
263 | + |
|
264 | + $oauth = new OAuthUserHelper($user, $this->getDatabase(), $this->getOAuthProtocolHelper(), $this->getSiteConfiguration()); |
|
265 | + |
|
266 | + if ($user->getWelcomeTemplate() != 0) { |
|
267 | + $this->assign('allowWelcomeSkip', true); |
|
268 | + |
|
269 | + if (!$oauth->canWelcome()) { |
|
270 | + $this->assign('forceWelcomeSkip', true); |
|
271 | + } |
|
272 | + } |
|
273 | + |
|
274 | + // test credentials |
|
275 | + $canManualCreate = $this->barrierTest(User::CREATION_MANUAL, $user, 'RequestCreation'); |
|
276 | + $canOauthCreate = $this->barrierTest(User::CREATION_OAUTH, $user, 'RequestCreation'); |
|
277 | + $canBotCreate = $this->barrierTest(User::CREATION_BOT, $user, 'RequestCreation'); |
|
278 | + |
|
279 | + $this->assign('canManualCreate', $canManualCreate); |
|
280 | + $this->assign('canOauthCreate', $canOauthCreate); |
|
281 | + $this->assign('canBotCreate', $canBotCreate); |
|
282 | + |
|
283 | + // show/hide the type radio buttons |
|
284 | + $creationHasChoice = count(array_filter([$canManualCreate, $canOauthCreate, $canBotCreate])) > 1; |
|
285 | + |
|
286 | + if (!$this->barrierTest($user->getCreationMode(), $user, 'RequestCreation')) { |
|
287 | + // user is not allowed to use their default. Force a choice. |
|
288 | + $creationHasChoice = true; |
|
289 | + } |
|
290 | + |
|
291 | + $this->assign('creationHasChoice', $creationHasChoice); |
|
292 | + |
|
293 | + // determine problems in creation types |
|
294 | + $this->assign('botProblem', false); |
|
295 | + if ($canBotCreate && $this->getSiteConfiguration()->getCreationBotPassword() === null) { |
|
296 | + $this->assign('botProblem', true); |
|
297 | + } |
|
298 | + |
|
299 | + $this->assign('oauthProblem', false); |
|
300 | + if ($canOauthCreate && !$oauth->canCreateAccount()) { |
|
301 | + $this->assign('oauthProblem', true); |
|
302 | + } |
|
303 | + } |
|
304 | 304 | } |
@@ -16,94 +16,94 @@ |
||
16 | 16 | |
17 | 17 | class PagePreferences extends InternalPageBase |
18 | 18 | { |
19 | - /** |
|
20 | - * Main function for this page, when no specific actions are called. |
|
21 | - * @return void |
|
22 | - */ |
|
23 | - protected function main() |
|
24 | - { |
|
25 | - $this->setHtmlTitle('Preferences'); |
|
26 | - |
|
27 | - $enforceOAuth = $this->getSiteConfiguration()->getEnforceOAuth(); |
|
28 | - $database = $this->getDatabase(); |
|
29 | - $user = User::getCurrent($database); |
|
30 | - |
|
31 | - // Dual mode |
|
32 | - if (WebRequest::wasPosted()) { |
|
33 | - $this->validateCSRFToken(); |
|
34 | - $user->setWelcomeSig(WebRequest::postString('sig')); |
|
35 | - $user->setEmailSig(WebRequest::postString('emailsig')); |
|
36 | - $user->setAbortPref(WebRequest::postBoolean('abortpref') ? 1 : 0); |
|
37 | - $this->setCreationMode($user); |
|
38 | - $user->setSkin(WebRequest::postBoolean('skintype') ? 'alt' : 'main'); |
|
39 | - |
|
40 | - $email = WebRequest::postEmail('email'); |
|
41 | - if ($email !== null) { |
|
42 | - $user->setEmail($email); |
|
43 | - } |
|
44 | - |
|
45 | - $user->save(); |
|
46 | - SessionAlert::success("Preferences updated!"); |
|
47 | - |
|
48 | - $this->redirect(''); |
|
49 | - } |
|
50 | - else { |
|
51 | - $this->assignCSRFToken(); |
|
52 | - $this->setTemplate('preferences/prefs.tpl'); |
|
53 | - $this->assign("enforceOAuth", $enforceOAuth); |
|
54 | - |
|
55 | - $this->assign('canManualCreate', |
|
56 | - $this->barrierTest(User::CREATION_MANUAL, $user, 'RequestCreation')); |
|
57 | - $this->assign('canOauthCreate', |
|
58 | - $this->barrierTest(User::CREATION_OAUTH, $user, 'RequestCreation')); |
|
59 | - $this->assign('canBotCreate', |
|
60 | - $this->barrierTest(User::CREATION_BOT, $user, 'RequestCreation')); |
|
61 | - |
|
62 | - $oauth = new OAuthUserHelper($user, $database, $this->getOAuthProtocolHelper(), |
|
63 | - $this->getSiteConfiguration()); |
|
64 | - $this->assign('oauth', $oauth); |
|
65 | - |
|
66 | - $identity = null; |
|
67 | - if ($oauth->isFullyLinked()) { |
|
68 | - $identity = $oauth->getIdentity(); |
|
69 | - } |
|
70 | - |
|
71 | - $this->assign('identity', $identity); |
|
72 | - $this->assign('graceTime', $this->getSiteConfiguration()->getOauthIdentityGraceTime()); |
|
73 | - } |
|
74 | - } |
|
75 | - |
|
76 | - protected function refreshOAuth() |
|
77 | - { |
|
78 | - if (!WebRequest::wasPosted()) { |
|
79 | - $this->redirect('preferences'); |
|
80 | - |
|
81 | - return; |
|
82 | - } |
|
83 | - |
|
84 | - $database = $this->getDatabase(); |
|
85 | - $oauth = new OAuthUserHelper(User::getCurrent($database), $database, $this->getOAuthProtocolHelper(), |
|
86 | - $this->getSiteConfiguration()); |
|
87 | - if ($oauth->isFullyLinked()) { |
|
88 | - $oauth->refreshIdentity(); |
|
89 | - } |
|
90 | - |
|
91 | - $this->redirect('preferences'); |
|
92 | - |
|
93 | - return; |
|
94 | - } |
|
95 | - |
|
96 | - /** |
|
97 | - * @param User $user |
|
98 | - */ |
|
99 | - protected function setCreationMode(User $user) |
|
100 | - { |
|
101 | - // if the user is selecting a creation mode that they are not allowed, do nothing. |
|
102 | - // this has the side effect of allowing them to keep a selected mode that either has been changed for them, |
|
103 | - // or that they have kept from when they previously had certain access. |
|
104 | - $creationMode = WebRequest::postInt('creationmode'); |
|
105 | - if ($this->barrierTest($creationMode, $user, 'RequestCreation')) { |
|
106 | - $user->setCreationMode($creationMode); |
|
107 | - } |
|
108 | - } |
|
19 | + /** |
|
20 | + * Main function for this page, when no specific actions are called. |
|
21 | + * @return void |
|
22 | + */ |
|
23 | + protected function main() |
|
24 | + { |
|
25 | + $this->setHtmlTitle('Preferences'); |
|
26 | + |
|
27 | + $enforceOAuth = $this->getSiteConfiguration()->getEnforceOAuth(); |
|
28 | + $database = $this->getDatabase(); |
|
29 | + $user = User::getCurrent($database); |
|
30 | + |
|
31 | + // Dual mode |
|
32 | + if (WebRequest::wasPosted()) { |
|
33 | + $this->validateCSRFToken(); |
|
34 | + $user->setWelcomeSig(WebRequest::postString('sig')); |
|
35 | + $user->setEmailSig(WebRequest::postString('emailsig')); |
|
36 | + $user->setAbortPref(WebRequest::postBoolean('abortpref') ? 1 : 0); |
|
37 | + $this->setCreationMode($user); |
|
38 | + $user->setSkin(WebRequest::postBoolean('skintype') ? 'alt' : 'main'); |
|
39 | + |
|
40 | + $email = WebRequest::postEmail('email'); |
|
41 | + if ($email !== null) { |
|
42 | + $user->setEmail($email); |
|
43 | + } |
|
44 | + |
|
45 | + $user->save(); |
|
46 | + SessionAlert::success("Preferences updated!"); |
|
47 | + |
|
48 | + $this->redirect(''); |
|
49 | + } |
|
50 | + else { |
|
51 | + $this->assignCSRFToken(); |
|
52 | + $this->setTemplate('preferences/prefs.tpl'); |
|
53 | + $this->assign("enforceOAuth", $enforceOAuth); |
|
54 | + |
|
55 | + $this->assign('canManualCreate', |
|
56 | + $this->barrierTest(User::CREATION_MANUAL, $user, 'RequestCreation')); |
|
57 | + $this->assign('canOauthCreate', |
|
58 | + $this->barrierTest(User::CREATION_OAUTH, $user, 'RequestCreation')); |
|
59 | + $this->assign('canBotCreate', |
|
60 | + $this->barrierTest(User::CREATION_BOT, $user, 'RequestCreation')); |
|
61 | + |
|
62 | + $oauth = new OAuthUserHelper($user, $database, $this->getOAuthProtocolHelper(), |
|
63 | + $this->getSiteConfiguration()); |
|
64 | + $this->assign('oauth', $oauth); |
|
65 | + |
|
66 | + $identity = null; |
|
67 | + if ($oauth->isFullyLinked()) { |
|
68 | + $identity = $oauth->getIdentity(); |
|
69 | + } |
|
70 | + |
|
71 | + $this->assign('identity', $identity); |
|
72 | + $this->assign('graceTime', $this->getSiteConfiguration()->getOauthIdentityGraceTime()); |
|
73 | + } |
|
74 | + } |
|
75 | + |
|
76 | + protected function refreshOAuth() |
|
77 | + { |
|
78 | + if (!WebRequest::wasPosted()) { |
|
79 | + $this->redirect('preferences'); |
|
80 | + |
|
81 | + return; |
|
82 | + } |
|
83 | + |
|
84 | + $database = $this->getDatabase(); |
|
85 | + $oauth = new OAuthUserHelper(User::getCurrent($database), $database, $this->getOAuthProtocolHelper(), |
|
86 | + $this->getSiteConfiguration()); |
|
87 | + if ($oauth->isFullyLinked()) { |
|
88 | + $oauth->refreshIdentity(); |
|
89 | + } |
|
90 | + |
|
91 | + $this->redirect('preferences'); |
|
92 | + |
|
93 | + return; |
|
94 | + } |
|
95 | + |
|
96 | + /** |
|
97 | + * @param User $user |
|
98 | + */ |
|
99 | + protected function setCreationMode(User $user) |
|
100 | + { |
|
101 | + // if the user is selecting a creation mode that they are not allowed, do nothing. |
|
102 | + // this has the side effect of allowing them to keep a selected mode that either has been changed for them, |
|
103 | + // or that they have kept from when they previously had certain access. |
|
104 | + $creationMode = WebRequest::postInt('creationmode'); |
|
105 | + if ($this->barrierTest($creationMode, $user, 'RequestCreation')) { |
|
106 | + $user->setCreationMode($creationMode); |
|
107 | + } |
|
108 | + } |
|
109 | 109 | } |
@@ -24,278 +24,278 @@ |
||
24 | 24 | |
25 | 25 | class PageCustomClose extends PageCloseRequest |
26 | 26 | { |
27 | - use RequestData; |
|
28 | - |
|
29 | - protected function main() |
|
30 | - { |
|
31 | - $database = $this->getDatabase(); |
|
32 | - |
|
33 | - $request = $this->getRequest($database); |
|
34 | - $currentUser = User::getCurrent($this->getDatabase()); |
|
35 | - |
|
36 | - if ($request->getStatus() === 'Closed') { |
|
37 | - throw new ApplicationLogicException('Request is already closed'); |
|
38 | - } |
|
39 | - |
|
40 | - // Dual-mode page |
|
41 | - if (WebRequest::wasPosted()) { |
|
42 | - $this->validateCSRFToken(); |
|
43 | - $this->doCustomClose($currentUser, $request, $database); |
|
44 | - |
|
45 | - $this->redirect(); |
|
46 | - } |
|
47 | - else { |
|
48 | - $this->assignCSRFToken(); |
|
49 | - $this->showCustomCloseForm($database, $request); |
|
50 | - } |
|
51 | - } |
|
52 | - |
|
53 | - /** |
|
54 | - * @param $database |
|
55 | - * |
|
56 | - * @return Request |
|
57 | - * @throws ApplicationLogicException |
|
58 | - */ |
|
59 | - protected function getRequest(PdoDatabase $database) |
|
60 | - { |
|
61 | - $requestId = WebRequest::getInt('request'); |
|
62 | - if ($requestId === null) { |
|
63 | - throw new ApplicationLogicException('Request ID not found'); |
|
64 | - } |
|
65 | - |
|
66 | - /** @var Request $request */ |
|
67 | - $request = Request::getById($requestId, $database); |
|
68 | - |
|
69 | - if ($request === false) { |
|
70 | - throw new ApplicationLogicException('Request not found'); |
|
71 | - } |
|
72 | - |
|
73 | - return $request; |
|
74 | - } |
|
75 | - |
|
76 | - /** |
|
77 | - * @param PdoDatabase $database |
|
78 | - * |
|
79 | - * @return EmailTemplate|null |
|
80 | - */ |
|
81 | - protected function getTemplate(PdoDatabase $database) |
|
82 | - { |
|
83 | - $templateId = WebRequest::getInt('template'); |
|
84 | - if ($templateId === null) { |
|
85 | - return null; |
|
86 | - } |
|
87 | - |
|
88 | - /** @var EmailTemplate $template */ |
|
89 | - $template = EmailTemplate::getById($templateId, $database); |
|
90 | - if ($template === false || !$template->getActive()) { |
|
91 | - return null; |
|
92 | - } |
|
93 | - |
|
94 | - return $template; |
|
95 | - } |
|
96 | - |
|
97 | - /** |
|
98 | - * @param $database |
|
99 | - * @param $request |
|
100 | - * |
|
101 | - * @throws Exception |
|
102 | - */ |
|
103 | - protected function showCustomCloseForm(PdoDatabase $database, Request $request) |
|
104 | - { |
|
105 | - $currentUser = User::getCurrent($database); |
|
106 | - $config = $this->getSiteConfiguration(); |
|
107 | - |
|
108 | - $allowedPrivateData = $this->isAllowedPrivateData($request, $currentUser); |
|
109 | - if (!$allowedPrivateData) { |
|
110 | - // we probably shouldn't be showing the user this form if they're not allowed to access private data... |
|
111 | - throw new AccessDeniedException($this->getSecurityManager()); |
|
112 | - } |
|
113 | - |
|
114 | - $template = $this->getTemplate($database); |
|
115 | - |
|
116 | - // Preload data |
|
117 | - $this->assign('defaultAction', ''); |
|
118 | - $this->assign('preloadText', ''); |
|
119 | - $this->assign('preloadTitle', ''); |
|
120 | - |
|
121 | - if ($template !== null) { |
|
122 | - $this->assign('defaultAction', $template->getDefaultAction()); |
|
123 | - $this->assign('preloadText', $template->getText()); |
|
124 | - $this->assign('preloadTitle', $template->getName()); |
|
125 | - } |
|
126 | - |
|
127 | - // Static data |
|
128 | - $this->assign('requeststates', $config->getRequestStates()); |
|
129 | - |
|
130 | - // request data |
|
131 | - $this->assign('requestId', $request->getIp()); |
|
132 | - $this->assign('updateVersion', $request->getUpdateVersion()); |
|
133 | - $this->setupBasicData($request, $config); |
|
134 | - $this->setupReservationDetails($request->getReserved(), $database, $currentUser); |
|
135 | - $this->setupPrivateData($request, $currentUser, $this->getSiteConfiguration(), $database); |
|
136 | - |
|
137 | - // IP location |
|
138 | - $trustedIp = $this->getXffTrustProvider()->getTrustedClientIp($request->getIp(), $request->getForwardedIp()); |
|
139 | - $this->assign('iplocation', $this->getLocationProvider()->getIpLocation($trustedIp)); |
|
140 | - |
|
141 | - // Confirmations |
|
142 | - $this->assign('confirmEmailAlreadySent', $this->checkEmailAlreadySent($request)); |
|
143 | - |
|
144 | - $this->assign('canSkipCcMailingList', $this->barrierTest('skipCcMailingList', $currentUser)); |
|
145 | - |
|
146 | - $this->assign('allowWelcomeSkip', false); |
|
147 | - $this->assign('forceWelcomeSkip', false); |
|
148 | - |
|
149 | - $oauth = new OAuthUserHelper($currentUser, $this->getDatabase(), $this->getOAuthProtocolHelper(), $config); |
|
150 | - |
|
151 | - if ($currentUser->getWelcomeTemplate() != 0) { |
|
152 | - $this->assign('allowWelcomeSkip', true); |
|
153 | - |
|
154 | - if (!$oauth->canWelcome()) { |
|
155 | - $this->assign('forceWelcomeSkip', true); |
|
156 | - } |
|
157 | - } |
|
158 | - |
|
159 | - |
|
160 | - // template |
|
161 | - $this->setTemplate('custom-close.tpl'); |
|
162 | - } |
|
163 | - |
|
164 | - /** |
|
165 | - * @param User $currentUser |
|
166 | - * @param Request $request |
|
167 | - * @param PdoDatabase $database |
|
168 | - * |
|
169 | - * @throws ApplicationLogicException |
|
170 | - */ |
|
171 | - protected function doCustomClose(User $currentUser, Request $request, PdoDatabase $database) |
|
172 | - { |
|
173 | - $messageBody = WebRequest::postString('msgbody'); |
|
174 | - if ($messageBody === null || trim($messageBody) === '') { |
|
175 | - throw new ApplicationLogicException('Message body cannot be blank'); |
|
176 | - } |
|
177 | - |
|
178 | - $ccMailingList = true; |
|
179 | - if ($this->barrierTest('skipCcMailingList', $currentUser)) { |
|
180 | - $ccMailingList = WebRequest::postBoolean('ccMailingList'); |
|
181 | - } |
|
182 | - |
|
183 | - if ($request->getStatus() === 'Closed') { |
|
184 | - throw new ApplicationLogicException('Request is already closed'); |
|
185 | - } |
|
186 | - |
|
187 | - if (!(WebRequest::postBoolean('confirmEmailAlreadySent')) |
|
188 | - ) { |
|
189 | - throw new ApplicationLogicException('Not all confirmations checked'); |
|
190 | - } |
|
191 | - |
|
192 | - $action = WebRequest::postString('action'); |
|
193 | - $availableRequestStates = $this->getSiteConfiguration()->getRequestStates(); |
|
194 | - |
|
195 | - if ($action === EmailTemplate::CREATED || $action === EmailTemplate::NOT_CREATED) { |
|
196 | - // Close request |
|
197 | - $this->closeRequest($request, $database, $action, $messageBody); |
|
198 | - |
|
199 | - $this->processWelcome($action); |
|
200 | - |
|
201 | - // Send the mail after the save, since save can be rolled back |
|
202 | - $this->sendMail($request, $messageBody, $currentUser, $ccMailingList); |
|
203 | - } |
|
204 | - else { |
|
205 | - if (array_key_exists($action, $availableRequestStates)) { |
|
206 | - // Defer to other state |
|
207 | - $this->deferRequest($request, $database, $action, $availableRequestStates, $messageBody); |
|
208 | - |
|
209 | - // Send the mail after the save, since save can be rolled back |
|
210 | - $this->sendMail($request, $messageBody, $currentUser, $ccMailingList); |
|
211 | - } |
|
212 | - else { |
|
213 | - $request->setReserved(null); |
|
214 | - $request->setUpdateVersion(WebRequest::postInt('updateversion')); |
|
215 | - $request->save(); |
|
216 | - |
|
217 | - // Perform the notifications and stuff *after* we've successfully saved, since the save can throw an OLE |
|
218 | - // and be rolled back. |
|
219 | - |
|
220 | - // Send mail |
|
221 | - $this->sendMail($request, $messageBody, $currentUser, $ccMailingList); |
|
222 | - |
|
223 | - Logger::sentMail($database, $request, $messageBody); |
|
224 | - Logger::unreserve($database, $request); |
|
225 | - |
|
226 | - $this->getNotificationHelper()->sentMail($request); |
|
227 | - SessionAlert::success("Sent mail to Request {$request->getId()}"); |
|
228 | - } |
|
229 | - } |
|
230 | - } |
|
231 | - |
|
232 | - /** |
|
233 | - * @param Request $request |
|
234 | - * @param PdoDatabase $database |
|
235 | - * @param string $action |
|
236 | - * @param string $messageBody |
|
237 | - * |
|
238 | - * @throws Exception |
|
239 | - * @throws OptimisticLockFailedException |
|
240 | - */ |
|
241 | - protected function closeRequest(Request $request, PdoDatabase $database, $action, $messageBody) |
|
242 | - { |
|
243 | - $request->setStatus('Closed'); |
|
244 | - $request->setReserved(null); |
|
245 | - $request->setUpdateVersion(WebRequest::postInt('updateversion')); |
|
246 | - $request->save(); |
|
247 | - |
|
248 | - // Perform the notifications and stuff *after* we've successfully saved, since the save can throw an OLE and |
|
249 | - // be rolled back. |
|
250 | - |
|
251 | - if ($action == EmailTemplate::CREATED) { |
|
252 | - $logCloseType = 'custom-y'; |
|
253 | - $notificationCloseType = "Custom, Created"; |
|
254 | - } |
|
255 | - else { |
|
256 | - $logCloseType = 'custom-n'; |
|
257 | - $notificationCloseType = "Custom, Not Created"; |
|
258 | - } |
|
259 | - |
|
260 | - Logger::closeRequest($database, $request, $logCloseType, $messageBody); |
|
261 | - $this->getNotificationHelper()->requestClosed($request, $notificationCloseType); |
|
262 | - |
|
263 | - $requestName = htmlentities($request->getName(), ENT_COMPAT, 'UTF-8'); |
|
264 | - SessionAlert::success("Request {$request->getId()} ({$requestName}) closed as {$notificationCloseType}."); |
|
265 | - } |
|
266 | - |
|
267 | - /** |
|
268 | - * @param Request $request |
|
269 | - * @param PdoDatabase $database |
|
270 | - * @param string $action |
|
271 | - * @param $availableRequestStates |
|
272 | - * @param string $messageBody |
|
273 | - * |
|
274 | - * @throws Exception |
|
275 | - * @throws OptimisticLockFailedException |
|
276 | - */ |
|
277 | - protected function deferRequest( |
|
278 | - Request $request, |
|
279 | - PdoDatabase $database, |
|
280 | - $action, |
|
281 | - $availableRequestStates, |
|
282 | - $messageBody |
|
283 | - ) { |
|
284 | - $request->setStatus($action); |
|
285 | - $request->setReserved(null); |
|
286 | - $request->setUpdateVersion(WebRequest::postInt('updateversion')); |
|
287 | - $request->save(); |
|
288 | - |
|
289 | - // Perform the notifications and stuff *after* we've successfully saved, since the save can throw an OLE |
|
290 | - // and be rolled back. |
|
291 | - |
|
292 | - $deferToLog = $availableRequestStates[$action]['defertolog']; |
|
293 | - Logger::sentMail($database, $request, $messageBody); |
|
294 | - Logger::deferRequest($database, $request, $deferToLog); |
|
295 | - |
|
296 | - $this->getNotificationHelper()->requestDeferredWithMail($request); |
|
297 | - |
|
298 | - $deferTo = $availableRequestStates[$action]['deferto']; |
|
299 | - SessionAlert::success("Request {$request->getId()} deferred to $deferTo, sending an email."); |
|
300 | - } |
|
27 | + use RequestData; |
|
28 | + |
|
29 | + protected function main() |
|
30 | + { |
|
31 | + $database = $this->getDatabase(); |
|
32 | + |
|
33 | + $request = $this->getRequest($database); |
|
34 | + $currentUser = User::getCurrent($this->getDatabase()); |
|
35 | + |
|
36 | + if ($request->getStatus() === 'Closed') { |
|
37 | + throw new ApplicationLogicException('Request is already closed'); |
|
38 | + } |
|
39 | + |
|
40 | + // Dual-mode page |
|
41 | + if (WebRequest::wasPosted()) { |
|
42 | + $this->validateCSRFToken(); |
|
43 | + $this->doCustomClose($currentUser, $request, $database); |
|
44 | + |
|
45 | + $this->redirect(); |
|
46 | + } |
|
47 | + else { |
|
48 | + $this->assignCSRFToken(); |
|
49 | + $this->showCustomCloseForm($database, $request); |
|
50 | + } |
|
51 | + } |
|
52 | + |
|
53 | + /** |
|
54 | + * @param $database |
|
55 | + * |
|
56 | + * @return Request |
|
57 | + * @throws ApplicationLogicException |
|
58 | + */ |
|
59 | + protected function getRequest(PdoDatabase $database) |
|
60 | + { |
|
61 | + $requestId = WebRequest::getInt('request'); |
|
62 | + if ($requestId === null) { |
|
63 | + throw new ApplicationLogicException('Request ID not found'); |
|
64 | + } |
|
65 | + |
|
66 | + /** @var Request $request */ |
|
67 | + $request = Request::getById($requestId, $database); |
|
68 | + |
|
69 | + if ($request === false) { |
|
70 | + throw new ApplicationLogicException('Request not found'); |
|
71 | + } |
|
72 | + |
|
73 | + return $request; |
|
74 | + } |
|
75 | + |
|
76 | + /** |
|
77 | + * @param PdoDatabase $database |
|
78 | + * |
|
79 | + * @return EmailTemplate|null |
|
80 | + */ |
|
81 | + protected function getTemplate(PdoDatabase $database) |
|
82 | + { |
|
83 | + $templateId = WebRequest::getInt('template'); |
|
84 | + if ($templateId === null) { |
|
85 | + return null; |
|
86 | + } |
|
87 | + |
|
88 | + /** @var EmailTemplate $template */ |
|
89 | + $template = EmailTemplate::getById($templateId, $database); |
|
90 | + if ($template === false || !$template->getActive()) { |
|
91 | + return null; |
|
92 | + } |
|
93 | + |
|
94 | + return $template; |
|
95 | + } |
|
96 | + |
|
97 | + /** |
|
98 | + * @param $database |
|
99 | + * @param $request |
|
100 | + * |
|
101 | + * @throws Exception |
|
102 | + */ |
|
103 | + protected function showCustomCloseForm(PdoDatabase $database, Request $request) |
|
104 | + { |
|
105 | + $currentUser = User::getCurrent($database); |
|
106 | + $config = $this->getSiteConfiguration(); |
|
107 | + |
|
108 | + $allowedPrivateData = $this->isAllowedPrivateData($request, $currentUser); |
|
109 | + if (!$allowedPrivateData) { |
|
110 | + // we probably shouldn't be showing the user this form if they're not allowed to access private data... |
|
111 | + throw new AccessDeniedException($this->getSecurityManager()); |
|
112 | + } |
|
113 | + |
|
114 | + $template = $this->getTemplate($database); |
|
115 | + |
|
116 | + // Preload data |
|
117 | + $this->assign('defaultAction', ''); |
|
118 | + $this->assign('preloadText', ''); |
|
119 | + $this->assign('preloadTitle', ''); |
|
120 | + |
|
121 | + if ($template !== null) { |
|
122 | + $this->assign('defaultAction', $template->getDefaultAction()); |
|
123 | + $this->assign('preloadText', $template->getText()); |
|
124 | + $this->assign('preloadTitle', $template->getName()); |
|
125 | + } |
|
126 | + |
|
127 | + // Static data |
|
128 | + $this->assign('requeststates', $config->getRequestStates()); |
|
129 | + |
|
130 | + // request data |
|
131 | + $this->assign('requestId', $request->getIp()); |
|
132 | + $this->assign('updateVersion', $request->getUpdateVersion()); |
|
133 | + $this->setupBasicData($request, $config); |
|
134 | + $this->setupReservationDetails($request->getReserved(), $database, $currentUser); |
|
135 | + $this->setupPrivateData($request, $currentUser, $this->getSiteConfiguration(), $database); |
|
136 | + |
|
137 | + // IP location |
|
138 | + $trustedIp = $this->getXffTrustProvider()->getTrustedClientIp($request->getIp(), $request->getForwardedIp()); |
|
139 | + $this->assign('iplocation', $this->getLocationProvider()->getIpLocation($trustedIp)); |
|
140 | + |
|
141 | + // Confirmations |
|
142 | + $this->assign('confirmEmailAlreadySent', $this->checkEmailAlreadySent($request)); |
|
143 | + |
|
144 | + $this->assign('canSkipCcMailingList', $this->barrierTest('skipCcMailingList', $currentUser)); |
|
145 | + |
|
146 | + $this->assign('allowWelcomeSkip', false); |
|
147 | + $this->assign('forceWelcomeSkip', false); |
|
148 | + |
|
149 | + $oauth = new OAuthUserHelper($currentUser, $this->getDatabase(), $this->getOAuthProtocolHelper(), $config); |
|
150 | + |
|
151 | + if ($currentUser->getWelcomeTemplate() != 0) { |
|
152 | + $this->assign('allowWelcomeSkip', true); |
|
153 | + |
|
154 | + if (!$oauth->canWelcome()) { |
|
155 | + $this->assign('forceWelcomeSkip', true); |
|
156 | + } |
|
157 | + } |
|
158 | + |
|
159 | + |
|
160 | + // template |
|
161 | + $this->setTemplate('custom-close.tpl'); |
|
162 | + } |
|
163 | + |
|
164 | + /** |
|
165 | + * @param User $currentUser |
|
166 | + * @param Request $request |
|
167 | + * @param PdoDatabase $database |
|
168 | + * |
|
169 | + * @throws ApplicationLogicException |
|
170 | + */ |
|
171 | + protected function doCustomClose(User $currentUser, Request $request, PdoDatabase $database) |
|
172 | + { |
|
173 | + $messageBody = WebRequest::postString('msgbody'); |
|
174 | + if ($messageBody === null || trim($messageBody) === '') { |
|
175 | + throw new ApplicationLogicException('Message body cannot be blank'); |
|
176 | + } |
|
177 | + |
|
178 | + $ccMailingList = true; |
|
179 | + if ($this->barrierTest('skipCcMailingList', $currentUser)) { |
|
180 | + $ccMailingList = WebRequest::postBoolean('ccMailingList'); |
|
181 | + } |
|
182 | + |
|
183 | + if ($request->getStatus() === 'Closed') { |
|
184 | + throw new ApplicationLogicException('Request is already closed'); |
|
185 | + } |
|
186 | + |
|
187 | + if (!(WebRequest::postBoolean('confirmEmailAlreadySent')) |
|
188 | + ) { |
|
189 | + throw new ApplicationLogicException('Not all confirmations checked'); |
|
190 | + } |
|
191 | + |
|
192 | + $action = WebRequest::postString('action'); |
|
193 | + $availableRequestStates = $this->getSiteConfiguration()->getRequestStates(); |
|
194 | + |
|
195 | + if ($action === EmailTemplate::CREATED || $action === EmailTemplate::NOT_CREATED) { |
|
196 | + // Close request |
|
197 | + $this->closeRequest($request, $database, $action, $messageBody); |
|
198 | + |
|
199 | + $this->processWelcome($action); |
|
200 | + |
|
201 | + // Send the mail after the save, since save can be rolled back |
|
202 | + $this->sendMail($request, $messageBody, $currentUser, $ccMailingList); |
|
203 | + } |
|
204 | + else { |
|
205 | + if (array_key_exists($action, $availableRequestStates)) { |
|
206 | + // Defer to other state |
|
207 | + $this->deferRequest($request, $database, $action, $availableRequestStates, $messageBody); |
|
208 | + |
|
209 | + // Send the mail after the save, since save can be rolled back |
|
210 | + $this->sendMail($request, $messageBody, $currentUser, $ccMailingList); |
|
211 | + } |
|
212 | + else { |
|
213 | + $request->setReserved(null); |
|
214 | + $request->setUpdateVersion(WebRequest::postInt('updateversion')); |
|
215 | + $request->save(); |
|
216 | + |
|
217 | + // Perform the notifications and stuff *after* we've successfully saved, since the save can throw an OLE |
|
218 | + // and be rolled back. |
|
219 | + |
|
220 | + // Send mail |
|
221 | + $this->sendMail($request, $messageBody, $currentUser, $ccMailingList); |
|
222 | + |
|
223 | + Logger::sentMail($database, $request, $messageBody); |
|
224 | + Logger::unreserve($database, $request); |
|
225 | + |
|
226 | + $this->getNotificationHelper()->sentMail($request); |
|
227 | + SessionAlert::success("Sent mail to Request {$request->getId()}"); |
|
228 | + } |
|
229 | + } |
|
230 | + } |
|
231 | + |
|
232 | + /** |
|
233 | + * @param Request $request |
|
234 | + * @param PdoDatabase $database |
|
235 | + * @param string $action |
|
236 | + * @param string $messageBody |
|
237 | + * |
|
238 | + * @throws Exception |
|
239 | + * @throws OptimisticLockFailedException |
|
240 | + */ |
|
241 | + protected function closeRequest(Request $request, PdoDatabase $database, $action, $messageBody) |
|
242 | + { |
|
243 | + $request->setStatus('Closed'); |
|
244 | + $request->setReserved(null); |
|
245 | + $request->setUpdateVersion(WebRequest::postInt('updateversion')); |
|
246 | + $request->save(); |
|
247 | + |
|
248 | + // Perform the notifications and stuff *after* we've successfully saved, since the save can throw an OLE and |
|
249 | + // be rolled back. |
|
250 | + |
|
251 | + if ($action == EmailTemplate::CREATED) { |
|
252 | + $logCloseType = 'custom-y'; |
|
253 | + $notificationCloseType = "Custom, Created"; |
|
254 | + } |
|
255 | + else { |
|
256 | + $logCloseType = 'custom-n'; |
|
257 | + $notificationCloseType = "Custom, Not Created"; |
|
258 | + } |
|
259 | + |
|
260 | + Logger::closeRequest($database, $request, $logCloseType, $messageBody); |
|
261 | + $this->getNotificationHelper()->requestClosed($request, $notificationCloseType); |
|
262 | + |
|
263 | + $requestName = htmlentities($request->getName(), ENT_COMPAT, 'UTF-8'); |
|
264 | + SessionAlert::success("Request {$request->getId()} ({$requestName}) closed as {$notificationCloseType}."); |
|
265 | + } |
|
266 | + |
|
267 | + /** |
|
268 | + * @param Request $request |
|
269 | + * @param PdoDatabase $database |
|
270 | + * @param string $action |
|
271 | + * @param $availableRequestStates |
|
272 | + * @param string $messageBody |
|
273 | + * |
|
274 | + * @throws Exception |
|
275 | + * @throws OptimisticLockFailedException |
|
276 | + */ |
|
277 | + protected function deferRequest( |
|
278 | + Request $request, |
|
279 | + PdoDatabase $database, |
|
280 | + $action, |
|
281 | + $availableRequestStates, |
|
282 | + $messageBody |
|
283 | + ) { |
|
284 | + $request->setStatus($action); |
|
285 | + $request->setReserved(null); |
|
286 | + $request->setUpdateVersion(WebRequest::postInt('updateversion')); |
|
287 | + $request->save(); |
|
288 | + |
|
289 | + // Perform the notifications and stuff *after* we've successfully saved, since the save can throw an OLE |
|
290 | + // and be rolled back. |
|
291 | + |
|
292 | + $deferToLog = $availableRequestStates[$action]['defertolog']; |
|
293 | + Logger::sentMail($database, $request, $messageBody); |
|
294 | + Logger::deferRequest($database, $request, $deferToLog); |
|
295 | + |
|
296 | + $this->getNotificationHelper()->requestDeferredWithMail($request); |
|
297 | + |
|
298 | + $deferTo = $availableRequestStates[$action]['deferto']; |
|
299 | + SessionAlert::success("Request {$request->getId()} deferred to $deferTo, sending an email."); |
|
300 | + } |
|
301 | 301 | } |
@@ -21,229 +21,229 @@ |
||
21 | 21 | |
22 | 22 | class PageCloseRequest extends RequestActionBase |
23 | 23 | { |
24 | - protected function main() |
|
25 | - { |
|
26 | - $this->processClose(); |
|
27 | - } |
|
28 | - |
|
29 | - /** |
|
30 | - * Main function for this page, when no specific actions are called. |
|
31 | - * @throws ApplicationLogicException |
|
32 | - */ |
|
33 | - final protected function processClose() |
|
34 | - { |
|
35 | - $this->checkPosted(); |
|
36 | - $database = $this->getDatabase(); |
|
37 | - |
|
38 | - $currentUser = User::getCurrent($database); |
|
39 | - $template = $this->getTemplate($database); |
|
40 | - $request = $this->getRequest($database); |
|
41 | - $request->setUpdateVersion(WebRequest::postInt('updateversion')); |
|
42 | - |
|
43 | - if ($request->getStatus() === 'Closed') { |
|
44 | - throw new ApplicationLogicException('Request is already closed'); |
|
45 | - } |
|
46 | - |
|
47 | - if ($this->confirmEmailAlreadySent($request, $template)) { |
|
48 | - return; |
|
49 | - } |
|
50 | - |
|
51 | - if ($this->checkReserveProtect($request, $currentUser)) { |
|
52 | - return; |
|
53 | - } |
|
54 | - |
|
55 | - if ($this->confirmAccountCreated($request, $template)) { |
|
56 | - return; |
|
57 | - } |
|
58 | - |
|
59 | - // I think we're good here... |
|
60 | - $request->setStatus('Closed'); |
|
61 | - $request->setReserved(null); |
|
62 | - |
|
63 | - Logger::closeRequest($database, $request, $template->getId(), null); |
|
64 | - |
|
65 | - $request->save(); |
|
66 | - |
|
67 | - $this->processWelcome($template->getDefaultAction()); |
|
68 | - |
|
69 | - // Perform the notifications and stuff *after* we've successfully saved, since the save can throw an OLE and |
|
70 | - // be rolled back. |
|
71 | - |
|
72 | - $this->getNotificationHelper()->requestClosed($request, $template->getName()); |
|
73 | - $sanitisedTemplateName = htmlentities($template->getName(), ENT_COMPAT, 'UTF-8'); |
|
74 | - SessionAlert::success("Request {$request->getId()} has been closed as {$sanitisedTemplateName}"); |
|
75 | - |
|
76 | - $this->sendMail($request, $template->getText(), $currentUser, false); |
|
77 | - |
|
78 | - $this->redirect(); |
|
79 | - } |
|
80 | - |
|
81 | - /** |
|
82 | - * @param PdoDatabase $database |
|
83 | - * |
|
84 | - * @return EmailTemplate |
|
85 | - * @throws ApplicationLogicException |
|
86 | - */ |
|
87 | - protected function getTemplate(PdoDatabase $database) |
|
88 | - { |
|
89 | - $templateId = WebRequest::postInt('template'); |
|
90 | - if ($templateId === null) { |
|
91 | - throw new ApplicationLogicException('No template specified'); |
|
92 | - } |
|
93 | - |
|
94 | - /** @var EmailTemplate $template */ |
|
95 | - $template = EmailTemplate::getById($templateId, $database); |
|
96 | - if ($template === false || !$template->getActive()) { |
|
97 | - throw new ApplicationLogicException('Invalid or inactive template specified'); |
|
98 | - } |
|
99 | - |
|
100 | - return $template; |
|
101 | - } |
|
102 | - |
|
103 | - /** |
|
104 | - * @param Request $request |
|
105 | - * @param EmailTemplate $template |
|
106 | - * |
|
107 | - * @return bool |
|
108 | - */ |
|
109 | - protected function confirmEmailAlreadySent(Request $request, EmailTemplate $template) |
|
110 | - { |
|
111 | - if ($this->checkEmailAlreadySent($request)) { |
|
112 | - $this->showConfirmation($request, $template, 'close-confirmations/email-sent.tpl'); |
|
113 | - |
|
114 | - return true; |
|
115 | - } |
|
116 | - |
|
117 | - return false; |
|
118 | - } |
|
119 | - |
|
120 | - protected function checkEmailAlreadySent(Request $request) |
|
121 | - { |
|
122 | - if ($request->getEmailSent() && !WebRequest::postBoolean('emailSentOverride')) { |
|
123 | - return true; |
|
124 | - } |
|
125 | - |
|
126 | - return false; |
|
127 | - } |
|
128 | - |
|
129 | - protected function checkReserveProtect(Request $request, User $currentUser) |
|
130 | - { |
|
131 | - $reservationId = $request->getReserved(); |
|
132 | - |
|
133 | - if ($reservationId !== 0 && $reservationId !== null) { |
|
134 | - if ($currentUser->getId() !== $reservationId) { |
|
135 | - SessionAlert::error("Request is reserved by someone else."); |
|
136 | - $this->redirect('/viewRequest', null, ['id' => $request->getId()] ); |
|
137 | - return true; |
|
138 | - } |
|
139 | - } |
|
140 | - |
|
141 | - return false; |
|
142 | - } |
|
143 | - |
|
144 | - /** |
|
145 | - * @param Request $request |
|
146 | - * @param EmailTemplate $template |
|
147 | - * |
|
148 | - * @return bool |
|
149 | - * @throws \Waca\Exceptions\CurlException |
|
150 | - */ |
|
151 | - protected function confirmAccountCreated(Request $request, EmailTemplate $template) |
|
152 | - { |
|
153 | - if ($this->checkAccountCreated($request, $template)) { |
|
154 | - $this->showConfirmation($request, $template, 'close-confirmations/account-created.tpl'); |
|
155 | - |
|
156 | - return true; |
|
157 | - } |
|
158 | - |
|
159 | - return false; |
|
160 | - } |
|
161 | - |
|
162 | - protected function checkAccountCreated(Request $request, EmailTemplate $template) |
|
163 | - { |
|
164 | - if ($template->getDefaultAction() === EmailTemplate::CREATED && !WebRequest::postBoolean('createOverride')) { |
|
165 | - $parameters = array( |
|
166 | - 'action' => 'query', |
|
167 | - 'list' => 'users', |
|
168 | - 'format' => 'php', |
|
169 | - 'ususers' => $request->getName(), |
|
170 | - ); |
|
171 | - |
|
172 | - $content = $this->getHttpHelper()->get($this->getSiteConfiguration()->getMediawikiWebServiceEndpoint(), |
|
173 | - $parameters); |
|
174 | - |
|
175 | - $apiResult = unserialize($content); |
|
176 | - $exists = !isset($apiResult['query']['users']['0']['missing']); |
|
177 | - |
|
178 | - if (!$exists) { |
|
179 | - return true; |
|
180 | - } |
|
181 | - } |
|
182 | - |
|
183 | - return false; |
|
184 | - } |
|
185 | - |
|
186 | - /** |
|
187 | - * @param Request $request |
|
188 | - * @param string $mailText |
|
189 | - * @param User $currentUser |
|
190 | - * @param boolean $ccMailingList |
|
191 | - */ |
|
192 | - protected function sendMail(Request $request, $mailText, User $currentUser, $ccMailingList) |
|
193 | - { |
|
194 | - $requestEmailHelper = new RequestEmailHelper($this->getEmailHelper()); |
|
195 | - $requestEmailHelper->sendMail($request, $mailText, $currentUser, $ccMailingList); |
|
196 | - |
|
197 | - $request->setEmailSent(true); |
|
198 | - $request->save(); |
|
199 | - } |
|
200 | - |
|
201 | - /** |
|
202 | - * @param Request $request |
|
203 | - * @param EmailTemplate $template |
|
204 | - * @param string $templateName |
|
205 | - * |
|
206 | - * @throws Exception |
|
207 | - * @return void |
|
208 | - */ |
|
209 | - protected function showConfirmation(Request $request, EmailTemplate $template, $templateName) |
|
210 | - { |
|
211 | - $this->assignCSRFToken(); |
|
212 | - |
|
213 | - $this->assign('request', $request->getId()); |
|
214 | - $this->assign('template', $template->getId()); |
|
215 | - |
|
216 | - $this->assign('updateversion', $request->getUpdateVersion()); |
|
217 | - |
|
218 | - $this->assign('emailSentOverride', WebRequest::postBoolean('emailSentOverride') ? 'true' : 'false'); |
|
219 | - $this->assign('reserveOverride', WebRequest::postBoolean('reserveOverride') ? 'true' : 'false'); |
|
220 | - $this->assign('createOverride', WebRequest::postBoolean('createOverride') ? 'true' : 'false'); |
|
221 | - |
|
222 | - $this->setTemplate($templateName); |
|
223 | - } |
|
224 | - |
|
225 | - /** |
|
226 | - * @param string $action |
|
227 | - * |
|
228 | - * @throws ApplicationLogicException |
|
229 | - */ |
|
230 | - final protected function processWelcome(string $action): void |
|
231 | - { |
|
232 | - $database = $this->getDatabase(); |
|
233 | - $currentUser = User::getCurrent($database); |
|
234 | - |
|
235 | - if ($action !== EmailTemplate::CREATED) { |
|
236 | - return; |
|
237 | - } |
|
238 | - |
|
239 | - if ($currentUser->getWelcomeTemplate() === null) { |
|
240 | - return; |
|
241 | - } |
|
242 | - |
|
243 | - if (WebRequest::postBoolean('skipAutoWelcome')) { |
|
244 | - return; |
|
245 | - } |
|
246 | - |
|
247 | - $this->enqueueWelcomeTask($this->getRequest($database), null, $currentUser, $database); |
|
248 | - } |
|
24 | + protected function main() |
|
25 | + { |
|
26 | + $this->processClose(); |
|
27 | + } |
|
28 | + |
|
29 | + /** |
|
30 | + * Main function for this page, when no specific actions are called. |
|
31 | + * @throws ApplicationLogicException |
|
32 | + */ |
|
33 | + final protected function processClose() |
|
34 | + { |
|
35 | + $this->checkPosted(); |
|
36 | + $database = $this->getDatabase(); |
|
37 | + |
|
38 | + $currentUser = User::getCurrent($database); |
|
39 | + $template = $this->getTemplate($database); |
|
40 | + $request = $this->getRequest($database); |
|
41 | + $request->setUpdateVersion(WebRequest::postInt('updateversion')); |
|
42 | + |
|
43 | + if ($request->getStatus() === 'Closed') { |
|
44 | + throw new ApplicationLogicException('Request is already closed'); |
|
45 | + } |
|
46 | + |
|
47 | + if ($this->confirmEmailAlreadySent($request, $template)) { |
|
48 | + return; |
|
49 | + } |
|
50 | + |
|
51 | + if ($this->checkReserveProtect($request, $currentUser)) { |
|
52 | + return; |
|
53 | + } |
|
54 | + |
|
55 | + if ($this->confirmAccountCreated($request, $template)) { |
|
56 | + return; |
|
57 | + } |
|
58 | + |
|
59 | + // I think we're good here... |
|
60 | + $request->setStatus('Closed'); |
|
61 | + $request->setReserved(null); |
|
62 | + |
|
63 | + Logger::closeRequest($database, $request, $template->getId(), null); |
|
64 | + |
|
65 | + $request->save(); |
|
66 | + |
|
67 | + $this->processWelcome($template->getDefaultAction()); |
|
68 | + |
|
69 | + // Perform the notifications and stuff *after* we've successfully saved, since the save can throw an OLE and |
|
70 | + // be rolled back. |
|
71 | + |
|
72 | + $this->getNotificationHelper()->requestClosed($request, $template->getName()); |
|
73 | + $sanitisedTemplateName = htmlentities($template->getName(), ENT_COMPAT, 'UTF-8'); |
|
74 | + SessionAlert::success("Request {$request->getId()} has been closed as {$sanitisedTemplateName}"); |
|
75 | + |
|
76 | + $this->sendMail($request, $template->getText(), $currentUser, false); |
|
77 | + |
|
78 | + $this->redirect(); |
|
79 | + } |
|
80 | + |
|
81 | + /** |
|
82 | + * @param PdoDatabase $database |
|
83 | + * |
|
84 | + * @return EmailTemplate |
|
85 | + * @throws ApplicationLogicException |
|
86 | + */ |
|
87 | + protected function getTemplate(PdoDatabase $database) |
|
88 | + { |
|
89 | + $templateId = WebRequest::postInt('template'); |
|
90 | + if ($templateId === null) { |
|
91 | + throw new ApplicationLogicException('No template specified'); |
|
92 | + } |
|
93 | + |
|
94 | + /** @var EmailTemplate $template */ |
|
95 | + $template = EmailTemplate::getById($templateId, $database); |
|
96 | + if ($template === false || !$template->getActive()) { |
|
97 | + throw new ApplicationLogicException('Invalid or inactive template specified'); |
|
98 | + } |
|
99 | + |
|
100 | + return $template; |
|
101 | + } |
|
102 | + |
|
103 | + /** |
|
104 | + * @param Request $request |
|
105 | + * @param EmailTemplate $template |
|
106 | + * |
|
107 | + * @return bool |
|
108 | + */ |
|
109 | + protected function confirmEmailAlreadySent(Request $request, EmailTemplate $template) |
|
110 | + { |
|
111 | + if ($this->checkEmailAlreadySent($request)) { |
|
112 | + $this->showConfirmation($request, $template, 'close-confirmations/email-sent.tpl'); |
|
113 | + |
|
114 | + return true; |
|
115 | + } |
|
116 | + |
|
117 | + return false; |
|
118 | + } |
|
119 | + |
|
120 | + protected function checkEmailAlreadySent(Request $request) |
|
121 | + { |
|
122 | + if ($request->getEmailSent() && !WebRequest::postBoolean('emailSentOverride')) { |
|
123 | + return true; |
|
124 | + } |
|
125 | + |
|
126 | + return false; |
|
127 | + } |
|
128 | + |
|
129 | + protected function checkReserveProtect(Request $request, User $currentUser) |
|
130 | + { |
|
131 | + $reservationId = $request->getReserved(); |
|
132 | + |
|
133 | + if ($reservationId !== 0 && $reservationId !== null) { |
|
134 | + if ($currentUser->getId() !== $reservationId) { |
|
135 | + SessionAlert::error("Request is reserved by someone else."); |
|
136 | + $this->redirect('/viewRequest', null, ['id' => $request->getId()] ); |
|
137 | + return true; |
|
138 | + } |
|
139 | + } |
|
140 | + |
|
141 | + return false; |
|
142 | + } |
|
143 | + |
|
144 | + /** |
|
145 | + * @param Request $request |
|
146 | + * @param EmailTemplate $template |
|
147 | + * |
|
148 | + * @return bool |
|
149 | + * @throws \Waca\Exceptions\CurlException |
|
150 | + */ |
|
151 | + protected function confirmAccountCreated(Request $request, EmailTemplate $template) |
|
152 | + { |
|
153 | + if ($this->checkAccountCreated($request, $template)) { |
|
154 | + $this->showConfirmation($request, $template, 'close-confirmations/account-created.tpl'); |
|
155 | + |
|
156 | + return true; |
|
157 | + } |
|
158 | + |
|
159 | + return false; |
|
160 | + } |
|
161 | + |
|
162 | + protected function checkAccountCreated(Request $request, EmailTemplate $template) |
|
163 | + { |
|
164 | + if ($template->getDefaultAction() === EmailTemplate::CREATED && !WebRequest::postBoolean('createOverride')) { |
|
165 | + $parameters = array( |
|
166 | + 'action' => 'query', |
|
167 | + 'list' => 'users', |
|
168 | + 'format' => 'php', |
|
169 | + 'ususers' => $request->getName(), |
|
170 | + ); |
|
171 | + |
|
172 | + $content = $this->getHttpHelper()->get($this->getSiteConfiguration()->getMediawikiWebServiceEndpoint(), |
|
173 | + $parameters); |
|
174 | + |
|
175 | + $apiResult = unserialize($content); |
|
176 | + $exists = !isset($apiResult['query']['users']['0']['missing']); |
|
177 | + |
|
178 | + if (!$exists) { |
|
179 | + return true; |
|
180 | + } |
|
181 | + } |
|
182 | + |
|
183 | + return false; |
|
184 | + } |
|
185 | + |
|
186 | + /** |
|
187 | + * @param Request $request |
|
188 | + * @param string $mailText |
|
189 | + * @param User $currentUser |
|
190 | + * @param boolean $ccMailingList |
|
191 | + */ |
|
192 | + protected function sendMail(Request $request, $mailText, User $currentUser, $ccMailingList) |
|
193 | + { |
|
194 | + $requestEmailHelper = new RequestEmailHelper($this->getEmailHelper()); |
|
195 | + $requestEmailHelper->sendMail($request, $mailText, $currentUser, $ccMailingList); |
|
196 | + |
|
197 | + $request->setEmailSent(true); |
|
198 | + $request->save(); |
|
199 | + } |
|
200 | + |
|
201 | + /** |
|
202 | + * @param Request $request |
|
203 | + * @param EmailTemplate $template |
|
204 | + * @param string $templateName |
|
205 | + * |
|
206 | + * @throws Exception |
|
207 | + * @return void |
|
208 | + */ |
|
209 | + protected function showConfirmation(Request $request, EmailTemplate $template, $templateName) |
|
210 | + { |
|
211 | + $this->assignCSRFToken(); |
|
212 | + |
|
213 | + $this->assign('request', $request->getId()); |
|
214 | + $this->assign('template', $template->getId()); |
|
215 | + |
|
216 | + $this->assign('updateversion', $request->getUpdateVersion()); |
|
217 | + |
|
218 | + $this->assign('emailSentOverride', WebRequest::postBoolean('emailSentOverride') ? 'true' : 'false'); |
|
219 | + $this->assign('reserveOverride', WebRequest::postBoolean('reserveOverride') ? 'true' : 'false'); |
|
220 | + $this->assign('createOverride', WebRequest::postBoolean('createOverride') ? 'true' : 'false'); |
|
221 | + |
|
222 | + $this->setTemplate($templateName); |
|
223 | + } |
|
224 | + |
|
225 | + /** |
|
226 | + * @param string $action |
|
227 | + * |
|
228 | + * @throws ApplicationLogicException |
|
229 | + */ |
|
230 | + final protected function processWelcome(string $action): void |
|
231 | + { |
|
232 | + $database = $this->getDatabase(); |
|
233 | + $currentUser = User::getCurrent($database); |
|
234 | + |
|
235 | + if ($action !== EmailTemplate::CREATED) { |
|
236 | + return; |
|
237 | + } |
|
238 | + |
|
239 | + if ($currentUser->getWelcomeTemplate() === null) { |
|
240 | + return; |
|
241 | + } |
|
242 | + |
|
243 | + if (WebRequest::postBoolean('skipAutoWelcome')) { |
|
244 | + return; |
|
245 | + } |
|
246 | + |
|
247 | + $this->enqueueWelcomeTask($this->getRequest($database), null, $currentUser, $database); |
|
248 | + } |
|
249 | 249 | } |
@@ -133,7 +133,7 @@ |
||
133 | 133 | if ($reservationId !== 0 && $reservationId !== null) { |
134 | 134 | if ($currentUser->getId() !== $reservationId) { |
135 | 135 | SessionAlert::error("Request is reserved by someone else."); |
136 | - $this->redirect('/viewRequest', null, ['id' => $request->getId()] ); |
|
136 | + $this->redirect('/viewRequest', null, ['id' => $request->getId()]); |
|
137 | 137 | return true; |
138 | 138 | } |
139 | 139 | } |