@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+218 -64
+6 -1
scripts/user/add_user.php
··· 59 59 ->setActor($admin) 60 60 ->createNewUser($user, $email_object); 61 61 62 - $user->sendWelcomeEmail($admin); 62 + $welcome_engine = id(new PhabricatorPeopleWelcomeMailEngine()) 63 + ->setSender($admin) 64 + ->setRecipient($user); 65 + if ($welcome_engine->canSendMail()) { 66 + $welcome_engine->sendMail(); 67 + } 63 68 64 69 echo pht( 65 70 "Created user '%s' (realname='%s', email='%s').\n",
+6
src/__phutil_library_map__.php
··· 3814 3814 'PhabricatorPeopleLogQuery' => 'applications/people/query/PhabricatorPeopleLogQuery.php', 3815 3815 'PhabricatorPeopleLogSearchEngine' => 'applications/people/query/PhabricatorPeopleLogSearchEngine.php', 3816 3816 'PhabricatorPeopleLogsController' => 'applications/people/controller/PhabricatorPeopleLogsController.php', 3817 + 'PhabricatorPeopleMailEngine' => 'applications/people/mail/PhabricatorPeopleMailEngine.php', 3818 + 'PhabricatorPeopleMailEngineException' => 'applications/people/mail/PhabricatorPeopleMailEngineException.php', 3817 3819 'PhabricatorPeopleManageProfileMenuItem' => 'applications/people/menuitem/PhabricatorPeopleManageProfileMenuItem.php', 3818 3820 'PhabricatorPeopleManagementWorkflow' => 'applications/people/management/PhabricatorPeopleManagementWorkflow.php', 3819 3821 'PhabricatorPeopleNewController' => 'applications/people/controller/PhabricatorPeopleNewController.php', ··· 3841 3843 'PhabricatorPeopleUserFunctionDatasource' => 'applications/people/typeahead/PhabricatorPeopleUserFunctionDatasource.php', 3842 3844 'PhabricatorPeopleUserPHIDType' => 'applications/people/phid/PhabricatorPeopleUserPHIDType.php', 3843 3845 'PhabricatorPeopleWelcomeController' => 'applications/people/controller/PhabricatorPeopleWelcomeController.php', 3846 + 'PhabricatorPeopleWelcomeMailEngine' => 'applications/people/mail/PhabricatorPeopleWelcomeMailEngine.php', 3844 3847 'PhabricatorPhabricatorAuthProvider' => 'applications/auth/provider/PhabricatorPhabricatorAuthProvider.php', 3845 3848 'PhabricatorPhameApplication' => 'applications/phame/application/PhabricatorPhameApplication.php', 3846 3849 'PhabricatorPhameBlogPHIDType' => 'applications/phame/phid/PhabricatorPhameBlogPHIDType.php', ··· 9730 9733 'PhabricatorPeopleLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 9731 9734 'PhabricatorPeopleLogSearchEngine' => 'PhabricatorApplicationSearchEngine', 9732 9735 'PhabricatorPeopleLogsController' => 'PhabricatorPeopleController', 9736 + 'PhabricatorPeopleMailEngine' => 'Phobject', 9737 + 'PhabricatorPeopleMailEngineException' => 'Exception', 9733 9738 'PhabricatorPeopleManageProfileMenuItem' => 'PhabricatorProfileMenuItem', 9734 9739 'PhabricatorPeopleManagementWorkflow' => 'PhabricatorManagementWorkflow', 9735 9740 'PhabricatorPeopleNewController' => 'PhabricatorPeopleController', ··· 9757 9762 'PhabricatorPeopleUserFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 9758 9763 'PhabricatorPeopleUserPHIDType' => 'PhabricatorPHIDType', 9759 9764 'PhabricatorPeopleWelcomeController' => 'PhabricatorPeopleController', 9765 + 'PhabricatorPeopleWelcomeMailEngine' => 'PhabricatorPeopleMailEngine', 9760 9766 'PhabricatorPhabricatorAuthProvider' => 'PhabricatorOAuth2AuthProvider', 9761 9767 'PhabricatorPhameApplication' => 'PhabricatorApplication', 9762 9768 'PhabricatorPhameBlogPHIDType' => 'PhabricatorPHIDType',
+8
src/applications/metamta/management/PhabricatorMailManagementShowOutboundWorkflow.php
··· 115 115 $info[] = $this->newSectionHeader(pht('HEADERS')); 116 116 117 117 $headers = $message->getDeliveredHeaders(); 118 + if (!$headers) { 119 + $headers = array(); 120 + } 121 + 118 122 $unfiltered = $message->getUnfilteredHeaders(); 123 + if (!$unfiltered) { 124 + $unfiltered = array(); 125 + } 119 126 120 127 $header_map = array(); 121 128 foreach ($headers as $header) { ··· 201 208 $info[] = null; 202 209 } else { 203 210 $info[] = pht('(This message has no HTML body.)'); 211 + $info[] = null; 204 212 } 205 213 206 214 $console->writeOut('%s', implode("\n", $info));
+7 -2
src/applications/people/controller/PhabricatorPeopleNewController.php
··· 107 107 ->makeMailingListUser($user, true); 108 108 } 109 109 110 - if ($welcome_checked && !$is_bot && !$is_list) { 111 - $user->sendWelcomeEmail($admin); 110 + if ($welcome_checked) { 111 + $welcome_engine = id(new PhabricatorPeopleWelcomeMailEngine()) 112 + ->setSender($admin) 113 + ->setRecipient($user); 114 + if ($welcome_engine->canSendMail()) { 115 + $welcome_engine->sendMail(); 116 + } 112 117 } 113 118 114 119 $response = id(new AphrontRedirectResponse())
+4 -1
src/applications/people/controller/PhabricatorPeopleProfileManageController.php
··· 92 92 PeopleDisableUsersCapability::CAPABILITY); 93 93 $can_disable = ($has_disable && !$is_self); 94 94 95 - $can_welcome = ($is_admin && $user->canEstablishWebSessions()); 95 + $welcome_engine = id(new PhabricatorPeopleWelcomeMailEngine()) 96 + ->setSender($viewer) 97 + ->setRecipient($user); 96 98 99 + $can_welcome = $welcome_engine->canSendMail(); 97 100 $curtain = $this->newCurtainView($user); 98 101 99 102 $curtain->addAction(
+19 -10
src/applications/people/controller/PhabricatorPeopleWelcomeController.php
··· 3 3 final class PhabricatorPeopleWelcomeController 4 4 extends PhabricatorPeopleController { 5 5 6 + public function shouldRequireAdmin() { 7 + // You need to be an administrator to actually send welcome email, but 8 + // we let anyone hit this page so they can get a nice error dialog 9 + // explaining the issue. 10 + return false; 11 + } 12 + 6 13 public function handleRequest(AphrontRequest $request) { 7 14 $admin = $this->getViewer(); 8 15 ··· 14 21 return new Aphront404Response(); 15 22 } 16 23 17 - $profile_uri = '/p/'.$user->getUsername().'/'; 24 + $id = $user->getID(); 25 + $profile_uri = "/people/manage/{$id}/"; 26 + 27 + $welcome_engine = id(new PhabricatorPeopleWelcomeMailEngine()) 28 + ->setSender($admin) 29 + ->setRecipient($user); 18 30 19 - if (!$user->canEstablishWebSessions()) { 31 + try { 32 + $welcome_engine->validateMail(); 33 + } catch (PhabricatorPeopleMailEngineException $ex) { 20 34 return $this->newDialog() 21 - ->setTitle(pht('Not a Normal User')) 22 - ->appendParagraph( 23 - pht( 24 - 'You can not send this user a welcome mail because they are not '. 25 - 'a normal user and can not log in to the web interface. Special '. 26 - 'users (like bots and mailing lists) are unable to establish web '. 27 - 'sessions.')) 35 + ->setTitle($ex->getTitle()) 36 + ->appendParagraph($ex->getBody()) 28 37 ->addCancelButton($profile_uri, pht('Done')); 29 38 } 30 39 31 40 if ($request->isFormPost()) { 32 - $user->sendWelcomeEmail($admin); 41 + $welcome_engine->sendMail(); 33 42 return id(new AphrontRedirectResponse())->setURI($profile_uri); 34 43 } 35 44
+61
src/applications/people/mail/PhabricatorPeopleMailEngine.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorPeopleMailEngine 4 + extends Phobject { 5 + 6 + private $sender; 7 + private $recipient; 8 + 9 + final public function setSender(PhabricatorUser $sender) { 10 + $this->sender = $sender; 11 + return $this; 12 + } 13 + 14 + final public function getSender() { 15 + if (!$this->sender) { 16 + throw new PhutilInvalidStateException('setSender'); 17 + } 18 + return $this->sender; 19 + } 20 + 21 + final public function setRecipient(PhabricatorUser $recipient) { 22 + $this->recipient = $recipient; 23 + return $this; 24 + } 25 + 26 + final public function getRecipient() { 27 + if (!$this->recipient) { 28 + throw new PhutilInvalidStateException('setRecipient'); 29 + } 30 + return $this->recipient; 31 + } 32 + 33 + final public function canSendMail() { 34 + try { 35 + $this->validateMail(); 36 + return true; 37 + } catch (PhabricatorPeopleMailEngineException $ex) { 38 + return false; 39 + } 40 + } 41 + 42 + final public function sendMail() { 43 + $this->validateMail(); 44 + $mail = $this->newMail(); 45 + 46 + $mail 47 + ->setForceDelivery(true) 48 + ->save(); 49 + 50 + return $mail; 51 + } 52 + 53 + abstract public function validateMail(); 54 + abstract protected function newMail(); 55 + 56 + 57 + final protected function throwValidationException($title, $body) { 58 + throw new PhabricatorPeopleMailEngineException($title, $body); 59 + } 60 + 61 + }
+24
src/applications/people/mail/PhabricatorPeopleMailEngineException.php
··· 1 + <?php 2 + 3 + final class PhabricatorPeopleMailEngineException 4 + extends Exception { 5 + 6 + private $title; 7 + private $body; 8 + 9 + public function __construct($title, $body) { 10 + $this->title = $title; 11 + $this->body = $body; 12 + 13 + parent::__construct(pht('%s: %s', $title, $body)); 14 + } 15 + 16 + public function getTitle() { 17 + return $this->title; 18 + } 19 + 20 + public function getBody() { 21 + return $this->body; 22 + } 23 + 24 + }
+83
src/applications/people/mail/PhabricatorPeopleWelcomeMailEngine.php
··· 1 + <?php 2 + 3 + final class PhabricatorPeopleWelcomeMailEngine 4 + extends PhabricatorPeopleMailEngine { 5 + 6 + public function validateMail() { 7 + $sender = $this->getSender(); 8 + $recipient = $this->getRecipient(); 9 + 10 + if (!$sender->getIsAdmin()) { 11 + $this->throwValidationException( 12 + pht('Not an Administrator'), 13 + pht( 14 + 'You can not send welcome mail because you are not an '. 15 + 'administrator. Only administrators may send welcome mail.')); 16 + } 17 + 18 + if ($recipient->getIsDisabled()) { 19 + $this->throwValidationException( 20 + pht('User is Disabled'), 21 + pht( 22 + 'You can not send welcome mail to this user because their account '. 23 + 'is disabled.')); 24 + } 25 + 26 + if (!$recipient->canEstablishWebSessions()) { 27 + $this->throwValidationException( 28 + pht('Not a Normal User'), 29 + pht( 30 + 'You can not send this user welcome mail because they are not '. 31 + 'a normal user and can not log in to the web interface. Special '. 32 + 'users (like bots and mailing lists) are unable to establish '. 33 + 'web sessions.')); 34 + } 35 + } 36 + 37 + protected function newMail() { 38 + $sender = $this->getSender(); 39 + $recipient = $this->getRecipient(); 40 + 41 + $sender_username = $sender->getUserName(); 42 + $sender_realname = $sender->getRealName(); 43 + 44 + $recipient_username = $recipient->getUserName(); 45 + $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); 46 + 47 + $base_uri = PhabricatorEnv::getProductionURI('/'); 48 + 49 + $engine = new PhabricatorAuthSessionEngine(); 50 + 51 + $uri = $engine->getOneTimeLoginURI( 52 + $recipient, 53 + $recipient->loadPrimaryEmail(), 54 + PhabricatorAuthSessionEngine::ONETIME_WELCOME); 55 + 56 + $body = pht( 57 + "Welcome to Phabricator!\n\n". 58 + "%s (%s) has created an account for you.\n\n". 59 + " Username: %s\n\n". 60 + "To login to Phabricator, follow this link and set a password:\n\n". 61 + " %s\n\n". 62 + "After you have set a password, you can login in the future by ". 63 + "going here:\n\n". 64 + " %s\n", 65 + $sender_username, 66 + $sender_realname, 67 + $recipient_username, 68 + $uri, 69 + $base_uri); 70 + 71 + if (!$is_serious) { 72 + $body .= sprintf( 73 + "\n%s\n", 74 + pht("Love,\nPhabricator")); 75 + } 76 + 77 + return id(new PhabricatorMetaMTAMail()) 78 + ->addTos(array($recipient->getPHID())) 79 + ->setSubject(pht('[Phabricator] Welcome to Phabricator')) 80 + ->setBody($body); 81 + } 82 + 83 + }
-50
src/applications/people/storage/PhabricatorUser.php
··· 555 555 } 556 556 } 557 557 558 - public function sendWelcomeEmail(PhabricatorUser $admin) { 559 - if (!$this->canEstablishWebSessions()) { 560 - throw new Exception( 561 - pht( 562 - 'Can not send welcome mail to users who can not establish '. 563 - 'web sessions!')); 564 - } 565 - 566 - $admin_username = $admin->getUserName(); 567 - $admin_realname = $admin->getRealName(); 568 - $user_username = $this->getUserName(); 569 - $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); 570 - 571 - $base_uri = PhabricatorEnv::getProductionURI('/'); 572 - 573 - $engine = new PhabricatorAuthSessionEngine(); 574 - $uri = $engine->getOneTimeLoginURI( 575 - $this, 576 - $this->loadPrimaryEmail(), 577 - PhabricatorAuthSessionEngine::ONETIME_WELCOME); 578 - 579 - $body = pht( 580 - "Welcome to Phabricator!\n\n". 581 - "%s (%s) has created an account for you.\n\n". 582 - " Username: %s\n\n". 583 - "To login to Phabricator, follow this link and set a password:\n\n". 584 - " %s\n\n". 585 - "After you have set a password, you can login in the future by ". 586 - "going here:\n\n". 587 - " %s\n", 588 - $admin_username, 589 - $admin_realname, 590 - $user_username, 591 - $uri, 592 - $base_uri); 593 - 594 - if (!$is_serious) { 595 - $body .= sprintf( 596 - "\n%s\n", 597 - pht("Love,\nPhabricator")); 598 - } 599 - 600 - $mail = id(new PhabricatorMetaMTAMail()) 601 - ->addTos(array($this->getPHID())) 602 - ->setForceDelivery(true) 603 - ->setSubject(pht('[Phabricator] Welcome to Phabricator')) 604 - ->setBody($body) 605 - ->saveAndSend(); 606 - } 607 - 608 558 public function sendUsernameChangeEmail( 609 559 PhabricatorUser $admin, 610 560 $old_username) {