MediaWiki REL1_37
SpecialChangeEmail.php
Go to the documentation of this file.
1<?php
26
36 private $status;
37
42 parent::__construct( 'ChangeEmail', 'editmyprivateinfo' );
43
44 $this->setAuthManager( $authManager );
45 }
46
47 public function doesWrites() {
48 return true;
49 }
50
54 public function isListed() {
55 return $this->getAuthManager()->allowsPropertyChange( 'emailaddress' );
56 }
57
62 public function execute( $par ) {
63 $out = $this->getOutput();
64 $out->disallowUserJs();
65
66 parent::execute( $par );
67 }
68
69 protected function getLoginSecurityLevel() {
70 return $this->getName();
71 }
72
73 protected function checkExecutePermissions( User $user ) {
74 if ( !$this->getAuthManager()->allowsPropertyChange( 'emailaddress' ) ) {
75 throw new ErrorPageError( 'changeemail', 'cannotchangeemail' );
76 }
77
78 $this->requireLogin( 'changeemail-no-info' );
79
80 // This could also let someone check the current email address, so
81 // require both permissions.
82 if ( !$this->getAuthority()->isAllowed( 'viewmyprivateinfo' ) ) {
83 throw new PermissionsError( 'viewmyprivateinfo' );
84 }
85
86 parent::checkExecutePermissions( $user );
87 }
88
89 protected function getFormFields() {
90 $user = $this->getUser();
91
92 $fields = [
93 'Name' => [
94 'type' => 'info',
95 'label-message' => 'username',
96 'default' => $user->getName(),
97 ],
98 'OldEmail' => [
99 'type' => 'info',
100 'label-message' => 'changeemail-oldemail',
101 'default' => $user->getEmail() ?: $this->msg( 'changeemail-none' )->text(),
102 ],
103 'NewEmail' => [
104 'type' => 'email',
105 'label-message' => 'changeemail-newemail',
106 'autofocus' => true,
107 'maxlength' => 255,
108 'help-message' => 'changeemail-newemail-help',
109 ],
110 ];
111
112 return $fields;
113 }
114
115 protected function getDisplayFormat() {
116 return 'ooui';
117 }
118
119 protected function alterForm( HTMLForm $form ) {
120 $form->setId( 'mw-changeemail-form' );
121 $form->setTableId( 'mw-changeemail-table' );
122 $form->setSubmitTextMsg( 'changeemail-submit' );
123 $form->addHiddenFields( $this->getRequest()->getValues( 'returnto', 'returntoquery' ) );
124
125 $form->addHeaderText( $this->msg( 'changeemail-header' )->parseAsBlock() );
126 }
127
128 public function onSubmit( array $data ) {
129 $status = $this->attemptChange( $this->getUser(), $data['NewEmail'] );
130
131 $this->status = $status;
132
133 return $status;
134 }
135
136 public function onSuccess() {
137 $request = $this->getRequest();
138
139 $returnto = $request->getVal( 'returnto' );
140 $titleObj = $returnto !== null ? Title::newFromText( $returnto ) : null;
141 if ( !$titleObj instanceof Title ) {
142 $titleObj = Title::newMainPage();
143 }
144 $query = $request->getVal( 'returntoquery', '' );
145
146 if ( $this->status->value === true ) {
147 $this->getOutput()->redirect( $titleObj->getFullUrlForRedirect( $query ) );
148 } elseif ( $this->status->value === 'eauth' ) {
149 # Notify user that a confirmation email has been sent...
150 $this->getOutput()->wrapWikiMsg( "<div class='warningbox'>\n$1\n</div>",
151 'eauthentsent', $this->getUser()->getName() );
152 // just show the link to go back
153 $this->getOutput()->addReturnTo( $titleObj, wfCgiToArray( $query ) );
154 }
155 }
156
162 private function attemptChange( User $user, $newaddr ) {
163 if ( $newaddr != '' && !Sanitizer::validateEmail( $newaddr ) ) {
164 return Status::newFatal( 'invalidemailaddress' );
165 }
166
167 $oldaddr = $user->getEmail();
168 if ( $newaddr === $oldaddr ) {
169 return Status::newFatal( 'changeemail-nochange' );
170 }
171
172 if ( strlen( $newaddr ) > 255 ) {
173 return Status::newFatal( 'changeemail-maxlength' );
174 }
175
176 // To prevent spam, rate limit adding a new address, but do
177 // not rate limit removing an address.
178 if ( $newaddr !== '' && $user->pingLimiter( 'changeemail' ) ) {
179 return Status::newFatal( 'actionthrottledtext' );
180 }
181
182 $userLatest = $user->getInstanceForUpdate();
183 $status = $userLatest->setEmailWithConfirmation( $newaddr );
184 if ( !$status->isGood() ) {
185 return $status;
186 }
187
188 LoggerFactory::getInstance( 'authentication' )->info(
189 'Changing email address for {user} from {oldemail} to {newemail}', [
190 'user' => $userLatest->getName(),
191 'oldemail' => $oldaddr,
192 'newemail' => $newaddr,
193 ]
194 );
195
196 $this->getHookRunner()->onPrefsEmailAudit( $userLatest, $oldaddr, $newaddr );
197
198 $userLatest->saveSettings();
199
200 return $status;
201 }
202
203 public function requiresUnblock() {
204 return false;
205 }
206
207 protected function getGroupName() {
208 return 'users';
209 }
210}
wfCgiToArray( $query)
This is the logical opposite of wfArrayToCgi(): it accepts a query string as its argument and returns...
An error page which can definitely be safely rendered using the OutputPage.
Special page which uses an HTMLForm to handle processing.
string null $par
The sub-page of the special page.
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition HTMLForm.php:143
setTableId( $id)
Set the id of the <table> or outermost <div> element.
setSubmitTextMsg( $msg)
Set the text for the submit button to a message.
setId( $id)
addHeaderText( $msg, $section=null)
Add HTML to the header, inside the form.
Definition HTMLForm.php:830
addHiddenFields(array $fields)
Add an array of hidden fields to the output.
Definition HTMLForm.php:985
This serves as the entry point to the authentication system.
PSR-3 logger instance factory.
Show an error when a user tries to do something they do not have the necessary permissions for.
Let users change their email address.
doesWrites()
Indicates whether this special page may perform database writes.
requiresUnblock()
Whether this action cannot be executed by a blocked user.
getDisplayFormat()
Get display format for the form.
onSuccess()
Do something exciting on successful processing of the form, most likely to show a confirmation messag...
alterForm(HTMLForm $form)
Play with the HTMLForm if you need to more substantially.
getFormFields()
Get an HTMLForm descriptor array.
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
attemptChange(User $user, $newaddr)
checkExecutePermissions(User $user)
Called from execute() to check if the given user can perform this action.
__construct(AuthManager $authManager)
execute( $par)
Main execution point.
getLoginSecurityLevel()
Tells if the special page does something security-sensitive and needs extra defense against a stolen ...
onSubmit(array $data)
Process the form on POST submission.
getName()
Get the name of this Special Page.
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.
AuthManager null $authManager
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getAuthority()
Shortcut to get the Authority executing this instance.
getRequest()
Get the WebRequest being used for this instance.
setAuthManager(AuthManager $authManager)
Set the injected AuthManager from the special page constructor.
isGood()
Returns whether the operation completed and didn't have any error or warnings.
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition Status.php:44
Represents a title within MediaWiki.
Definition Title.php:48
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition User.php:69
pingLimiter( $action='edit', $incrBy=1)
Primitive rate limits: enforce maximum actions per time period to put a brake on flooding.
Definition User.php:1689
getEmail()
Get the user's e-mail address.
Definition User.php:2433
getInstanceForUpdate()
Get a new instance of this user that was loaded from the primary DB via a locking read.
Definition User.php:4240