Skip to content

Commit 5537e29

Browse files
author
epriestley
committed
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
1 parent 98bf3a9 commit 5537e29

10 files changed

+218
-64
lines changed

scripts/user/add_user.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,12 @@
5959
->setActor($admin)
6060
->createNewUser($user, $email_object);
6161

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+
}
6368

6469
echo pht(
6570
"Created user '%s' (realname='%s', email='%s').\n",

src/__phutil_library_map__.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3814,6 +3814,8 @@
38143814
'PhabricatorPeopleLogQuery' => 'applications/people/query/PhabricatorPeopleLogQuery.php',
38153815
'PhabricatorPeopleLogSearchEngine' => 'applications/people/query/PhabricatorPeopleLogSearchEngine.php',
38163816
'PhabricatorPeopleLogsController' => 'applications/people/controller/PhabricatorPeopleLogsController.php',
3817+
'PhabricatorPeopleMailEngine' => 'applications/people/mail/PhabricatorPeopleMailEngine.php',
3818+
'PhabricatorPeopleMailEngineException' => 'applications/people/mail/PhabricatorPeopleMailEngineException.php',
38173819
'PhabricatorPeopleManageProfileMenuItem' => 'applications/people/menuitem/PhabricatorPeopleManageProfileMenuItem.php',
38183820
'PhabricatorPeopleManagementWorkflow' => 'applications/people/management/PhabricatorPeopleManagementWorkflow.php',
38193821
'PhabricatorPeopleNewController' => 'applications/people/controller/PhabricatorPeopleNewController.php',
@@ -3841,6 +3843,7 @@
38413843
'PhabricatorPeopleUserFunctionDatasource' => 'applications/people/typeahead/PhabricatorPeopleUserFunctionDatasource.php',
38423844
'PhabricatorPeopleUserPHIDType' => 'applications/people/phid/PhabricatorPeopleUserPHIDType.php',
38433845
'PhabricatorPeopleWelcomeController' => 'applications/people/controller/PhabricatorPeopleWelcomeController.php',
3846+
'PhabricatorPeopleWelcomeMailEngine' => 'applications/people/mail/PhabricatorPeopleWelcomeMailEngine.php',
38443847
'PhabricatorPhabricatorAuthProvider' => 'applications/auth/provider/PhabricatorPhabricatorAuthProvider.php',
38453848
'PhabricatorPhameApplication' => 'applications/phame/application/PhabricatorPhameApplication.php',
38463849
'PhabricatorPhameBlogPHIDType' => 'applications/phame/phid/PhabricatorPhameBlogPHIDType.php',
@@ -9730,6 +9733,8 @@
97309733
'PhabricatorPeopleLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
97319734
'PhabricatorPeopleLogSearchEngine' => 'PhabricatorApplicationSearchEngine',
97329735
'PhabricatorPeopleLogsController' => 'PhabricatorPeopleController',
9736+
'PhabricatorPeopleMailEngine' => 'Phobject',
9737+
'PhabricatorPeopleMailEngineException' => 'Exception',
97339738
'PhabricatorPeopleManageProfileMenuItem' => 'PhabricatorProfileMenuItem',
97349739
'PhabricatorPeopleManagementWorkflow' => 'PhabricatorManagementWorkflow',
97359740
'PhabricatorPeopleNewController' => 'PhabricatorPeopleController',
@@ -9757,6 +9762,7 @@
97579762
'PhabricatorPeopleUserFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
97589763
'PhabricatorPeopleUserPHIDType' => 'PhabricatorPHIDType',
97599764
'PhabricatorPeopleWelcomeController' => 'PhabricatorPeopleController',
9765+
'PhabricatorPeopleWelcomeMailEngine' => 'PhabricatorPeopleMailEngine',
97609766
'PhabricatorPhabricatorAuthProvider' => 'PhabricatorOAuth2AuthProvider',
97619767
'PhabricatorPhameApplication' => 'PhabricatorApplication',
97629768
'PhabricatorPhameBlogPHIDType' => 'PhabricatorPHIDType',

src/applications/metamta/management/PhabricatorMailManagementShowOutboundWorkflow.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,14 @@ public function execute(PhutilArgumentParser $args) {
115115
$info[] = $this->newSectionHeader(pht('HEADERS'));
116116

117117
$headers = $message->getDeliveredHeaders();
118+
if (!$headers) {
119+
$headers = array();
120+
}
121+
118122
$unfiltered = $message->getUnfilteredHeaders();
123+
if (!$unfiltered) {
124+
$unfiltered = array();
125+
}
119126

120127
$header_map = array();
121128
foreach ($headers as $header) {
@@ -201,6 +208,7 @@ public function execute(PhutilArgumentParser $args) {
201208
$info[] = null;
202209
} else {
203210
$info[] = pht('(This message has no HTML body.)');
211+
$info[] = null;
204212
}
205213

206214
$console->writeOut('%s', implode("\n", $info));

src/applications/people/controller/PhabricatorPeopleNewController.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,13 @@ public function handleRequest(AphrontRequest $request) {
107107
->makeMailingListUser($user, true);
108108
}
109109

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+
}
112117
}
113118

114119
$response = id(new AphrontRedirectResponse())

src/applications/people/controller/PhabricatorPeopleProfileManageController.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,11 @@ private function buildCurtain(PhabricatorUser $user) {
9292
PeopleDisableUsersCapability::CAPABILITY);
9393
$can_disable = ($has_disable && !$is_self);
9494

95-
$can_welcome = ($is_admin && $user->canEstablishWebSessions());
95+
$welcome_engine = id(new PhabricatorPeopleWelcomeMailEngine())
96+
->setSender($viewer)
97+
->setRecipient($user);
9698

99+
$can_welcome = $welcome_engine->canSendMail();
97100
$curtain = $this->newCurtainView($user);
98101

99102
$curtain->addAction(

src/applications/people/controller/PhabricatorPeopleWelcomeController.php

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@
33
final class PhabricatorPeopleWelcomeController
44
extends PhabricatorPeopleController {
55

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+
613
public function handleRequest(AphrontRequest $request) {
714
$admin = $this->getViewer();
815

@@ -14,22 +21,24 @@ public function handleRequest(AphrontRequest $request) {
1421
return new Aphront404Response();
1522
}
1623

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);
1830

19-
if (!$user->canEstablishWebSessions()) {
31+
try {
32+
$welcome_engine->validateMail();
33+
} catch (PhabricatorPeopleMailEngineException $ex) {
2034
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())
2837
->addCancelButton($profile_uri, pht('Done'));
2938
}
3039

3140
if ($request->isFormPost()) {
32-
$user->sendWelcomeEmail($admin);
41+
$welcome_engine->sendMail();
3342
return id(new AphrontRedirectResponse())->setURI($profile_uri);
3443
}
3544

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
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+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
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+
}

src/applications/people/storage/PhabricatorUser.php

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -555,56 +555,6 @@ public function updateNameTokens() {
555555
}
556556
}
557557

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-
608558
public function sendUsernameChangeEmail(
609559
PhabricatorUser $admin,
610560
$old_username) {

0 commit comments

Comments
 (0)