Correct Aphlict websocket URI construction after PHP8 compatibility changes
[phabricator.git] / src / applications / settings / panel / PhabricatorEmailAddressesSettingsPanel.php
blobb4ce5e21cd16eb08a067b9ffd629c37867d5c45b
1 <?php
3 final class PhabricatorEmailAddressesSettingsPanel
4 extends PhabricatorSettingsPanel {
6 public function getPanelKey() {
7 return 'email';
10 public function getPanelName() {
11 return pht('Email Addresses');
14 public function getPanelMenuIcon() {
15 return 'fa-at';
18 public function getPanelGroupKey() {
19 return PhabricatorSettingsEmailPanelGroup::PANELGROUPKEY;
22 public function isEditableByAdministrators() {
23 if ($this->getUser()->getIsMailingList()) {
24 return true;
27 return false;
30 public function processRequest(AphrontRequest $request) {
31 $user = $this->getUser();
32 $editable = PhabricatorEnv::getEnvConfig('account.editable');
34 $uri = new PhutilURI($request->getPath());
36 if ($editable) {
37 $new = $request->getStr('new');
38 if ($new) {
39 return $this->returnNewAddressResponse($request, $uri, $new);
42 $delete = $request->getInt('delete');
43 if ($delete) {
44 return $this->returnDeleteAddressResponse($request, $uri, $delete);
48 $verify = $request->getInt('verify');
49 if ($verify) {
50 return $this->returnVerifyAddressResponse($request, $uri, $verify);
53 $primary = $request->getInt('primary');
54 if ($primary) {
55 return $this->returnPrimaryAddressResponse($request, $uri, $primary);
58 $emails = id(new PhabricatorUserEmail())->loadAllWhere(
59 'userPHID = %s ORDER BY address',
60 $user->getPHID());
62 $rowc = array();
63 $rows = array();
64 foreach ($emails as $email) {
66 $button_verify = javelin_tag(
67 'a',
68 array(
69 'class' => 'button small button-grey',
70 'href' => $uri->alter('verify', $email->getID()),
71 'sigil' => 'workflow',
73 pht('Verify'));
75 $button_make_primary = javelin_tag(
76 'a',
77 array(
78 'class' => 'button small button-grey',
79 'href' => $uri->alter('primary', $email->getID()),
80 'sigil' => 'workflow',
82 pht('Make Primary'));
84 $button_remove = javelin_tag(
85 'a',
86 array(
87 'class' => 'button small button-grey',
88 'href' => $uri->alter('delete', $email->getID()),
89 'sigil' => 'workflow',
91 pht('Remove'));
93 $button_primary = phutil_tag(
94 'a',
95 array(
96 'class' => 'button small disabled',
98 pht('Primary'));
100 if (!$email->getIsVerified()) {
101 $action = $button_verify;
102 } else if ($email->getIsPrimary()) {
103 $action = $button_primary;
104 } else {
105 $action = $button_make_primary;
108 if ($email->getIsPrimary()) {
109 $remove = $button_primary;
110 $rowc[] = 'highlighted';
111 } else {
112 $remove = $button_remove;
113 $rowc[] = null;
116 $rows[] = array(
117 $email->getAddress(),
118 $action,
119 $remove,
123 $table = new AphrontTableView($rows);
124 $table->setHeaders(
125 array(
126 pht('Email'),
127 pht('Status'),
128 pht('Remove'),
130 $table->setColumnClasses(
131 array(
132 'wide',
133 'action',
134 'action',
136 $table->setRowClasses($rowc);
137 $table->setColumnVisibility(
138 array(
139 true,
140 true,
141 $editable,
144 $buttons = array();
145 if ($editable) {
146 $buttons[] = id(new PHUIButtonView())
147 ->setTag('a')
148 ->setIcon('fa-plus')
149 ->setText(pht('Add New Address'))
150 ->setHref($uri->alter('new', 'true'))
151 ->addSigil('workflow')
152 ->setColor(PHUIButtonView::GREY);
155 return $this->newBox(pht('Email Addresses'), $table, $buttons);
158 private function returnNewAddressResponse(
159 AphrontRequest $request,
160 PhutilURI $uri,
161 $new) {
163 $user = $this->getUser();
164 $viewer = $this->getViewer();
166 $token = id(new PhabricatorAuthSessionEngine())->requireHighSecuritySession(
167 $viewer,
168 $request,
169 $this->getPanelURI());
171 $e_email = true;
172 $email = null;
173 $errors = array();
174 if ($request->isDialogFormPost()) {
175 $email = $request->getStr('email');
176 if (phutil_nonempty_string($email)) {
177 $email = trim($email);
180 if ($new == 'verify') {
181 // The user clicked "Done" from the "an email has been sent" dialog.
182 return id(new AphrontReloadResponse())->setURI($uri);
185 PhabricatorSystemActionEngine::willTakeAction(
186 array($viewer->getPHID()),
187 new PhabricatorSettingsAddEmailAction(),
190 if ($email === null || !strlen($email)) {
191 $e_email = pht('Required');
192 $errors[] = pht('Email is required.');
193 } else if (!PhabricatorUserEmail::isValidAddress($email)) {
194 $e_email = pht('Invalid');
195 $errors[] = PhabricatorUserEmail::describeValidAddresses();
196 } else if (!PhabricatorUserEmail::isAllowedAddress($email)) {
197 $e_email = pht('Disallowed');
198 $errors[] = PhabricatorUserEmail::describeAllowedAddresses();
200 if ($e_email === true) {
201 $application_email = id(new PhabricatorMetaMTAApplicationEmailQuery())
202 ->setViewer(PhabricatorUser::getOmnipotentUser())
203 ->withAddresses(array($email))
204 ->executeOne();
205 if ($application_email) {
206 $e_email = pht('In Use');
207 $errors[] = $application_email->getInUseMessage();
211 if (!$errors) {
212 $object = id(new PhabricatorUserEmail())
213 ->setAddress($email)
214 ->setIsVerified(0);
216 // If an administrator is editing a mailing list, automatically verify
217 // the address.
218 if ($viewer->getPHID() != $user->getPHID()) {
219 if ($viewer->getIsAdmin()) {
220 $object->setIsVerified(1);
224 try {
225 id(new PhabricatorUserEditor())
226 ->setActor($viewer)
227 ->addEmail($user, $object);
229 if ($object->getIsVerified()) {
230 // If we autoverified the address, just reload the page.
231 return id(new AphrontReloadResponse())->setURI($uri);
234 $object->sendVerificationEmail($user);
236 $dialog = $this->newDialog()
237 ->addHiddenInput('new', 'verify')
238 ->setTitle(pht('Verification Email Sent'))
239 ->appendChild(phutil_tag('p', array(), pht(
240 'A verification email has been sent. Click the link in the '.
241 'email to verify your address.')))
242 ->setSubmitURI($uri)
243 ->addSubmitButton(pht('Done'));
245 return id(new AphrontDialogResponse())->setDialog($dialog);
246 } catch (AphrontDuplicateKeyQueryException $ex) {
247 $e_email = pht('Duplicate');
248 $errors[] = pht('Another user already has this email.');
253 if ($errors) {
254 $errors = id(new PHUIInfoView())
255 ->setErrors($errors);
258 $form = id(new PHUIFormLayoutView())
259 ->appendChild(
260 id(new AphrontFormTextControl())
261 ->setLabel(pht('Email'))
262 ->setName('email')
263 ->setValue($email)
264 ->setCaption(PhabricatorUserEmail::describeAllowedAddresses())
265 ->setError($e_email));
267 $dialog = $this->newDialog()
268 ->addHiddenInput('new', 'true')
269 ->setTitle(pht('New Address'))
270 ->appendChild($errors)
271 ->appendChild($form)
272 ->addSubmitButton(pht('Save'))
273 ->addCancelButton($uri);
275 return id(new AphrontDialogResponse())->setDialog($dialog);
278 private function returnDeleteAddressResponse(
279 AphrontRequest $request,
280 PhutilURI $uri,
281 $email_id) {
282 $user = $this->getUser();
283 $viewer = $this->getViewer();
285 $token = id(new PhabricatorAuthSessionEngine())->requireHighSecuritySession(
286 $viewer,
287 $request,
288 $this->getPanelURI());
290 // NOTE: You can only delete your own email addresses, and you can not
291 // delete your primary address.
292 $email = id(new PhabricatorUserEmail())->loadOneWhere(
293 'id = %d AND userPHID = %s AND isPrimary = 0',
294 $email_id,
295 $user->getPHID());
297 if (!$email) {
298 return new Aphront404Response();
301 if ($request->isFormPost()) {
302 id(new PhabricatorUserEditor())
303 ->setActor($viewer)
304 ->removeEmail($user, $email);
306 return id(new AphrontRedirectResponse())->setURI($uri);
309 $address = $email->getAddress();
311 $dialog = id(new AphrontDialogView())
312 ->setUser($viewer)
313 ->addHiddenInput('delete', $email_id)
314 ->setTitle(pht("Really delete address '%s'?", $address))
315 ->appendParagraph(
316 pht(
317 'Are you sure you want to delete this address? You will no '.
318 'longer be able to use it to login.'))
319 ->appendParagraph(
320 pht(
321 'Note: Removing an email address from your account will invalidate '.
322 'any outstanding password reset links.'))
323 ->addSubmitButton(pht('Delete'))
324 ->addCancelButton($uri);
326 return id(new AphrontDialogResponse())->setDialog($dialog);
329 private function returnVerifyAddressResponse(
330 AphrontRequest $request,
331 PhutilURI $uri,
332 $email_id) {
333 $user = $this->getUser();
334 $viewer = $this->getViewer();
336 // NOTE: You can only send more email for your unverified addresses.
337 $email = id(new PhabricatorUserEmail())->loadOneWhere(
338 'id = %d AND userPHID = %s AND isVerified = 0',
339 $email_id,
340 $user->getPHID());
342 if (!$email) {
343 return new Aphront404Response();
346 if ($request->isFormPost()) {
347 $email->sendVerificationEmail($user);
348 return id(new AphrontRedirectResponse())->setURI($uri);
351 $address = $email->getAddress();
353 $dialog = id(new AphrontDialogView())
354 ->setUser($viewer)
355 ->addHiddenInput('verify', $email_id)
356 ->setTitle(pht('Send Another Verification Email?'))
357 ->appendChild(phutil_tag('p', array(), pht(
358 'Send another copy of the verification email to %s?',
359 $address)))
360 ->addSubmitButton(pht('Send Email'))
361 ->addCancelButton($uri);
363 return id(new AphrontDialogResponse())->setDialog($dialog);
366 private function returnPrimaryAddressResponse(
367 AphrontRequest $request,
368 PhutilURI $uri,
369 $email_id) {
370 $user = $this->getUser();
371 $viewer = $this->getViewer();
373 $token = id(new PhabricatorAuthSessionEngine())->requireHighSecuritySession(
374 $viewer,
375 $request,
376 $this->getPanelURI());
378 // NOTE: You can only make your own verified addresses primary.
379 $email = id(new PhabricatorUserEmail())->loadOneWhere(
380 'id = %d AND userPHID = %s AND isVerified = 1 AND isPrimary = 0',
381 $email_id,
382 $user->getPHID());
384 if (!$email) {
385 return new Aphront404Response();
388 if ($request->isFormPost()) {
389 id(new PhabricatorUserEditor())
390 ->setActor($viewer)
391 ->changePrimaryEmail($user, $email);
393 return id(new AphrontRedirectResponse())->setURI($uri);
396 $address = $email->getAddress();
398 $dialog = id(new AphrontDialogView())
399 ->setUser($viewer)
400 ->addHiddenInput('primary', $email_id)
401 ->setTitle(pht('Change primary email address?'))
402 ->appendParagraph(
403 pht(
404 'If you change your primary address, %s will send all '.
405 'email to %s.',
406 PlatformSymbols::getPlatformServerName(),
407 $address))
408 ->appendParagraph(
409 pht(
410 'Note: Changing your primary email address will invalidate any '.
411 'outstanding password reset links.'))
412 ->addSubmitButton(pht('Change Primary Address'))
413 ->addCancelButton($uri);
415 return id(new AphrontDialogResponse())->setDialog($dialog);