Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 331 |
|
0.00% |
0 / 10 |
CRAP | |
0.00% |
0 / 1 |
SpecialContact | |
0.00% |
0 / 331 |
|
0.00% |
0 / 10 |
7832 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
getDescription | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getTypeConfig | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
12 | |||
getFormSpecificMessageKey | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
20 | |||
execute | |
0.00% |
0 / 156 |
|
0.00% |
0 / 1 |
1056 | |||
processInput | |
0.00% |
0 / 135 |
|
0.00% |
0 / 1 |
1406 | |||
getYesOrNoMsg | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
6 | |||
useCaptcha | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
30 | |||
getCaptcha | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
2 | |||
getContactPageHookRunner | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 |
1 | <?php |
2 | /** |
3 | * Speclial:Contact, a contact form for visitors. |
4 | * Based on SpecialEmailUser.php |
5 | * |
6 | * @file |
7 | * @ingroup SpecialPage |
8 | * @author Daniel Kinzler, brightbyte.de |
9 | * @copyright © 2007-2014 Daniel Kinzler, Sam Reed |
10 | * @license GPL-2.0-or-later |
11 | */ |
12 | |
13 | namespace MediaWiki\Extension\ContactPage; |
14 | |
15 | use ErrorPageError; |
16 | use ExtensionRegistry; |
17 | use HTMLForm; |
18 | use MailAddress; |
19 | use MediaWiki\Extension\ConfirmEdit\Hooks as ConfirmEditHooks; |
20 | use MediaWiki\Extension\ContactPage\Hooks\HookRunner; |
21 | use MediaWiki\Html\Html; |
22 | use MediaWiki\Parser\Sanitizer; |
23 | use MediaWiki\Session\SessionManager; |
24 | use MediaWiki\SpecialPage\UnlistedSpecialPage; |
25 | use MediaWiki\Status\Status; |
26 | use MediaWiki\User\Options\UserOptionsLookup; |
27 | use MediaWiki\User\User; |
28 | use UserBlockedError; |
29 | use UserMailer; |
30 | |
31 | /** |
32 | * Provides the contact form |
33 | * @ingroup SpecialPage |
34 | */ |
35 | class SpecialContact extends UnlistedSpecialPage { |
36 | /** @var UserOptionsLookup */ |
37 | private $userOptionsLookup; |
38 | /** @var HookRunner|null */ |
39 | private $contactPageHookRunner; |
40 | |
41 | /** |
42 | * @param UserOptionsLookup $userOptionsLookup |
43 | */ |
44 | public function __construct( UserOptionsLookup $userOptionsLookup ) { |
45 | parent::__construct( 'Contact' ); |
46 | $this->userOptionsLookup = $userOptionsLookup; |
47 | } |
48 | |
49 | /** |
50 | * @inheritDoc |
51 | */ |
52 | public function getDescription() { |
53 | return $this->msg( 'contactpage' ); |
54 | } |
55 | |
56 | /** |
57 | * @var string |
58 | */ |
59 | protected $formType; |
60 | |
61 | /** |
62 | * @return array |
63 | */ |
64 | protected function getTypeConfig() { |
65 | $contactConfig = $this->getConfig()->get( 'ContactConfig' ); |
66 | |
67 | if ( $contactConfig['default']['SenderName'] === null ) { |
68 | $sitename = $this->getConfig()->get( 'Sitename' ); |
69 | $contactConfig['default']['SenderName'] = "Contact Form on $sitename"; |
70 | } |
71 | |
72 | if ( isset( $contactConfig[$this->formType] ) ) { |
73 | return $contactConfig[$this->formType] + $contactConfig['default']; |
74 | } |
75 | return $contactConfig['default']; |
76 | } |
77 | |
78 | /** |
79 | * Helper function for ::execute that returns a form |
80 | * specific message key if it is is not disabled. |
81 | * Otherwise returns the generic message key. |
82 | * Used to make it possible for forms to have |
83 | * form-specific messages. |
84 | * |
85 | * @param string $genericMessageKey The message key that will be used if no form-specific one can be used |
86 | * @return string |
87 | */ |
88 | protected function getFormSpecificMessageKey( string $genericMessageKey ) { |
89 | $formSpecificMessageKey = $genericMessageKey . '-' . $this->formType; |
90 | if ( !str_starts_with( $genericMessageKey, 'contactpage' ) ) { |
91 | // If the generic message does not start with "contactpage" the form |
92 | // specific one will have "contactpage-" prefixed on the generic message |
93 | // name. |
94 | $formSpecificMessageKey = 'contactpage-' . $formSpecificMessageKey; |
95 | } |
96 | if ( $this->formType && !$this->msg( $formSpecificMessageKey )->isDisabled() ) { |
97 | // Return the form-specific message if the form type is not the empty string |
98 | // and the message is defined. |
99 | return $formSpecificMessageKey; |
100 | } |
101 | return $genericMessageKey; |
102 | } |
103 | |
104 | /** |
105 | * Main execution function |
106 | * |
107 | * @param string|null $par Parameters passed to the page |
108 | * @throws UserBlockedError |
109 | * @throws ErrorPageError |
110 | */ |
111 | public function execute( $par ) { |
112 | if ( !$this->getConfig()->get( 'EnableEmail' ) ) { |
113 | // From Special:EmailUser |
114 | throw new ErrorPageError( 'usermaildisabled', 'usermaildisabledtext' ); |
115 | } |
116 | |
117 | $request = $this->getRequest(); |
118 | $this->formType = strtolower( $request->getText( 'formtype', $par ?? '' ) ); |
119 | |
120 | $config = $this->getTypeConfig(); |
121 | $user = $this->getUser(); |
122 | |
123 | // Display error if user not logged in when config requires it |
124 | $requiresConfirmedEmail = $config['MustHaveEmail'] ?? false; |
125 | $requiresLogin = $config['MustBeLoggedIn'] ?? false; |
126 | if ( $requiresLogin ) { |
127 | $this->requireNamedUser( 'contactpage-mustbeloggedin' ); |
128 | } elseif ( $requiresConfirmedEmail ) { |
129 | // MustHaveEmail must not be set without setting MustBeLoggedIn, as |
130 | // anon and temporary users do not have email addresses. |
131 | $this->getOutput()->showErrorPage( 'contactpage-config-error-title', |
132 | 'contactpage-config-error' ); |
133 | return; |
134 | } |
135 | |
136 | // Display error if sender has no confirmed email when config requires it |
137 | if ( $requiresConfirmedEmail && !$user->isEmailConfirmed() ) { |
138 | $this->getOutput()->showErrorPage( |
139 | 'contactpage-musthaveemail-error-title', |
140 | 'contactpage-musthaveemail-error' |
141 | ); |
142 | return; |
143 | } |
144 | |
145 | // Display error if no recipient user specified in configuration |
146 | if ( !$config['RecipientUser'] ) { |
147 | $this->getOutput()->showErrorPage( 'contactpage-config-error-title', |
148 | 'contactpage-config-error' ); |
149 | return; |
150 | } |
151 | |
152 | // Display error if recipient has email disabled |
153 | $recipient = User::newFromName( $config['RecipientUser'] ); |
154 | if ( $recipient === null || !$recipient->canReceiveEmail() ) { |
155 | $this->getOutput()->showErrorPage( 'noemailtitle', 'noemailtext' ); |
156 | return; |
157 | } |
158 | |
159 | // Blocked users cannot use the contact form if they're disabled from sending email. |
160 | $block = $user->getBlock(); |
161 | if ( $block && $block->appliesToRight( 'sendemail' ) ) { |
162 | $useCustomBlockMessage = $config['UseCustomBlockMessage'] ?? false; |
163 | if ( $useCustomBlockMessage ) { |
164 | $this->getOutput()->showErrorPage( $this->getFormSpecificMessageKey( 'contactpage-title' ), |
165 | $this->getFormSpecificMessageKey( 'contactpage-blocked-message' ) ); |
166 | return; |
167 | } |
168 | |
169 | throw new UserBlockedError( $block ); |
170 | } |
171 | |
172 | $this->getOutput()->setPageTitleMsg( |
173 | $this->msg( $this->getFormSpecificMessageKey( 'contactpage-title' ) ) |
174 | ); |
175 | |
176 | # Check for type in [[Special:Contact/type]]: change pagetext and prefill form fields |
177 | $formText = $this->msg( |
178 | $this->getFormSpecificMessageKey( 'contactpage-pagetext' ) |
179 | )->parseAsBlock(); |
180 | $formSpecificSubjectMessageKey = $this->msg( [ |
181 | 'contactpage-defsubject-' . $this->formType, |
182 | 'contactpage-subject-' . $this->formType |
183 | ] ); |
184 | if ( $this->formType != '' && !$formSpecificSubjectMessageKey->isDisabled() ) { |
185 | $subject = trim( $formSpecificSubjectMessageKey->inContentLanguage()->plain() ); |
186 | } else { |
187 | $subject = $this->msg( 'contactpage-defsubject' )->inContentLanguage()->text(); |
188 | } |
189 | |
190 | $fromAddress = ''; |
191 | $fromName = ''; |
192 | $nameReadonly = false; |
193 | $emailReadonly = false; |
194 | $subjectReadonly = $config['SubjectReadonly'] ?? false; |
195 | if ( $user->isNamed() ) { |
196 | // Use real name if set |
197 | $realName = $user->getRealName(); |
198 | if ( $realName ) { |
199 | $fromName = $realName; |
200 | } else { |
201 | $fromName = $user->getName(); |
202 | } |
203 | $fromAddress = $user->getEmail(); |
204 | $nameReadonly = $config['NameReadonly'] ?? false; |
205 | $emailReadonly = $config['EmailReadonly'] ?? false; |
206 | } |
207 | |
208 | // Show error if the following are true as they are in combination invalid configuration: |
209 | // * The form doesn't require logging in |
210 | // * The form requires details |
211 | // * The email form is read only. |
212 | // This is because the email field will be empty for anon and temp users and must be filled |
213 | // for the form to be valid, but cannot be modified by the client. |
214 | if ( !$requiresLogin && $emailReadonly && $config['RequireDetails'] ) { |
215 | $this->getOutput()->showErrorPage( 'contactpage-config-error-title', |
216 | 'contactpage-config-error' ); |
217 | return; |
218 | } |
219 | |
220 | $additional = $config['AdditionalFields'] ?? []; |
221 | |
222 | $formItems = [ |
223 | 'FromName' => [ |
224 | 'label-message' => $this->getFormSpecificMessageKey( 'contactpage-fromname' ), |
225 | 'type' => 'text', |
226 | 'required' => $config['RequireDetails'], |
227 | 'default' => $fromName, |
228 | 'disabled' => $nameReadonly, |
229 | ], |
230 | 'FromAddress' => [ |
231 | 'label-message' => $this->getFormSpecificMessageKey( 'contactpage-fromaddress' ), |
232 | 'type' => 'email', |
233 | 'required' => $config['RequireDetails'], |
234 | 'default' => $fromAddress, |
235 | 'disabled' => $emailReadonly, |
236 | ] |
237 | ]; |
238 | |
239 | if ( !$config['RequireDetails'] ) { |
240 | $formItems['FromInfo'] = [ |
241 | 'label' => '', |
242 | 'type' => 'info', |
243 | 'default' => Html::rawElement( 'small', [], |
244 | $this->msg( |
245 | $this->getFormSpecificMessageKey( 'contactpage-formfootnotes' ) |
246 | )->escaped() |
247 | ), |
248 | 'raw' => true, |
249 | ]; |
250 | } |
251 | |
252 | $formItems += [ |
253 | 'Subject' => [ |
254 | 'label-message' => $this->getFormSpecificMessageKey( 'emailsubject' ), |
255 | 'type' => 'text', |
256 | 'default' => $subject, |
257 | 'disabled' => $subjectReadonly, |
258 | ], |
259 | ] + $additional + [ |
260 | 'CCme' => [ |
261 | 'label-message' => $this->getFormSpecificMessageKey( 'emailccme' ), |
262 | 'type' => 'check', |
263 | 'default' => $this->userOptionsLookup->getBoolOption( $this->getUser(), 'ccmeonemails' ), |
264 | ], |
265 | 'FormType' => [ |
266 | 'class' => 'HTMLHiddenField', |
267 | 'label' => 'Type', |
268 | 'default' => $this->formType, |
269 | ] |
270 | ]; |
271 | |
272 | if ( $config['IncludeIP'] && $user->isRegistered() ) { |
273 | $formItems['IncludeIP'] = [ |
274 | 'label-message' => $this->getFormSpecificMessageKey( 'contactpage-includeip' ), |
275 | 'type' => 'check', |
276 | ]; |
277 | } |
278 | |
279 | if ( $this->useCaptcha() ) { |
280 | $formItems['Captcha'] = [ |
281 | 'label-message' => 'captcha-label', |
282 | 'type' => 'info', |
283 | 'default' => $this->getCaptcha(), |
284 | 'raw' => true, |
285 | ]; |
286 | } |
287 | |
288 | $form = HTMLForm::factory( 'ooui', |
289 | $formItems, $this->getContext(), "contactpage-{$this->formType}" |
290 | ); |
291 | $form->setWrapperLegendMsg( 'contactpage-legend' ); |
292 | $form->setSubmitTextMsg( $this->getFormSpecificMessageKey( 'emailsend' ) ); |
293 | if ( $this->formType != '' ) { |
294 | $form->setId( "contactpage-{$this->formType}" ); |
295 | |
296 | $msg = $this->msg( "contactpage-legend-{$this->formType}" ); |
297 | if ( !$msg->isDisabled() ) { |
298 | $form->setWrapperLegendMsg( $msg ); |
299 | } |
300 | |
301 | $msg = $this->msg( "contactpage-emailsend-{$this->formType}" ); |
302 | if ( !$msg->isDisabled() ) { |
303 | $form->setSubmitTextMsg( $msg ); |
304 | } |
305 | } |
306 | $form->setSubmitCallback( [ $this, 'processInput' ] ); |
307 | $form->loadData(); |
308 | |
309 | // Stolen from Special:EmailUser |
310 | if ( !$this->getContactPageHookRunner()->onEmailUserForm( $form ) ) { |
311 | return; |
312 | } |
313 | |
314 | $result = $form->show(); |
315 | |
316 | if ( $result === true || ( $result instanceof Status && $result->isGood() ) ) { |
317 | $output = $this->getOutput(); |
318 | $output->setPageTitleMsg( $this->msg( $this->getFormSpecificMessageKey( 'emailsent' ) ) ); |
319 | $output->addWikiMsg( |
320 | $this->getFormSpecificMessageKey( 'emailsenttext' ), |
321 | $recipient |
322 | ); |
323 | |
324 | $output->returnToMain( false ); |
325 | } else { |
326 | if ( $config['RLStyleModules'] ) { |
327 | $this->getOutput()->addModuleStyles( $config['RLStyleModules'] ); |
328 | } |
329 | if ( $config['RLModules'] ) { |
330 | $this->getOutput()->addModules( $config['RLModules'] ); |
331 | } |
332 | $this->getOutput()->prependHTML( trim( $formText ) ); |
333 | } |
334 | } |
335 | |
336 | /** |
337 | * @param array $formData |
338 | * @return bool|string|array|Status |
339 | * - Bool true or a good Status object indicates success, |
340 | * - Bool false indicates no submission was attempted, |
341 | * - Anything else indicates failure. The value may be a fatal Status |
342 | * object, an HTML string, or an array of arrays (message keys and |
343 | * params) or strings (message keys) |
344 | */ |
345 | public function processInput( $formData ) { |
346 | $config = $this->getTypeConfig(); |
347 | |
348 | $request = $this->getRequest(); |
349 | $user = $this->getUser(); |
350 | |
351 | if ( $this->useCaptcha() && |
352 | !$this->getConfig()->get( 'Captcha' )->passCaptchaFromRequest( $request, $user ) |
353 | ) { |
354 | return [ 'contactpage-captcha-error' ]; |
355 | } |
356 | |
357 | $senderIP = $request->getIP(); |
358 | |
359 | // Setup user that is going to receive the contact page response |
360 | $contactRecipientUser = User::newFromName( $config['RecipientUser'] ); |
361 | $contactRecipientAddress = MailAddress::newFromUser( $contactRecipientUser ); |
362 | |
363 | // Used when user hasn't set an email, when $wgUserEmailUseReplyTo is true, |
364 | // or when sending CC email to user |
365 | $siteAddress = new MailAddress( |
366 | $config['SenderEmail'] ?: $this->getConfig()->get( 'PasswordSender' ), |
367 | $config['SenderName'] |
368 | ); |
369 | |
370 | // Initialize the sender to the site address |
371 | $senderAddress = $siteAddress; |
372 | |
373 | $fromAddress = $formData['FromAddress']; |
374 | $fromName = $formData['FromName']; |
375 | |
376 | $fromUserAddress = null; |
377 | $replyTo = null; |
378 | |
379 | if ( $fromAddress ) { |
380 | // T232199 - If the email address is invalid, bail out. |
381 | // Don't allow it to fallback to basically @server.host.name |
382 | if ( !Sanitizer::validateEmail( $fromAddress ) ) { |
383 | return [ 'invalidemailaddress' ]; |
384 | } |
385 | |
386 | // Use user submitted details |
387 | $fromUserAddress = new MailAddress( $fromAddress, $fromName ); |
388 | |
389 | if ( $this->getConfig()->get( 'UserEmailUseReplyTo' ) ) { |
390 | // Define reply-to address |
391 | $replyTo = $fromUserAddress; |
392 | } else { |
393 | // Not using ReplyTo, so set the sender to $fromUserAddress |
394 | $senderAddress = $fromUserAddress; |
395 | } |
396 | } |
397 | |
398 | $includeIP = isset( $config['IncludeIP'] ) && $config['IncludeIP'] |
399 | && ( $user->isAnon() || $formData['IncludeIP'] ); |
400 | $subject = $formData['Subject']; |
401 | |
402 | if ( $fromName !== '' ) { |
403 | if ( $includeIP ) { |
404 | $subject = $this->msg( |
405 | 'contactpage-subject-and-sender-withip', |
406 | $subject, |
407 | $fromName, |
408 | $senderIP |
409 | )->inContentLanguage()->text(); |
410 | } else { |
411 | $subject = $this->msg( |
412 | 'contactpage-subject-and-sender', |
413 | $subject, |
414 | $fromName |
415 | )->inContentLanguage()->text(); |
416 | } |
417 | } elseif ( $fromAddress !== '' ) { |
418 | if ( $includeIP ) { |
419 | $subject = $this->msg( |
420 | 'contactpage-subject-and-sender-withip', |
421 | $subject, |
422 | $fromAddress, |
423 | $senderIP |
424 | )->inContentLanguage()->text(); |
425 | } else { |
426 | $subject = $this->msg( |
427 | 'contactpage-subject-and-sender', |
428 | $subject, |
429 | $fromAddress |
430 | )->inContentLanguage()->text(); |
431 | } |
432 | } elseif ( $includeIP ) { |
433 | $subject = $this->msg( |
434 | 'contactpage-subject-and-sender', |
435 | $subject, |
436 | $senderIP |
437 | )->inContentLanguage()->text(); |
438 | } |
439 | |
440 | $text = ''; |
441 | foreach ( $config['AdditionalFields'] as $name => $field ) { |
442 | $class = HTMLForm::getClassFromDescriptor( $name, $field ); |
443 | |
444 | $value = ''; |
445 | // TODO: Support selectandother/HTMLSelectAndOtherField |
446 | // options, options-messages and options-message |
447 | if ( isset( $field['options-messages'] ) ) { |
448 | // Multiple values! |
449 | if ( is_string( $formData[$name] ) ) { |
450 | $optionValues = array_flip( $field['options-messages'] ); |
451 | if ( isset( $optionValues[$formData[$name]] ) ) { |
452 | $value = $this->msg( $optionValues[$formData[$name]] )->inContentLanguage()->text(); |
453 | } else { |
454 | $value = $formData[$name]; |
455 | } |
456 | } elseif ( count( $formData[$name] ) ) { |
457 | $formValues = array_flip( $formData[$name] ); |
458 | $value .= "\n"; |
459 | foreach ( $field['options-messages'] as $msg => $optionValue ) { |
460 | $msg = $this->msg( $msg )->inContentLanguage()->text(); |
461 | $optionValue = $this->getYesOrNoMsg( isset( $formValues[$optionValue] ) ); |
462 | $value .= "\t$msg: $optionValue\n"; |
463 | } |
464 | } |
465 | } elseif ( isset( $field['options'] ) ) { |
466 | if ( is_string( $formData[$name] ) ) { |
467 | $value = $formData[$name]; |
468 | } elseif ( count( $formData[$name] ) ) { |
469 | $formValues = array_flip( $formData[$name] ); |
470 | $value .= "\n"; |
471 | foreach ( $field['options'] as $msg => $optionValue ) { |
472 | $optionValue = $this->getYesOrNoMsg( isset( $formValues[$optionValue] ) ); |
473 | $value .= "\t$msg: $optionValue\n"; |
474 | } |
475 | } |
476 | } elseif ( $class === 'HTMLCheckField' ) { |
477 | $value = $this->getYesOrNoMsg( $formData[$name] xor |
478 | ( isset( $field['invert'] ) && $field['invert'] ) ); |
479 | } elseif ( isset( $formData[$name] ) ) { |
480 | // HTMLTextField, HTMLTextAreaField |
481 | // HTMLFloatField, HTMLIntField |
482 | |
483 | // Just dump the value if its wordy |
484 | $value = $formData[$name]; |
485 | } else { |
486 | continue; |
487 | } |
488 | |
489 | if ( isset( $field['contactpage-email-label'] ) ) { |
490 | $name = $field['contactpage-email-label']; |
491 | } elseif ( isset( $field['label-message'] ) ) { |
492 | $name = $this->msg( $field['label-message'] )->inContentLanguage()->text(); |
493 | } else { |
494 | $name = $field['label']; |
495 | } |
496 | |
497 | $text .= "{$name}: $value\n"; |
498 | } |
499 | |
500 | $hookRunner = $this->getContactPageHookRunner(); |
501 | if ( !$hookRunner->onContactForm( $contactRecipientAddress, $replyTo, $subject, |
502 | $text, $this->formType, $formData ) |
503 | ) { |
504 | // TODO: Need to do some proper error handling here |
505 | return false; |
506 | } |
507 | |
508 | wfDebug( __METHOD__ . ': sending mail from ' . $senderAddress->toString() . |
509 | ' to ' . $contactRecipientAddress->toString() . |
510 | ' replyto ' . ( $replyTo == null ? '-/-' : $replyTo->toString() ) . "\n" |
511 | ); |
512 | // @phan-suppress-next-line SecurityCheck-XSS UserMailer::send defaults to text/plain if passed a string |
513 | $mailResult = UserMailer::send( |
514 | $contactRecipientAddress, |
515 | $senderAddress, |
516 | $subject, |
517 | $text, |
518 | [ 'replyTo' => $replyTo ] |
519 | ); |
520 | |
521 | $language = $this->getLanguage(); |
522 | if ( !$mailResult->isOK() ) { |
523 | wfDebug( __METHOD__ . ': got error from UserMailer: ' . |
524 | $mailResult->getMessage( false, false, 'en' )->text() . "\n" ); |
525 | return [ $mailResult->getMessage( 'contactpage-usermailererror', false, $language ) ]; |
526 | } |
527 | |
528 | // if the user requested a copy of this mail, do this now, |
529 | // unless they are emailing themselves, in which case one copy of the message is sufficient. |
530 | if ( $formData['CCme'] && $fromUserAddress ) { |
531 | $cc_subject = $this->msg( 'emailccsubject', $contactRecipientUser->getName(), $subject )->text(); |
532 | if ( $hookRunner->onContactForm( |
533 | $fromUserAddress, $senderAddress, $cc_subject, $text, $this->formType, $formData ) |
534 | ) { |
535 | wfDebug( __METHOD__ . ': sending cc mail from ' . $senderAddress->toString() . |
536 | ' to ' . $fromUserAddress->toString() . "\n" |
537 | ); |
538 | // @phan-suppress-next-line SecurityCheck-XSS UserMailer::send defaults to text/plain if passed a string |
539 | $ccResult = UserMailer::send( |
540 | $fromUserAddress, |
541 | $senderAddress, |
542 | $cc_subject, |
543 | $text, |
544 | ); |
545 | if ( !$ccResult->isOK() ) { |
546 | // At this stage, the user's CC mail has failed, but their |
547 | // original mail has succeeded. It's unlikely, but still, what to do? |
548 | // We can either show them an error, or we can say everything was fine, |
549 | // or we can say we sort of failed AND sort of succeeded. Of these options, |
550 | // simply saying there was an error is probably best. |
551 | return [ $ccResult->getMessage( 'contactpage-usermailererror', false, $language ) ]; |
552 | } |
553 | } |
554 | } |
555 | |
556 | $hookRunner->onContactFromComplete( $contactRecipientAddress, $replyTo, $subject, $text ); |
557 | |
558 | return true; |
559 | } |
560 | |
561 | /** |
562 | * @param bool $value |
563 | * @return string |
564 | */ |
565 | private function getYesOrNoMsg( $value ) { |
566 | return $this->msg( $value ? 'htmlform-yes' : 'htmlform-no' )->inContentLanguage()->text(); |
567 | } |
568 | |
569 | /** |
570 | * @return bool True if CAPTCHA should be used, false otherwise |
571 | */ |
572 | private function useCaptcha() { |
573 | $extRegistry = ExtensionRegistry::getInstance(); |
574 | if ( !$extRegistry->isLoaded( 'ConfirmEdit' ) ) { |
575 | return false; |
576 | } |
577 | $config = $this->getConfig(); |
578 | $captchaTriggers = $config->get( 'CaptchaTriggers' ); |
579 | |
580 | return $config->get( 'CaptchaClass' ) |
581 | && isset( $captchaTriggers['contactpage'] ) |
582 | && $captchaTriggers['contactpage'] |
583 | && !$this->getUser()->isAllowed( 'skipcaptcha' ); |
584 | } |
585 | |
586 | /** |
587 | * @return string CAPTCHA form HTML |
588 | */ |
589 | private function getCaptcha() { |
590 | // NOTE: make sure we have a session. May be required for CAPTCHAs to work. |
591 | SessionManager::getGlobalSession()->persist(); |
592 | |
593 | $captcha = ConfirmEditHooks::getInstance(); |
594 | $captcha->setTrigger( 'contactpage' ); |
595 | $captcha->setAction( 'contact' ); |
596 | |
597 | $formInformation = $captcha->getFormInformation(); |
598 | $formMetainfo = $formInformation; |
599 | unset( $formMetainfo['html'] ); |
600 | $captcha->addFormInformationToOutput( $this->getOutput(), $formMetainfo ); |
601 | |
602 | return '<div class="captcha">' . |
603 | $formInformation['html'] . |
604 | "</div>\n"; |
605 | } |
606 | |
607 | /** |
608 | * @return HookRunner |
609 | */ |
610 | private function getContactPageHookRunner() { |
611 | if ( !$this->contactPageHookRunner ) { |
612 | $this->contactPageHookRunner = new HookRunner( $this->getHookContainer() ); |
613 | } |
614 | return $this->contactPageHookRunner; |
615 | } |
616 | } |