mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-09 16:32:39 +01:00
Move "Welcome" mail generation out of PhabricatorUser
Summary: Ref PHI1027. Currently, `PhabricatorUser` has a couple of mail-related methods which shouldn't really be there in the long term. Immediately, I want to make some adjusments to the welcome email. Move "Welcome" mail generation to a separate class and consolidate all the error handling. (Eventually, "invite" and "verify address" email should move to similar subclasses, too.) Previously, a bunch of errors/conditions got checked in multiple places. The only functional change is that we no longer allow you to send welcome mail to disabled users. Test Plan: - Used "Send Welcome Mail" from profile pages to send mail. - Hit "not admin", "disabled user", "bot/mailing list" errors. - Used `scripts/user/add_user.php` to send welcome mail. - Used "Create New User" to send welcome mail. - Verified mail with `bin/mail show-outbound`. (Cleaned up a couple of minor display issues here.) Reviewers: amckinley Reviewed By: amckinley Differential Revision: https://secure.phabricator.com/D19989
This commit is contained in:
parent
98bf3a950d
commit
5537e29ee8
10 changed files with 218 additions and 64 deletions
|
@ -59,7 +59,12 @@ id(new PhabricatorUserEditor())
|
||||||
->setActor($admin)
|
->setActor($admin)
|
||||||
->createNewUser($user, $email_object);
|
->createNewUser($user, $email_object);
|
||||||
|
|
||||||
$user->sendWelcomeEmail($admin);
|
$welcome_engine = id(new PhabricatorPeopleWelcomeMailEngine())
|
||||||
|
->setSender($admin)
|
||||||
|
->setRecipient($user);
|
||||||
|
if ($welcome_engine->canSendMail()) {
|
||||||
|
$welcome_engine->sendMail();
|
||||||
|
}
|
||||||
|
|
||||||
echo pht(
|
echo pht(
|
||||||
"Created user '%s' (realname='%s', email='%s').\n",
|
"Created user '%s' (realname='%s', email='%s').\n",
|
||||||
|
|
|
@ -3814,6 +3814,8 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorPeopleLogQuery' => 'applications/people/query/PhabricatorPeopleLogQuery.php',
|
'PhabricatorPeopleLogQuery' => 'applications/people/query/PhabricatorPeopleLogQuery.php',
|
||||||
'PhabricatorPeopleLogSearchEngine' => 'applications/people/query/PhabricatorPeopleLogSearchEngine.php',
|
'PhabricatorPeopleLogSearchEngine' => 'applications/people/query/PhabricatorPeopleLogSearchEngine.php',
|
||||||
'PhabricatorPeopleLogsController' => 'applications/people/controller/PhabricatorPeopleLogsController.php',
|
'PhabricatorPeopleLogsController' => 'applications/people/controller/PhabricatorPeopleLogsController.php',
|
||||||
|
'PhabricatorPeopleMailEngine' => 'applications/people/mail/PhabricatorPeopleMailEngine.php',
|
||||||
|
'PhabricatorPeopleMailEngineException' => 'applications/people/mail/PhabricatorPeopleMailEngineException.php',
|
||||||
'PhabricatorPeopleManageProfileMenuItem' => 'applications/people/menuitem/PhabricatorPeopleManageProfileMenuItem.php',
|
'PhabricatorPeopleManageProfileMenuItem' => 'applications/people/menuitem/PhabricatorPeopleManageProfileMenuItem.php',
|
||||||
'PhabricatorPeopleManagementWorkflow' => 'applications/people/management/PhabricatorPeopleManagementWorkflow.php',
|
'PhabricatorPeopleManagementWorkflow' => 'applications/people/management/PhabricatorPeopleManagementWorkflow.php',
|
||||||
'PhabricatorPeopleNewController' => 'applications/people/controller/PhabricatorPeopleNewController.php',
|
'PhabricatorPeopleNewController' => 'applications/people/controller/PhabricatorPeopleNewController.php',
|
||||||
|
@ -3841,6 +3843,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorPeopleUserFunctionDatasource' => 'applications/people/typeahead/PhabricatorPeopleUserFunctionDatasource.php',
|
'PhabricatorPeopleUserFunctionDatasource' => 'applications/people/typeahead/PhabricatorPeopleUserFunctionDatasource.php',
|
||||||
'PhabricatorPeopleUserPHIDType' => 'applications/people/phid/PhabricatorPeopleUserPHIDType.php',
|
'PhabricatorPeopleUserPHIDType' => 'applications/people/phid/PhabricatorPeopleUserPHIDType.php',
|
||||||
'PhabricatorPeopleWelcomeController' => 'applications/people/controller/PhabricatorPeopleWelcomeController.php',
|
'PhabricatorPeopleWelcomeController' => 'applications/people/controller/PhabricatorPeopleWelcomeController.php',
|
||||||
|
'PhabricatorPeopleWelcomeMailEngine' => 'applications/people/mail/PhabricatorPeopleWelcomeMailEngine.php',
|
||||||
'PhabricatorPhabricatorAuthProvider' => 'applications/auth/provider/PhabricatorPhabricatorAuthProvider.php',
|
'PhabricatorPhabricatorAuthProvider' => 'applications/auth/provider/PhabricatorPhabricatorAuthProvider.php',
|
||||||
'PhabricatorPhameApplication' => 'applications/phame/application/PhabricatorPhameApplication.php',
|
'PhabricatorPhameApplication' => 'applications/phame/application/PhabricatorPhameApplication.php',
|
||||||
'PhabricatorPhameBlogPHIDType' => 'applications/phame/phid/PhabricatorPhameBlogPHIDType.php',
|
'PhabricatorPhameBlogPHIDType' => 'applications/phame/phid/PhabricatorPhameBlogPHIDType.php',
|
||||||
|
@ -9730,6 +9733,8 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorPeopleLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
'PhabricatorPeopleLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
'PhabricatorPeopleLogSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
'PhabricatorPeopleLogSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||||
'PhabricatorPeopleLogsController' => 'PhabricatorPeopleController',
|
'PhabricatorPeopleLogsController' => 'PhabricatorPeopleController',
|
||||||
|
'PhabricatorPeopleMailEngine' => 'Phobject',
|
||||||
|
'PhabricatorPeopleMailEngineException' => 'Exception',
|
||||||
'PhabricatorPeopleManageProfileMenuItem' => 'PhabricatorProfileMenuItem',
|
'PhabricatorPeopleManageProfileMenuItem' => 'PhabricatorProfileMenuItem',
|
||||||
'PhabricatorPeopleManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
'PhabricatorPeopleManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
||||||
'PhabricatorPeopleNewController' => 'PhabricatorPeopleController',
|
'PhabricatorPeopleNewController' => 'PhabricatorPeopleController',
|
||||||
|
@ -9757,6 +9762,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorPeopleUserFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
'PhabricatorPeopleUserFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
||||||
'PhabricatorPeopleUserPHIDType' => 'PhabricatorPHIDType',
|
'PhabricatorPeopleUserPHIDType' => 'PhabricatorPHIDType',
|
||||||
'PhabricatorPeopleWelcomeController' => 'PhabricatorPeopleController',
|
'PhabricatorPeopleWelcomeController' => 'PhabricatorPeopleController',
|
||||||
|
'PhabricatorPeopleWelcomeMailEngine' => 'PhabricatorPeopleMailEngine',
|
||||||
'PhabricatorPhabricatorAuthProvider' => 'PhabricatorOAuth2AuthProvider',
|
'PhabricatorPhabricatorAuthProvider' => 'PhabricatorOAuth2AuthProvider',
|
||||||
'PhabricatorPhameApplication' => 'PhabricatorApplication',
|
'PhabricatorPhameApplication' => 'PhabricatorApplication',
|
||||||
'PhabricatorPhameBlogPHIDType' => 'PhabricatorPHIDType',
|
'PhabricatorPhameBlogPHIDType' => 'PhabricatorPHIDType',
|
||||||
|
|
|
@ -115,7 +115,14 @@ final class PhabricatorMailManagementShowOutboundWorkflow
|
||||||
$info[] = $this->newSectionHeader(pht('HEADERS'));
|
$info[] = $this->newSectionHeader(pht('HEADERS'));
|
||||||
|
|
||||||
$headers = $message->getDeliveredHeaders();
|
$headers = $message->getDeliveredHeaders();
|
||||||
|
if (!$headers) {
|
||||||
|
$headers = array();
|
||||||
|
}
|
||||||
|
|
||||||
$unfiltered = $message->getUnfilteredHeaders();
|
$unfiltered = $message->getUnfilteredHeaders();
|
||||||
|
if (!$unfiltered) {
|
||||||
|
$unfiltered = array();
|
||||||
|
}
|
||||||
|
|
||||||
$header_map = array();
|
$header_map = array();
|
||||||
foreach ($headers as $header) {
|
foreach ($headers as $header) {
|
||||||
|
@ -201,6 +208,7 @@ final class PhabricatorMailManagementShowOutboundWorkflow
|
||||||
$info[] = null;
|
$info[] = null;
|
||||||
} else {
|
} else {
|
||||||
$info[] = pht('(This message has no HTML body.)');
|
$info[] = pht('(This message has no HTML body.)');
|
||||||
|
$info[] = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$console->writeOut('%s', implode("\n", $info));
|
$console->writeOut('%s', implode("\n", $info));
|
||||||
|
|
|
@ -107,8 +107,13 @@ final class PhabricatorPeopleNewController
|
||||||
->makeMailingListUser($user, true);
|
->makeMailingListUser($user, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($welcome_checked && !$is_bot && !$is_list) {
|
if ($welcome_checked) {
|
||||||
$user->sendWelcomeEmail($admin);
|
$welcome_engine = id(new PhabricatorPeopleWelcomeMailEngine())
|
||||||
|
->setSender($admin)
|
||||||
|
->setRecipient($user);
|
||||||
|
if ($welcome_engine->canSendMail()) {
|
||||||
|
$welcome_engine->sendMail();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$response = id(new AphrontRedirectResponse())
|
$response = id(new AphrontRedirectResponse())
|
||||||
|
|
|
@ -92,8 +92,11 @@ final class PhabricatorPeopleProfileManageController
|
||||||
PeopleDisableUsersCapability::CAPABILITY);
|
PeopleDisableUsersCapability::CAPABILITY);
|
||||||
$can_disable = ($has_disable && !$is_self);
|
$can_disable = ($has_disable && !$is_self);
|
||||||
|
|
||||||
$can_welcome = ($is_admin && $user->canEstablishWebSessions());
|
$welcome_engine = id(new PhabricatorPeopleWelcomeMailEngine())
|
||||||
|
->setSender($viewer)
|
||||||
|
->setRecipient($user);
|
||||||
|
|
||||||
|
$can_welcome = $welcome_engine->canSendMail();
|
||||||
$curtain = $this->newCurtainView($user);
|
$curtain = $this->newCurtainView($user);
|
||||||
|
|
||||||
$curtain->addAction(
|
$curtain->addAction(
|
||||||
|
|
|
@ -3,6 +3,13 @@
|
||||||
final class PhabricatorPeopleWelcomeController
|
final class PhabricatorPeopleWelcomeController
|
||||||
extends PhabricatorPeopleController {
|
extends PhabricatorPeopleController {
|
||||||
|
|
||||||
|
public function shouldRequireAdmin() {
|
||||||
|
// You need to be an administrator to actually send welcome email, but
|
||||||
|
// we let anyone hit this page so they can get a nice error dialog
|
||||||
|
// explaining the issue.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public function handleRequest(AphrontRequest $request) {
|
public function handleRequest(AphrontRequest $request) {
|
||||||
$admin = $this->getViewer();
|
$admin = $this->getViewer();
|
||||||
|
|
||||||
|
@ -14,22 +21,24 @@ final class PhabricatorPeopleWelcomeController
|
||||||
return new Aphront404Response();
|
return new Aphront404Response();
|
||||||
}
|
}
|
||||||
|
|
||||||
$profile_uri = '/p/'.$user->getUsername().'/';
|
$id = $user->getID();
|
||||||
|
$profile_uri = "/people/manage/{$id}/";
|
||||||
|
|
||||||
if (!$user->canEstablishWebSessions()) {
|
$welcome_engine = id(new PhabricatorPeopleWelcomeMailEngine())
|
||||||
|
->setSender($admin)
|
||||||
|
->setRecipient($user);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$welcome_engine->validateMail();
|
||||||
|
} catch (PhabricatorPeopleMailEngineException $ex) {
|
||||||
return $this->newDialog()
|
return $this->newDialog()
|
||||||
->setTitle(pht('Not a Normal User'))
|
->setTitle($ex->getTitle())
|
||||||
->appendParagraph(
|
->appendParagraph($ex->getBody())
|
||||||
pht(
|
|
||||||
'You can not send this user a welcome mail because they are not '.
|
|
||||||
'a normal user and can not log in to the web interface. Special '.
|
|
||||||
'users (like bots and mailing lists) are unable to establish web '.
|
|
||||||
'sessions.'))
|
|
||||||
->addCancelButton($profile_uri, pht('Done'));
|
->addCancelButton($profile_uri, pht('Done'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($request->isFormPost()) {
|
if ($request->isFormPost()) {
|
||||||
$user->sendWelcomeEmail($admin);
|
$welcome_engine->sendMail();
|
||||||
return id(new AphrontRedirectResponse())->setURI($profile_uri);
|
return id(new AphrontRedirectResponse())->setURI($profile_uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
61
src/applications/people/mail/PhabricatorPeopleMailEngine.php
Normal file
61
src/applications/people/mail/PhabricatorPeopleMailEngine.php
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class PhabricatorPeopleMailEngine
|
||||||
|
extends Phobject {
|
||||||
|
|
||||||
|
private $sender;
|
||||||
|
private $recipient;
|
||||||
|
|
||||||
|
final public function setSender(PhabricatorUser $sender) {
|
||||||
|
$this->sender = $sender;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function getSender() {
|
||||||
|
if (!$this->sender) {
|
||||||
|
throw new PhutilInvalidStateException('setSender');
|
||||||
|
}
|
||||||
|
return $this->sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function setRecipient(PhabricatorUser $recipient) {
|
||||||
|
$this->recipient = $recipient;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function getRecipient() {
|
||||||
|
if (!$this->recipient) {
|
||||||
|
throw new PhutilInvalidStateException('setRecipient');
|
||||||
|
}
|
||||||
|
return $this->recipient;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function canSendMail() {
|
||||||
|
try {
|
||||||
|
$this->validateMail();
|
||||||
|
return true;
|
||||||
|
} catch (PhabricatorPeopleMailEngineException $ex) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function sendMail() {
|
||||||
|
$this->validateMail();
|
||||||
|
$mail = $this->newMail();
|
||||||
|
|
||||||
|
$mail
|
||||||
|
->setForceDelivery(true)
|
||||||
|
->save();
|
||||||
|
|
||||||
|
return $mail;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract public function validateMail();
|
||||||
|
abstract protected function newMail();
|
||||||
|
|
||||||
|
|
||||||
|
final protected function throwValidationException($title, $body) {
|
||||||
|
throw new PhabricatorPeopleMailEngineException($title, $body);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorPeopleMailEngineException
|
||||||
|
extends Exception {
|
||||||
|
|
||||||
|
private $title;
|
||||||
|
private $body;
|
||||||
|
|
||||||
|
public function __construct($title, $body) {
|
||||||
|
$this->title = $title;
|
||||||
|
$this->body = $body;
|
||||||
|
|
||||||
|
parent::__construct(pht('%s: %s', $title, $body));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle() {
|
||||||
|
return $this->title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBody() {
|
||||||
|
return $this->body;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorPeopleWelcomeMailEngine
|
||||||
|
extends PhabricatorPeopleMailEngine {
|
||||||
|
|
||||||
|
public function validateMail() {
|
||||||
|
$sender = $this->getSender();
|
||||||
|
$recipient = $this->getRecipient();
|
||||||
|
|
||||||
|
if (!$sender->getIsAdmin()) {
|
||||||
|
$this->throwValidationException(
|
||||||
|
pht('Not an Administrator'),
|
||||||
|
pht(
|
||||||
|
'You can not send welcome mail because you are not an '.
|
||||||
|
'administrator. Only administrators may send welcome mail.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($recipient->getIsDisabled()) {
|
||||||
|
$this->throwValidationException(
|
||||||
|
pht('User is Disabled'),
|
||||||
|
pht(
|
||||||
|
'You can not send welcome mail to this user because their account '.
|
||||||
|
'is disabled.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$recipient->canEstablishWebSessions()) {
|
||||||
|
$this->throwValidationException(
|
||||||
|
pht('Not a Normal User'),
|
||||||
|
pht(
|
||||||
|
'You can not send this user welcome mail because they are not '.
|
||||||
|
'a normal user and can not log in to the web interface. Special '.
|
||||||
|
'users (like bots and mailing lists) are unable to establish '.
|
||||||
|
'web sessions.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function newMail() {
|
||||||
|
$sender = $this->getSender();
|
||||||
|
$recipient = $this->getRecipient();
|
||||||
|
|
||||||
|
$sender_username = $sender->getUserName();
|
||||||
|
$sender_realname = $sender->getRealName();
|
||||||
|
|
||||||
|
$recipient_username = $recipient->getUserName();
|
||||||
|
$is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
|
||||||
|
|
||||||
|
$base_uri = PhabricatorEnv::getProductionURI('/');
|
||||||
|
|
||||||
|
$engine = new PhabricatorAuthSessionEngine();
|
||||||
|
|
||||||
|
$uri = $engine->getOneTimeLoginURI(
|
||||||
|
$recipient,
|
||||||
|
$recipient->loadPrimaryEmail(),
|
||||||
|
PhabricatorAuthSessionEngine::ONETIME_WELCOME);
|
||||||
|
|
||||||
|
$body = pht(
|
||||||
|
"Welcome to Phabricator!\n\n".
|
||||||
|
"%s (%s) has created an account for you.\n\n".
|
||||||
|
" Username: %s\n\n".
|
||||||
|
"To login to Phabricator, follow this link and set a password:\n\n".
|
||||||
|
" %s\n\n".
|
||||||
|
"After you have set a password, you can login in the future by ".
|
||||||
|
"going here:\n\n".
|
||||||
|
" %s\n",
|
||||||
|
$sender_username,
|
||||||
|
$sender_realname,
|
||||||
|
$recipient_username,
|
||||||
|
$uri,
|
||||||
|
$base_uri);
|
||||||
|
|
||||||
|
if (!$is_serious) {
|
||||||
|
$body .= sprintf(
|
||||||
|
"\n%s\n",
|
||||||
|
pht("Love,\nPhabricator"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return id(new PhabricatorMetaMTAMail())
|
||||||
|
->addTos(array($recipient->getPHID()))
|
||||||
|
->setSubject(pht('[Phabricator] Welcome to Phabricator'))
|
||||||
|
->setBody($body);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -555,56 +555,6 @@ final class PhabricatorUser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function sendWelcomeEmail(PhabricatorUser $admin) {
|
|
||||||
if (!$this->canEstablishWebSessions()) {
|
|
||||||
throw new Exception(
|
|
||||||
pht(
|
|
||||||
'Can not send welcome mail to users who can not establish '.
|
|
||||||
'web sessions!'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$admin_username = $admin->getUserName();
|
|
||||||
$admin_realname = $admin->getRealName();
|
|
||||||
$user_username = $this->getUserName();
|
|
||||||
$is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
|
|
||||||
|
|
||||||
$base_uri = PhabricatorEnv::getProductionURI('/');
|
|
||||||
|
|
||||||
$engine = new PhabricatorAuthSessionEngine();
|
|
||||||
$uri = $engine->getOneTimeLoginURI(
|
|
||||||
$this,
|
|
||||||
$this->loadPrimaryEmail(),
|
|
||||||
PhabricatorAuthSessionEngine::ONETIME_WELCOME);
|
|
||||||
|
|
||||||
$body = pht(
|
|
||||||
"Welcome to Phabricator!\n\n".
|
|
||||||
"%s (%s) has created an account for you.\n\n".
|
|
||||||
" Username: %s\n\n".
|
|
||||||
"To login to Phabricator, follow this link and set a password:\n\n".
|
|
||||||
" %s\n\n".
|
|
||||||
"After you have set a password, you can login in the future by ".
|
|
||||||
"going here:\n\n".
|
|
||||||
" %s\n",
|
|
||||||
$admin_username,
|
|
||||||
$admin_realname,
|
|
||||||
$user_username,
|
|
||||||
$uri,
|
|
||||||
$base_uri);
|
|
||||||
|
|
||||||
if (!$is_serious) {
|
|
||||||
$body .= sprintf(
|
|
||||||
"\n%s\n",
|
|
||||||
pht("Love,\nPhabricator"));
|
|
||||||
}
|
|
||||||
|
|
||||||
$mail = id(new PhabricatorMetaMTAMail())
|
|
||||||
->addTos(array($this->getPHID()))
|
|
||||||
->setForceDelivery(true)
|
|
||||||
->setSubject(pht('[Phabricator] Welcome to Phabricator'))
|
|
||||||
->setBody($body)
|
|
||||||
->saveAndSend();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function sendUsernameChangeEmail(
|
public function sendUsernameChangeEmail(
|
||||||
PhabricatorUser $admin,
|
PhabricatorUser $admin,
|
||||||
$old_username) {
|
$old_username) {
|
||||||
|
|
Loading…
Reference in a new issue