Guarantee terms in PhabricatorAuthPasswordEngine are strings
[phabricator/blender.git] / src / applications / auth / data / PhabricatorAuthInviteAction.php
blob8b6b61aa3081c909dec2df92cb34c89b03f2c5d6
1 <?php
3 final class PhabricatorAuthInviteAction extends Phobject {
5 private $rawInput;
6 private $emailAddress;
7 private $userPHID;
8 private $issues = array();
9 private $action;
11 const ACTION_SEND = 'invite.send';
12 const ACTION_ERROR = 'invite.error';
13 const ACTION_IGNORE = 'invite.ignore';
15 const ISSUE_PARSE = 'invite.parse';
16 const ISSUE_DUPLICATE = 'invite.duplicate';
17 const ISSUE_UNVERIFIED = 'invite.unverified';
18 const ISSUE_VERIFIED = 'invite.verified';
19 const ISSUE_INVITED = 'invite.invited';
20 const ISSUE_ACCEPTED = 'invite.accepted';
22 public function getRawInput() {
23 return $this->rawInput;
26 public function getEmailAddress() {
27 return $this->emailAddress;
30 public function getUserPHID() {
31 return $this->userPHID;
34 public function getIssues() {
35 return $this->issues;
38 public function setAction($action) {
39 $this->action = $action;
40 return $this;
43 public function getAction() {
44 return $this->action;
47 public function willSend() {
48 return ($this->action == self::ACTION_SEND);
51 public function getShortNameForIssue($issue) {
52 $map = array(
53 self::ISSUE_PARSE => pht('Not a Valid Email Address'),
54 self::ISSUE_DUPLICATE => pht('Address Duplicated in Input'),
55 self::ISSUE_UNVERIFIED => pht('Unverified User Email'),
56 self::ISSUE_VERIFIED => pht('Verified User Email'),
57 self::ISSUE_INVITED => pht('Previously Invited'),
58 self::ISSUE_ACCEPTED => pht('Already Accepted Invite'),
61 return idx($map, $issue);
64 public function getShortNameForAction($action) {
65 $map = array(
66 self::ACTION_SEND => pht('Will Send Invite'),
67 self::ACTION_ERROR => pht('Address Error'),
68 self::ACTION_IGNORE => pht('Will Ignore Address'),
71 return idx($map, $action);
74 public function getIconForAction($action) {
75 switch ($action) {
76 case self::ACTION_SEND:
77 $icon = 'fa-envelope-o';
78 $color = 'green';
79 break;
80 case self::ACTION_IGNORE:
81 $icon = 'fa-ban';
82 $color = 'grey';
83 break;
84 case self::ACTION_ERROR:
85 $icon = 'fa-exclamation-triangle';
86 $color = 'red';
87 break;
90 return id(new PHUIIconView())
91 ->setIcon("{$icon} {$color}");
94 public static function newActionListFromAddresses(
95 PhabricatorUser $viewer,
96 array $addresses) {
98 $results = array();
99 foreach ($addresses as $address) {
100 $result = new PhabricatorAuthInviteAction();
101 $result->rawInput = $address;
103 $email = new PhutilEmailAddress($address);
104 $result->emailAddress = phutil_utf8_strtolower($email->getAddress());
106 if (!preg_match('/^\S+@\S+\.\S+\z/', $result->emailAddress)) {
107 $result->issues[] = self::ISSUE_PARSE;
110 $results[] = $result;
113 // Identify duplicates.
114 $address_groups = mgroup($results, 'getEmailAddress');
115 foreach ($address_groups as $address => $group) {
116 if (count($group) > 1) {
117 foreach ($group as $action) {
118 $action->issues[] = self::ISSUE_DUPLICATE;
123 // Identify addresses which are already in the system.
124 $addresses = mpull($results, 'getEmailAddress');
125 $email_objects = id(new PhabricatorUserEmail())->loadAllWhere(
126 'address IN (%Ls)',
127 $addresses);
129 $email_map = array();
130 foreach ($email_objects as $email_object) {
131 $address_key = phutil_utf8_strtolower($email_object->getAddress());
132 $email_map[$address_key] = $email_object;
135 // Identify outstanding invites.
136 $invites = id(new PhabricatorAuthInviteQuery())
137 ->setViewer($viewer)
138 ->withEmailAddresses($addresses)
139 ->execute();
140 $invite_map = mpull($invites, null, 'getEmailAddress');
142 foreach ($results as $action) {
143 $email = idx($email_map, $action->getEmailAddress());
144 if ($email) {
145 if ($email->getUserPHID()) {
146 $action->userPHID = $email->getUserPHID();
147 if ($email->getIsVerified()) {
148 $action->issues[] = self::ISSUE_VERIFIED;
149 } else {
150 $action->issues[] = self::ISSUE_UNVERIFIED;
155 $invite = idx($invite_map, $action->getEmailAddress());
156 if ($invite) {
157 if ($invite->getAcceptedByPHID()) {
158 $action->issues[] = self::ISSUE_ACCEPTED;
159 if (!$action->userPHID) {
160 // This could be different from the user who is currently attached
161 // to the email address if the address was removed or added to a
162 // different account later. Only show it if the address was
163 // removed, since the current status is more up-to-date otherwise.
164 $action->userPHID = $invite->getAcceptedByPHID();
166 } else {
167 $action->issues[] = self::ISSUE_INVITED;
172 foreach ($results as $result) {
173 foreach ($result->getIssues() as $issue) {
174 switch ($issue) {
175 case self::ISSUE_PARSE:
176 $result->action = self::ACTION_ERROR;
177 break;
178 case self::ISSUE_ACCEPTED:
179 case self::ISSUE_VERIFIED:
180 $result->action = self::ACTION_IGNORE;
181 break;
184 if (!$result->action) {
185 $result->action = self::ACTION_SEND;
189 return $results;
192 public function sendInvite(PhabricatorUser $actor, $template) {
193 if (!$this->willSend()) {
194 throw new Exception(pht('Invite action is not a send action!'));
197 if (!preg_match('/{\$INVITE_URI}/', $template)) {
198 throw new Exception(pht('Invite template does not include invite URI!'));
201 PhabricatorWorker::scheduleTask(
202 'PhabricatorAuthInviteWorker',
203 array(
204 'address' => $this->getEmailAddress(),
205 'template' => $template,
206 'authorPHID' => $actor->getPHID(),