MediaWiki  master
SpecialConfirmEmail.php
Go to the documentation of this file.
1 <?php
26 use Wikimedia\ScopedCallback;
27 
37 
39  private $userFactory;
40 
44  public function __construct( UserFactory $userFactory ) {
45  parent::__construct( 'Confirmemail', 'editmyprivateinfo' );
46 
47  $this->userFactory = $userFactory;
48  }
49 
50  public function doesWrites() {
51  return true;
52  }
53 
62  public function execute( $code ) {
63  // Ignore things like primary queries/connections on GET requests.
64  // It's very convenient to just allow formless link usage.
65  $trxProfiler = Profiler::instance()->getTransactionProfiler();
66 
67  $this->setHeaders();
68  $this->checkReadOnly();
69  $this->checkPermissions();
70 
71  // This could also let someone check the current email address, so
72  // require both permissions.
73  if ( !$this->getAuthority()->isAllowed( 'viewmyprivateinfo' ) ) {
74  throw new PermissionsError( 'viewmyprivateinfo' );
75  }
76 
77  if ( $code === null || $code === '' ) {
78  $this->requireLogin( 'confirmemail_needlogin' );
79  if ( Sanitizer::validateEmail( $this->getUser()->getEmail() ) ) {
80  $this->showRequestForm();
81  } else {
82  $this->getOutput()->addWikiMsg( 'confirmemail_noemail' );
83  }
84  } else {
85  $scope = $trxProfiler->silenceForScope( $trxProfiler::EXPECTATION_REPLICAS_ONLY );
86  $this->attemptConfirm( $code );
87  ScopedCallback::consume( $scope );
88  }
89  }
90 
94  private function showRequestForm() {
95  $user = $this->getUser();
96  $out = $this->getOutput();
97 
98  if ( !$user->isEmailConfirmed() ) {
99  $descriptor = [];
100  if ( $user->isEmailConfirmationPending() ) {
101  $descriptor += [
102  'pending' => [
103  'type' => 'info',
104  'raw' => true,
105  'default' => "<div class=\"error mw-confirmemail-pending\">\n" .
106  $this->msg( 'confirmemail_pending' )->escaped() .
107  "\n</div>",
108  ],
109  ];
110  }
111 
112  $out->addWikiMsg( 'confirmemail_text' );
113  $form = HTMLForm::factory( 'ooui', $descriptor, $this->getContext() );
114  $form
115  ->setAction( $this->getPageTitle()->getLocalURL() )
116  ->setSubmitTextMsg( 'confirmemail_send' )
117  ->setSubmitCallback( [ $this, 'submitSend' ] );
118 
119  $retval = $form->show();
120 
121  if ( $retval === true ) {
122  // should never happen, but if so, don't let the user without any message
123  $out->addWikiMsg( 'confirmemail_sent' );
124  } elseif ( $retval instanceof Status && $retval->isGood() ) {
125  $out->addWikiTextAsInterface( $retval->getValue() );
126  }
127  } else {
128  // date and time are separate parameters to facilitate localisation.
129  // $time is kept for backward compat reasons.
130  // 'emailauthenticated' is also used in SpecialPreferences.php
131  $lang = $this->getLanguage();
132  $emailAuthenticated = $user->getEmailAuthenticationTimestamp();
133  $time = $lang->userTimeAndDate( $emailAuthenticated, $user );
134  $d = $lang->userDate( $emailAuthenticated, $user );
135  $t = $lang->userTime( $emailAuthenticated, $user );
136  $out->addWikiMsg( 'emailauthenticated', $time, $d, $t );
137  }
138  }
139 
145  public function submitSend() {
146  $status = $this->getUser()->sendConfirmationMail();
147  if ( $status->isGood() ) {
148  return Status::newGood( $this->msg( 'confirmemail_sent' )->text() );
149  } else {
150  return Status::newFatal( new RawMessage(
151  $status->getWikiText( 'confirmemail_sendfailed', false, $this->getLanguage() )
152  ) );
153  }
154  }
155 
162  private function attemptConfirm( $code ) {
163  $user = $this->userFactory->newFromConfirmationCode(
164  $code,
165  UserFactory::READ_LATEST
166  );
167 
168  if ( !is_object( $user ) ) {
169  $this->getOutput()->addWikiMsg( 'confirmemail_invalid' );
170 
171  return;
172  }
173 
174  // rate limit email confirmations
175  if ( $user->pingLimiter( 'confirmemail' ) ) {
176  $this->getOutput()->addWikiMsg( 'actionthrottledtext' );
177 
178  return;
179  }
180 
181  $userLatest = $user->getInstanceForUpdate();
182  $userLatest->confirmEmail();
183  $userLatest->saveSettings();
184  $message = $this->getUser()->isRegistered() ? 'confirmemail_loggedin' : 'confirmemail_success';
185  $this->getOutput()->addWikiMsg( $message );
186 
187  if ( !$this->getUser()->isRegistered() ) {
188  $title = SpecialPage::getTitleFor( 'Userlogin' );
189  $this->getOutput()->returnToMain( true, $title );
190  }
191  }
192 }
static factory( $displayFormat, $descriptor, IContextSource $context, $messagePrefix='')
Construct a HTMLForm object for given display type.
Definition: HTMLForm.php:352
Variant of the Message class.
Definition: RawMessage.php:40
Creates User objects.
Definition: UserFactory.php:38
Show an error when a user tries to do something they do not have the necessary permissions for.
static instance()
Singleton.
Definition: Profiler.php:108
static validateEmail( $addr)
Does a string look like an e-mail address?
Definition: Sanitizer.php:1893
Special page allows users to request email confirmation message, and handles processing of the confir...
doesWrites()
Indicates whether this special page may perform database writes.
execute( $code)
Main execution point.
__construct(UserFactory $userFactory)
submitSend()
Callback for HTMLForm send confirmation mail.
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
getOutput()
Get the OutputPage being used for this instance.
requireLogin( $reasonMsg='exception-nologin-text', $titleMsg='exception-nologin')
If the user is not logged in, throws UserNotLoggedIn error.
getUser()
Shortcut to get the User executing this instance.
checkPermissions()
Checks if userCanExecute, and if not throws a PermissionsError.
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...
getContext()
Gets the context this SpecialPage is executed in.
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getAuthority()
Shortcut to get the Authority executing this instance.
checkReadOnly()
If the wiki is currently in readonly mode, throws a ReadOnlyError.
getPageTitle( $subpage=false)
Get a self-referential title object.
getLanguage()
Shortcut to get user's language.
static newFatal( $message,... $parameters)
Factory function for fatal errors.
Definition: StatusValue.php:73
isGood()
Returns whether the operation completed and didn't have any error or warnings.
static newGood( $value=null)
Factory function for good results.
Definition: StatusValue.php:85
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition: Status.php:46
Shortcut to construct a special page which is unlisted by default.
if(!isset( $args[0])) $lang