2011-07-18 17:02:00 +02:00
|
|
|
<?php
|
|
|
|
|
2012-08-13 21:37:26 +02:00
|
|
|
final class PhabricatorSettingsPanelEmailAddresses
|
|
|
|
extends PhabricatorSettingsPanel {
|
2011-07-18 17:02:00 +02:00
|
|
|
|
2012-08-13 21:37:26 +02:00
|
|
|
public function getPanelKey() {
|
|
|
|
return 'email';
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getPanelName() {
|
|
|
|
return pht('Email Addresses');
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getPanelGroup() {
|
|
|
|
return pht('Email');
|
|
|
|
}
|
2011-07-18 17:02:00 +02:00
|
|
|
|
2012-08-13 21:37:26 +02:00
|
|
|
public function processRequest(AphrontRequest $request) {
|
2011-07-18 17:02:00 +02:00
|
|
|
$user = $request->getUser();
|
2012-08-13 21:37:26 +02:00
|
|
|
$editable = PhabricatorEnv::getEnvConfig('account.editable');
|
2011-07-18 17:02:00 +02:00
|
|
|
|
2012-05-07 19:29:33 +02:00
|
|
|
$uri = $request->getRequestURI();
|
|
|
|
$uri->setQueryParams(array());
|
|
|
|
|
|
|
|
if ($editable) {
|
|
|
|
$new = $request->getStr('new');
|
|
|
|
if ($new) {
|
2012-08-13 21:37:26 +02:00
|
|
|
return $this->returnNewAddressResponse($request, $uri, $new);
|
2012-05-07 19:29:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
$delete = $request->getInt('delete');
|
|
|
|
if ($delete) {
|
2012-08-13 21:37:26 +02:00
|
|
|
return $this->returnDeleteAddressResponse($request, $uri, $delete);
|
2012-05-07 19:29:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$verify = $request->getInt('verify');
|
|
|
|
if ($verify) {
|
2012-08-13 21:37:26 +02:00
|
|
|
return $this->returnVerifyAddressResponse($request, $uri, $verify);
|
2012-05-07 19:29:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
$primary = $request->getInt('primary');
|
|
|
|
if ($primary) {
|
2012-08-13 21:37:26 +02:00
|
|
|
return $this->returnPrimaryAddressResponse($request, $uri, $primary);
|
2012-05-07 19:29:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
$emails = id(new PhabricatorUserEmail())->loadAllWhere(
|
2012-05-23 21:55:07 +02:00
|
|
|
'userPHID = %s ORDER BY address',
|
2012-05-07 19:29:33 +02:00
|
|
|
$user->getPHID());
|
|
|
|
|
|
|
|
$rowc = array();
|
|
|
|
$rows = array();
|
|
|
|
foreach ($emails as $email) {
|
|
|
|
|
2013-01-25 21:57:17 +01:00
|
|
|
$button_verify = javelin_tag(
|
2012-05-23 21:55:07 +02:00
|
|
|
'a',
|
|
|
|
array(
|
|
|
|
'class' => 'button small grey',
|
|
|
|
'href' => $uri->alter('verify', $email->getID()),
|
|
|
|
'sigil' => 'workflow',
|
|
|
|
),
|
2013-03-03 15:52:42 +01:00
|
|
|
pht('Verify'));
|
2012-05-23 21:55:07 +02:00
|
|
|
|
2013-01-25 21:57:17 +01:00
|
|
|
$button_make_primary = javelin_tag(
|
2012-05-23 21:55:07 +02:00
|
|
|
'a',
|
|
|
|
array(
|
|
|
|
'class' => 'button small grey',
|
|
|
|
'href' => $uri->alter('primary', $email->getID()),
|
|
|
|
'sigil' => 'workflow',
|
|
|
|
),
|
2013-03-03 15:52:42 +01:00
|
|
|
pht('Make Primary'));
|
2012-05-23 21:55:07 +02:00
|
|
|
|
2013-01-25 21:57:17 +01:00
|
|
|
$button_remove = javelin_tag(
|
2012-05-23 21:55:07 +02:00
|
|
|
'a',
|
|
|
|
array(
|
|
|
|
'class' => 'button small grey',
|
|
|
|
'href' => $uri->alter('delete', $email->getID()),
|
|
|
|
'sigil' => 'workflow'
|
|
|
|
),
|
2013-03-03 15:52:42 +01:00
|
|
|
pht('Remove'));
|
2012-05-23 21:55:07 +02:00
|
|
|
|
2013-01-18 03:57:09 +01:00
|
|
|
$button_primary = phutil_tag(
|
2012-05-23 21:55:07 +02:00
|
|
|
'a',
|
|
|
|
array(
|
|
|
|
'class' => 'button small disabled',
|
|
|
|
),
|
2013-03-03 15:52:42 +01:00
|
|
|
pht('Primary'));
|
2012-05-23 21:55:07 +02:00
|
|
|
|
|
|
|
if (!$email->getIsVerified()) {
|
|
|
|
$action = $button_verify;
|
|
|
|
} else if ($email->getIsPrimary()) {
|
|
|
|
$action = $button_primary;
|
|
|
|
} else {
|
|
|
|
$action = $button_make_primary;
|
|
|
|
}
|
|
|
|
|
2012-05-07 19:29:33 +02:00
|
|
|
if ($email->getIsPrimary()) {
|
2012-05-23 21:55:07 +02:00
|
|
|
$remove = $button_primary;
|
2012-05-07 19:29:33 +02:00
|
|
|
$rowc[] = 'highlighted';
|
|
|
|
} else {
|
2012-05-23 21:55:07 +02:00
|
|
|
$remove = $button_remove;
|
2012-05-07 19:29:33 +02:00
|
|
|
$rowc[] = null;
|
2011-07-18 17:02:00 +02:00
|
|
|
}
|
|
|
|
|
2012-05-07 19:29:33 +02:00
|
|
|
$rows[] = array(
|
2013-02-13 23:50:15 +01:00
|
|
|
$email->getAddress(),
|
2012-05-07 19:29:33 +02:00
|
|
|
$action,
|
|
|
|
$remove,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
$table = new AphrontTableView($rows);
|
|
|
|
$table->setHeaders(
|
|
|
|
array(
|
2013-03-03 15:52:42 +01:00
|
|
|
pht('Email'),
|
|
|
|
pht('Status'),
|
|
|
|
pht('Remove'),
|
2012-05-07 19:29:33 +02:00
|
|
|
));
|
|
|
|
$table->setColumnClasses(
|
|
|
|
array(
|
|
|
|
'wide',
|
|
|
|
'action',
|
|
|
|
'action',
|
|
|
|
));
|
|
|
|
$table->setRowClasses($rowc);
|
|
|
|
$table->setColumnVisibility(
|
|
|
|
array(
|
|
|
|
true,
|
|
|
|
true,
|
|
|
|
$editable,
|
|
|
|
));
|
|
|
|
|
2014-01-08 21:42:55 +01:00
|
|
|
$view = new PHUIObjectBoxView();
|
|
|
|
$header = new PHUIHeaderView();
|
|
|
|
$header->setHeader(pht('Email Addresses'));
|
|
|
|
|
2012-05-07 19:29:33 +02:00
|
|
|
if ($editable) {
|
2014-01-08 21:42:55 +01:00
|
|
|
$icon = id(new PHUIIconView())
|
2014-05-12 19:08:32 +02:00
|
|
|
->setIconFont('fa-plus');
|
2014-01-08 21:42:55 +01:00
|
|
|
|
|
|
|
$button = new PHUIButtonView();
|
|
|
|
$button->setText(pht('Add New Address'));
|
|
|
|
$button->setTag('a');
|
|
|
|
$button->setHref($uri->alter('new', 'true'));
|
|
|
|
$button->setIcon($icon);
|
|
|
|
$button->addSigil('workflow');
|
|
|
|
$header->addActionLink($button);
|
2012-05-07 19:29:33 +02:00
|
|
|
}
|
2014-01-08 21:42:55 +01:00
|
|
|
$view->setHeader($header);
|
2012-05-07 19:29:33 +02:00
|
|
|
$view->appendChild($table);
|
|
|
|
|
|
|
|
return $view;
|
|
|
|
}
|
|
|
|
|
2012-08-13 21:37:26 +02:00
|
|
|
private function returnNewAddressResponse(
|
|
|
|
AphrontRequest $request,
|
|
|
|
PhutilURI $uri,
|
|
|
|
$new) {
|
|
|
|
|
2012-05-07 19:29:33 +02:00
|
|
|
$user = $request->getUser();
|
|
|
|
|
|
|
|
$e_email = true;
|
2014-03-11 00:21:47 +01:00
|
|
|
$email = null;
|
2012-05-07 19:29:33 +02:00
|
|
|
$errors = array();
|
|
|
|
if ($request->isDialogFormPost()) {
|
2014-03-11 00:21:47 +01:00
|
|
|
$email = trim($request->getStr('email'));
|
2011-07-18 17:02:00 +02:00
|
|
|
|
2012-05-07 19:29:33 +02:00
|
|
|
if ($new == 'verify') {
|
|
|
|
// The user clicked "Done" from the "an email has been sent" dialog.
|
|
|
|
return id(new AphrontReloadResponse())->setURI($uri);
|
|
|
|
}
|
|
|
|
|
2014-04-03 20:22:38 +02:00
|
|
|
PhabricatorSystemActionEngine::willTakeAction(
|
|
|
|
array($user->getPHID()),
|
|
|
|
new PhabricatorSettingsAddEmailAction(),
|
|
|
|
1);
|
|
|
|
|
2012-05-07 19:29:33 +02:00
|
|
|
if (!strlen($email)) {
|
2013-03-03 15:52:42 +01:00
|
|
|
$e_email = pht('Required');
|
|
|
|
$errors[] = pht('Email is required.');
|
2014-02-23 19:19:35 +01:00
|
|
|
} else if (!PhabricatorUserEmail::isValidAddress($email)) {
|
2013-03-03 15:52:42 +01:00
|
|
|
$e_email = pht('Invalid');
|
2014-02-23 19:19:35 +01:00
|
|
|
$errors[] = PhabricatorUserEmail::describeValidAddresses();
|
|
|
|
} else if (!PhabricatorUserEmail::isAllowedAddress($email)) {
|
|
|
|
$e_email = pht('Disallowed');
|
Allow restriction of permitted email domains
Summary:
Allow allowed email addresses to be restricted to certain domains. This implies email must be verified.
This probably isn't QUITE ready for prime-time without a few other tweaks (better administrative tools, notably) but we're nearly there.
Test Plan:
- With no restrictions:
- Registered with OAuth
- Created an account with accountadmin
- Added an email
- With restrictions:
- Tried to OAuth register with a restricted address, was prompted to provide a valid one.
- Tried to OAuth register with a valid address, worked fine.
- Tried to accountadmin a restricted address, got blocked.
- Tried to accountadmin a valid address, worked fine.
- Tried to add a restricted address, blocked.
- Tried to add a valid address, worked fine.
- Created a user with People with an invalid address, got blocked.
- Created a user with People with a valid address, worked fine.
Reviewers: btrahan, csilvers
Reviewed By: csilvers
CC: aran, joe, csilvers
Maniphest Tasks: T1184
Differential Revision: https://secure.phabricator.com/D2581
2012-05-26 15:04:35 +02:00
|
|
|
$errors[] = PhabricatorUserEmail::describeAllowedAddresses();
|
2011-07-18 17:02:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!$errors) {
|
2012-05-07 19:29:33 +02:00
|
|
|
$object = id(new PhabricatorUserEmail())
|
|
|
|
->setAddress($email)
|
2012-05-25 16:30:44 +02:00
|
|
|
->setIsVerified(0);
|
2012-05-07 19:29:33 +02:00
|
|
|
|
|
|
|
try {
|
2012-05-25 16:30:44 +02:00
|
|
|
|
|
|
|
id(new PhabricatorUserEditor())
|
|
|
|
->setActor($user)
|
|
|
|
->addEmail($user, $object);
|
2012-05-07 19:29:33 +02:00
|
|
|
|
|
|
|
$object->sendVerificationEmail($user);
|
|
|
|
|
|
|
|
$dialog = id(new AphrontDialogView())
|
|
|
|
->setUser($user)
|
|
|
|
->addHiddenInput('new', 'verify')
|
2013-03-03 15:52:42 +01:00
|
|
|
->setTitle(pht('Verification Email Sent'))
|
2013-02-13 23:50:15 +01:00
|
|
|
->appendChild(phutil_tag('p', array(), pht(
|
|
|
|
'A verification email has been sent. Click the link in the '.
|
|
|
|
'email to verify your address.')))
|
2012-05-07 19:29:33 +02:00
|
|
|
->setSubmitURI($uri)
|
2013-03-03 15:52:42 +01:00
|
|
|
->addSubmitButton(pht('Done'));
|
2012-05-07 19:29:33 +02:00
|
|
|
|
|
|
|
return id(new AphrontDialogResponse())->setDialog($dialog);
|
2014-08-05 23:51:21 +02:00
|
|
|
} catch (AphrontDuplicateKeyQueryException $ex) {
|
2014-08-22 01:07:14 +02:00
|
|
|
$e_email = pht('Duplicate');
|
2013-03-03 15:52:42 +01:00
|
|
|
$errors[] = pht('Another user already has this email.');
|
2012-05-07 19:29:33 +02:00
|
|
|
}
|
2011-07-18 17:02:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-07 19:29:33 +02:00
|
|
|
if ($errors) {
|
|
|
|
$errors = id(new AphrontErrorView())
|
|
|
|
->setErrors($errors);
|
2011-07-18 17:02:00 +02:00
|
|
|
}
|
|
|
|
|
2013-08-26 20:53:11 +02:00
|
|
|
$form = id(new PHUIFormLayoutView())
|
2011-07-18 17:02:00 +02:00
|
|
|
->appendChild(
|
|
|
|
id(new AphrontFormTextControl())
|
2013-03-03 15:52:42 +01:00
|
|
|
->setLabel(pht('Email'))
|
2011-07-18 17:02:00 +02:00
|
|
|
->setName('email')
|
2014-03-11 00:21:47 +01:00
|
|
|
->setValue($email)
|
Allow restriction of permitted email domains
Summary:
Allow allowed email addresses to be restricted to certain domains. This implies email must be verified.
This probably isn't QUITE ready for prime-time without a few other tweaks (better administrative tools, notably) but we're nearly there.
Test Plan:
- With no restrictions:
- Registered with OAuth
- Created an account with accountadmin
- Added an email
- With restrictions:
- Tried to OAuth register with a restricted address, was prompted to provide a valid one.
- Tried to OAuth register with a valid address, worked fine.
- Tried to accountadmin a restricted address, got blocked.
- Tried to accountadmin a valid address, worked fine.
- Tried to add a restricted address, blocked.
- Tried to add a valid address, worked fine.
- Created a user with People with an invalid address, got blocked.
- Created a user with People with a valid address, worked fine.
Reviewers: btrahan, csilvers
Reviewed By: csilvers
CC: aran, joe, csilvers
Maniphest Tasks: T1184
Differential Revision: https://secure.phabricator.com/D2581
2012-05-26 15:04:35 +02:00
|
|
|
->setCaption(PhabricatorUserEmail::describeAllowedAddresses())
|
2011-07-18 17:02:00 +02:00
|
|
|
->setError($e_email));
|
|
|
|
|
2012-05-07 19:29:33 +02:00
|
|
|
$dialog = id(new AphrontDialogView())
|
|
|
|
->setUser($user)
|
|
|
|
->addHiddenInput('new', 'true')
|
2013-03-03 15:52:42 +01:00
|
|
|
->setTitle(pht('New Address'))
|
2012-05-07 19:29:33 +02:00
|
|
|
->appendChild($errors)
|
|
|
|
->appendChild($form)
|
2013-03-03 15:52:42 +01:00
|
|
|
->addSubmitButton(pht('Save'))
|
2012-05-07 19:29:33 +02:00
|
|
|
->addCancelButton($uri);
|
|
|
|
|
|
|
|
return id(new AphrontDialogResponse())->setDialog($dialog);
|
|
|
|
}
|
|
|
|
|
2012-08-13 21:37:26 +02:00
|
|
|
private function returnDeleteAddressResponse(
|
|
|
|
AphrontRequest $request,
|
|
|
|
PhutilURI $uri,
|
|
|
|
$email_id) {
|
|
|
|
|
2012-05-07 19:29:33 +02:00
|
|
|
$user = $request->getUser();
|
|
|
|
|
|
|
|
// NOTE: You can only delete your own email addresses, and you can not
|
|
|
|
// delete your primary address.
|
|
|
|
$email = id(new PhabricatorUserEmail())->loadOneWhere(
|
|
|
|
'id = %d AND userPHID = %s AND isPrimary = 0',
|
|
|
|
$email_id,
|
|
|
|
$user->getPHID());
|
|
|
|
|
|
|
|
if (!$email) {
|
|
|
|
return new Aphront404Response();
|
2011-07-18 17:02:00 +02:00
|
|
|
}
|
|
|
|
|
2012-05-07 19:29:33 +02:00
|
|
|
if ($request->isFormPost()) {
|
2012-05-25 16:30:44 +02:00
|
|
|
|
|
|
|
id(new PhabricatorUserEditor())
|
|
|
|
->setActor($user)
|
|
|
|
->removeEmail($user, $email);
|
|
|
|
|
2012-05-07 19:29:33 +02:00
|
|
|
return id(new AphrontRedirectResponse())->setURI($uri);
|
|
|
|
}
|
|
|
|
|
|
|
|
$address = $email->getAddress();
|
|
|
|
|
|
|
|
$dialog = id(new AphrontDialogView())
|
|
|
|
->setUser($user)
|
|
|
|
->addHiddenInput('delete', $email_id)
|
2013-03-03 15:52:42 +01:00
|
|
|
->setTitle(pht("Really delete address '%s'?", $address))
|
2014-08-04 21:04:23 +02:00
|
|
|
->appendParagraph(
|
|
|
|
pht(
|
|
|
|
'Are you sure you want to delete this address? You will no '.
|
|
|
|
'longer be able to use it to login.'))
|
|
|
|
->appendParagraph(
|
|
|
|
pht(
|
|
|
|
'Note: Removing an email address from your account will invalidate '.
|
|
|
|
'any outstanding password reset links.'))
|
2013-03-03 15:52:42 +01:00
|
|
|
->addSubmitButton(pht('Delete'))
|
2012-05-07 19:29:33 +02:00
|
|
|
->addCancelButton($uri);
|
|
|
|
|
|
|
|
return id(new AphrontDialogResponse())->setDialog($dialog);
|
|
|
|
}
|
|
|
|
|
2012-08-13 21:37:26 +02:00
|
|
|
private function returnVerifyAddressResponse(
|
|
|
|
AphrontRequest $request,
|
|
|
|
PhutilURI $uri,
|
|
|
|
$email_id) {
|
|
|
|
|
2012-05-07 19:29:33 +02:00
|
|
|
$user = $request->getUser();
|
2011-07-18 17:02:00 +02:00
|
|
|
|
2012-05-07 19:29:33 +02:00
|
|
|
// NOTE: You can only send more email for your unverified addresses.
|
|
|
|
$email = id(new PhabricatorUserEmail())->loadOneWhere(
|
|
|
|
'id = %d AND userPHID = %s AND isVerified = 0',
|
|
|
|
$email_id,
|
|
|
|
$user->getPHID());
|
|
|
|
|
|
|
|
if (!$email) {
|
|
|
|
return new Aphront404Response();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($request->isFormPost()) {
|
|
|
|
$email->sendVerificationEmail($user);
|
|
|
|
return id(new AphrontRedirectResponse())->setURI($uri);
|
|
|
|
}
|
|
|
|
|
|
|
|
$address = $email->getAddress();
|
|
|
|
|
|
|
|
$dialog = id(new AphrontDialogView())
|
|
|
|
->setUser($user)
|
|
|
|
->addHiddenInput('verify', $email_id)
|
2014-06-09 20:36:49 +02:00
|
|
|
->setTitle(pht('Send Another Verification Email?'))
|
2013-11-11 18:23:23 +01:00
|
|
|
->appendChild(phutil_tag('p', array(), pht(
|
|
|
|
'Send another copy of the verification email to %s?',
|
|
|
|
$address)))
|
2013-03-03 15:52:42 +01:00
|
|
|
->addSubmitButton(pht('Send Email'))
|
2012-05-07 19:29:33 +02:00
|
|
|
->addCancelButton($uri);
|
|
|
|
|
|
|
|
return id(new AphrontDialogResponse())->setDialog($dialog);
|
2011-07-18 17:02:00 +02:00
|
|
|
}
|
2012-05-07 19:29:33 +02:00
|
|
|
|
2012-08-13 21:37:26 +02:00
|
|
|
private function returnPrimaryAddressResponse(
|
|
|
|
AphrontRequest $request,
|
|
|
|
PhutilURI $uri,
|
|
|
|
$email_id) {
|
|
|
|
|
2012-05-07 19:29:33 +02:00
|
|
|
$user = $request->getUser();
|
|
|
|
|
2014-05-01 02:44:59 +02:00
|
|
|
$token = id(new PhabricatorAuthSessionEngine())->requireHighSecuritySession(
|
|
|
|
$user,
|
|
|
|
$request,
|
|
|
|
$this->getPanelURI());
|
|
|
|
|
2012-05-07 19:29:33 +02:00
|
|
|
// NOTE: You can only make your own verified addresses primary.
|
|
|
|
$email = id(new PhabricatorUserEmail())->loadOneWhere(
|
|
|
|
'id = %d AND userPHID = %s AND isVerified = 1 AND isPrimary = 0',
|
|
|
|
$email_id,
|
|
|
|
$user->getPHID());
|
|
|
|
|
|
|
|
if (!$email) {
|
|
|
|
return new Aphront404Response();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($request->isFormPost()) {
|
|
|
|
|
2012-05-25 16:30:44 +02:00
|
|
|
id(new PhabricatorUserEditor())
|
|
|
|
->setActor($user)
|
|
|
|
->changePrimaryEmail($user, $email);
|
2012-05-07 19:29:33 +02:00
|
|
|
|
|
|
|
return id(new AphrontRedirectResponse())->setURI($uri);
|
|
|
|
}
|
|
|
|
|
|
|
|
$address = $email->getAddress();
|
|
|
|
|
|
|
|
$dialog = id(new AphrontDialogView())
|
|
|
|
->setUser($user)
|
|
|
|
->addHiddenInput('primary', $email_id)
|
2014-06-09 20:36:49 +02:00
|
|
|
->setTitle(pht('Change primary email address?'))
|
2014-08-04 21:04:23 +02:00
|
|
|
->appendParagraph(
|
|
|
|
pht(
|
|
|
|
'If you change your primary address, Phabricator will send all '.
|
|
|
|
'email to %s.',
|
|
|
|
$address))
|
|
|
|
->appendParagraph(
|
|
|
|
pht(
|
|
|
|
'Note: Changing your primary email address will invalidate any '.
|
|
|
|
'outstanding password reset links.'))
|
2013-03-03 15:52:42 +01:00
|
|
|
->addSubmitButton(pht('Change Primary Address'))
|
2012-05-07 19:29:33 +02:00
|
|
|
->addCancelButton($uri);
|
|
|
|
|
|
|
|
return id(new AphrontDialogResponse())->setDialog($dialog);
|
|
|
|
}
|
|
|
|
|
2011-07-18 17:02:00 +02:00
|
|
|
}
|