diff --git a/src/applications/people/controller/PhabricatorPeopleProfileController.php b/src/applications/people/controller/PhabricatorPeopleProfileController.php --- a/src/applications/people/controller/PhabricatorPeopleProfileController.php +++ b/src/applications/people/controller/PhabricatorPeopleProfileController.php @@ -103,6 +103,8 @@ if ($user->getIsDisabled()) { $header->setStatus('fa-ban', 'red', pht('Disabled')); + } else if (!$user->getIsEmailVerified()) { + $header->setStatus('fa-envelope', 'red', pht('Email Not Verified')); } else { $header->setStatus($profile_icon, 'bluegrey', $profile_title); } diff --git a/src/applications/people/markup/PhabricatorMentionRemarkupRule.php b/src/applications/people/markup/PhabricatorMentionRemarkupRule.php --- a/src/applications/people/markup/PhabricatorMentionRemarkupRule.php +++ b/src/applications/people/markup/PhabricatorMentionRemarkupRule.php @@ -150,7 +150,7 @@ $tag->addClass('phabricator-remarkup-mention-nopermission'); } - if (!$user->isUserActivated()) { + if (!$user->isResponsive()) { $tag->setDotColor(PHUITagView::COLOR_GREY); } else { if ($user->getAwayUntil()) { diff --git a/src/applications/people/phid/PhabricatorPeopleUserPHIDType.php b/src/applications/people/phid/PhabricatorPeopleUserPHIDType.php --- a/src/applications/people/phid/PhabricatorPeopleUserPHIDType.php +++ b/src/applications/people/phid/PhabricatorPeopleUserPHIDType.php @@ -61,7 +61,7 @@ } $availability = null; - if (!$user->isUserActivated()) { + if (!$user->isResponsive()) { $availability = PhabricatorObjectHandle::AVAILABILITY_DISABLED; } else { $until = $user->getAwayUntil(); diff --git a/src/applications/people/storage/PhabricatorUser.php b/src/applications/people/storage/PhabricatorUser.php --- a/src/applications/people/storage/PhabricatorUser.php +++ b/src/applications/people/storage/PhabricatorUser.php @@ -120,6 +120,32 @@ return true; } + + /** + * Is this a user who we can reasonably expect to respond to requests? + * + * This is used to provide a grey "disabled/unresponsive" dot cue when + * rendering handles and tags, so it isn't a surprise if you get ignored + * when you ask things of users who will not receive notifications or could + * not respond to them (because they are disabled, unapproved, do not have + * verified email addresses, etc). + * + * @return bool True if this user can receive and respond to requests from + * other humans. + */ + public function isResponsive() { + if (!$this->isUserActivated()) { + return false; + } + + if (!$this->getIsEmailVerified()) { + return false; + } + + return true; + } + + public function canEstablishWebSessions() { if ($this->getIsMailingList()) { return false; diff --git a/src/applications/people/view/PhabricatorUserCardView.php b/src/applications/people/view/PhabricatorUserCardView.php --- a/src/applications/people/view/PhabricatorUserCardView.php +++ b/src/applications/people/view/PhabricatorUserCardView.php @@ -52,17 +52,44 @@ require_celerity_resource('project-card-view-css'); - $profile_icon = PhabricatorPeopleIconSet::getIconIcon($profile->getIcon()); - $profile_title = $profile->getDisplayTitle(); + // We don't have a ton of room on the hovercard, so we're trying to show + // the most important tag. Users can click through to the profile to get + // more details. + + if ($user->getIsDisabled()) { + $tag_icon = 'fa-ban'; + $tag_title = pht('Disabled'); + $tag_shade = PHUITagView::COLOR_RED; + } else if (!$user->getIsApproved()) { + $tag_icon = 'fa-ban'; + $tag_title = pht('Unapproved Account'); + $tag_shade = PHUITagView::COLOR_RED; + } else if (!$user->getIsEmailVerified()) { + $tag_icon = 'fa-envelope'; + $tag_title = pht('Email Not Verified'); + $tag_shade = PHUITagView::COLOR_RED; + } else if ($user->getIsAdmin()) { + $tag_icon = 'fa-star'; + $tag_title = pht('Administrator'); + $tag_shade = PHUITagView::COLOR_INDIGO; + } else { + $tag_icon = PhabricatorPeopleIconSet::getIconIcon($profile->getIcon()); + $tag_title = $profile->getDisplayTitle(); + $tag_shade = null; + } $tag = id(new PHUITagView()) - ->setIcon($profile_icon) - ->setName($profile_title) - ->addClass('project-view-header-tag') + ->setIcon($tag_icon) + ->setName($tag_title) ->setType(PHUITagView::TYPE_SHADE); + if ($tag_shade !== null) { + $tag->setShade($tag_shade); + } + $header = id(new PHUIHeaderView()) - ->setHeader(array($user->getFullName(), $tag)) + ->setHeader($user->getFullName()) + ->addTag($tag) ->setUser($viewer) ->setImage($picture); @@ -70,7 +97,7 @@ $body[] = $this->addItem( pht('User Since'), - phabricator_date($profile->getDateCreated(), $viewer)); + phabricator_date($user->getDateCreated(), $viewer)); if (PhabricatorApplication::isClassInstalledForViewer( 'PhabricatorCalendarApplication', diff --git a/src/applications/search/controller/PhabricatorSearchHovercardController.php b/src/applications/search/controller/PhabricatorSearchHovercardController.php --- a/src/applications/search/controller/PhabricatorSearchHovercardController.php +++ b/src/applications/search/controller/PhabricatorSearchHovercardController.php @@ -9,7 +9,23 @@ public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); - $phids = $request->getArr('phids'); + $phids = $request->getStrList('phids'); + + // If object names are provided, look them up and pretend they were + // passed as additional PHIDs. This is primarily useful for debugging, + // since you don't have to go look up user PHIDs to preview their + // hovercards. + $names = $request->getStrList('names'); + if ($names) { + $named_objects = id(new PhabricatorObjectQuery()) + ->setViewer($viewer) + ->withNames($names) + ->execute(); + + foreach ($named_objects as $object) { + $phids[] = $object->getPHID(); + } + } $handles = id(new PhabricatorHandleQuery()) ->setViewer($viewer)