2011-01-24 03:09:16 +01:00
|
|
|
<?php
|
|
|
|
|
2012-03-10 00:46:25 +01:00
|
|
|
final class PhabricatorPeopleProfileController
|
|
|
|
extends PhabricatorPeopleController {
|
2011-01-24 03:09:16 +01:00
|
|
|
|
|
|
|
private $username;
|
|
|
|
|
2015-07-22 18:32:54 +02:00
|
|
|
public function shouldAllowPublic() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-03-19 21:48:50 +01:00
|
|
|
public function shouldRequireAdmin() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2011-01-24 03:09:16 +01:00
|
|
|
public function willProcessRequest(array $data) {
|
2011-06-18 10:13:56 +02:00
|
|
|
$this->username = idx($data, 'username');
|
2013-02-05 22:46:02 +01:00
|
|
|
}
|
|
|
|
|
2011-01-24 03:09:16 +01:00
|
|
|
public function processRequest() {
|
2011-02-20 02:33:53 +01:00
|
|
|
$viewer = $this->getRequest()->getUser();
|
|
|
|
|
2013-07-10 14:10:54 +02:00
|
|
|
$user = id(new PhabricatorPeopleQuery())
|
|
|
|
->setViewer($viewer)
|
|
|
|
->withUsernames(array($this->username))
|
2015-07-23 20:46:34 +02:00
|
|
|
->needBadges(true)
|
2013-09-08 18:43:27 +02:00
|
|
|
->needProfileImage(true)
|
2015-05-14 20:15:04 +02:00
|
|
|
->needAvailability(true)
|
2013-07-10 14:10:54 +02:00
|
|
|
->executeOne();
|
2011-01-24 03:09:16 +01:00
|
|
|
if (!$user) {
|
|
|
|
return new Aphront404Response();
|
|
|
|
}
|
|
|
|
|
2013-03-24 14:42:31 +01:00
|
|
|
$profile = $user->loadUserProfile();
|
2012-03-06 22:57:31 +01:00
|
|
|
$username = phutil_escape_uri($user->getUserName());
|
2011-02-20 03:28:41 +01:00
|
|
|
|
2015-02-02 23:04:23 +01:00
|
|
|
$picture = $user->getProfileImageURI();
|
2011-12-24 03:17:40 +01:00
|
|
|
|
2013-09-17 18:12:37 +02:00
|
|
|
$header = id(new PHUIHeaderView())
|
2014-05-12 18:51:40 +02:00
|
|
|
->setHeader($user->getFullName())
|
2013-07-10 01:23:22 +02:00
|
|
|
->setSubheader($profile->getTitle())
|
|
|
|
->setImage($picture);
|
2011-12-24 03:17:40 +01:00
|
|
|
|
2013-07-10 01:23:45 +02:00
|
|
|
$actions = id(new PhabricatorActionListView())
|
2013-07-10 14:11:08 +02:00
|
|
|
->setObject($user)
|
2013-07-12 20:39:47 +02:00
|
|
|
->setObjectURI($this->getRequest()->getRequestURI())
|
2013-07-10 01:23:45 +02:00
|
|
|
->setUser($viewer);
|
2011-12-24 03:17:40 +01:00
|
|
|
|
2014-04-02 21:05:34 +02:00
|
|
|
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
|
|
|
$viewer,
|
|
|
|
$user,
|
|
|
|
PhabricatorPolicyCapability::CAN_EDIT);
|
2013-07-10 01:23:45 +02:00
|
|
|
|
|
|
|
$actions->addAction(
|
|
|
|
id(new PhabricatorActionView())
|
2014-05-12 19:08:32 +02:00
|
|
|
->setIcon('fa-pencil')
|
2013-07-10 01:23:45 +02:00
|
|
|
->setName(pht('Edit Profile'))
|
|
|
|
->setHref($this->getApplicationURI('editprofile/'.$user->getID().'/'))
|
|
|
|
->setDisabled(!$can_edit)
|
|
|
|
->setWorkflow(!$can_edit));
|
2011-02-20 02:33:53 +01:00
|
|
|
|
2013-07-10 01:23:54 +02:00
|
|
|
$actions->addAction(
|
|
|
|
id(new PhabricatorActionView())
|
2014-05-12 19:08:32 +02:00
|
|
|
->setIcon('fa-picture-o')
|
2013-07-10 01:23:54 +02:00
|
|
|
->setName(pht('Edit Profile Picture'))
|
|
|
|
->setHref($this->getApplicationURI('picture/'.$user->getID().'/'))
|
|
|
|
->setDisabled(!$can_edit)
|
|
|
|
->setWorkflow(!$can_edit));
|
|
|
|
|
[Redesign] People, Profile, Feed UI
Summary: Ref T8099, Mostly a Feed cleanup, removing old CSS, relying on modern display objects, adds back the feed to profile (I miss it, but maybe you don't).
Test Plan: Visit Feed on Profiles, Projects, Feed, and Dashboards. Same UI Everywhere. TODO, "Public Feed".
Reviewers: btrahan, epriestley
Reviewed By: epriestley
Subscribers: Korvin, epriestley
Maniphest Tasks: T8099
Differential Revision: https://secure.phabricator.com/D13101
2015-06-01 20:28:01 +02:00
|
|
|
$class = 'PhabricatorConpherenceApplication';
|
|
|
|
if (PhabricatorApplication::isClassInstalledForViewer($class, $viewer)) {
|
2015-06-25 22:59:08 +02:00
|
|
|
$href = id(new PhutilURI('/conpherence/new/'))
|
|
|
|
->setQueryParam('participant', $user->getPHID());
|
|
|
|
|
[Redesign] People, Profile, Feed UI
Summary: Ref T8099, Mostly a Feed cleanup, removing old CSS, relying on modern display objects, adds back the feed to profile (I miss it, but maybe you don't).
Test Plan: Visit Feed on Profiles, Projects, Feed, and Dashboards. Same UI Everywhere. TODO, "Public Feed".
Reviewers: btrahan, epriestley
Reviewed By: epriestley
Subscribers: Korvin, epriestley
Maniphest Tasks: T8099
Differential Revision: https://secure.phabricator.com/D13101
2015-06-01 20:28:01 +02:00
|
|
|
$actions->addAction(
|
|
|
|
id(new PhabricatorActionView())
|
|
|
|
->setIcon('fa-comments')
|
|
|
|
->setName(pht('Send Message'))
|
|
|
|
->setWorkflow(true)
|
|
|
|
->setHref($href));
|
|
|
|
}
|
|
|
|
|
2012-01-17 01:54:05 +01:00
|
|
|
if ($viewer->getIsAdmin()) {
|
2014-04-02 21:06:05 +02:00
|
|
|
$actions->addAction(
|
|
|
|
id(new PhabricatorActionView())
|
2014-05-12 19:08:32 +02:00
|
|
|
->setIcon('fa-wrench')
|
2014-04-02 21:06:05 +02:00
|
|
|
->setName(pht('Edit Settings'))
|
|
|
|
->setDisabled(!$can_edit)
|
|
|
|
->setWorkflow(!$can_edit)
|
|
|
|
->setHref('/settings/'.$user->getID().'/'));
|
|
|
|
|
2014-04-02 21:05:49 +02:00
|
|
|
if ($user->getIsAdmin()) {
|
2014-05-12 19:08:32 +02:00
|
|
|
$empower_icon = 'fa-arrow-circle-o-down';
|
2014-04-02 21:05:49 +02:00
|
|
|
$empower_name = pht('Remove Administrator');
|
|
|
|
} else {
|
2014-05-12 19:08:32 +02:00
|
|
|
$empower_icon = 'fa-arrow-circle-o-up';
|
2014-04-02 21:05:49 +02:00
|
|
|
$empower_name = pht('Make Administrator');
|
|
|
|
}
|
|
|
|
|
|
|
|
$actions->addAction(
|
|
|
|
id(new PhabricatorActionView())
|
|
|
|
->setIcon($empower_icon)
|
|
|
|
->setName($empower_name)
|
|
|
|
->setDisabled(($user->getPHID() == $viewer->getPHID()))
|
|
|
|
->setWorkflow(true)
|
|
|
|
->setHref($this->getApplicationURI('empower/'.$user->getID().'/')));
|
|
|
|
|
2014-04-02 21:05:19 +02:00
|
|
|
$actions->addAction(
|
|
|
|
id(new PhabricatorActionView())
|
2014-05-12 19:08:32 +02:00
|
|
|
->setIcon('fa-tag')
|
2014-04-02 21:05:19 +02:00
|
|
|
->setName(pht('Change Username'))
|
|
|
|
->setWorkflow(true)
|
|
|
|
->setHref($this->getApplicationURI('rename/'.$user->getID().'/')));
|
|
|
|
|
2014-04-02 21:05:49 +02:00
|
|
|
if ($user->getIsDisabled()) {
|
2014-05-12 19:08:32 +02:00
|
|
|
$disable_icon = 'fa-check-circle-o';
|
2014-04-02 21:05:49 +02:00
|
|
|
$disable_name = pht('Enable User');
|
|
|
|
} else {
|
2014-05-12 19:08:32 +02:00
|
|
|
$disable_icon = 'fa-ban';
|
2014-04-02 21:05:49 +02:00
|
|
|
$disable_name = pht('Disable User');
|
|
|
|
}
|
|
|
|
|
|
|
|
$actions->addAction(
|
|
|
|
id(new PhabricatorActionView())
|
|
|
|
->setIcon($disable_icon)
|
|
|
|
->setName($disable_name)
|
|
|
|
->setDisabled(($user->getPHID() == $viewer->getPHID()))
|
|
|
|
->setWorkflow(true)
|
|
|
|
->setHref($this->getApplicationURI('disable/'.$user->getID().'/')));
|
|
|
|
|
2014-04-02 21:05:07 +02:00
|
|
|
$actions->addAction(
|
|
|
|
id(new PhabricatorActionView())
|
2014-05-12 19:08:32 +02:00
|
|
|
->setIcon('fa-times')
|
2014-04-02 21:05:07 +02:00
|
|
|
->setName(pht('Delete User'))
|
|
|
|
->setDisabled(($user->getPHID() == $viewer->getPHID()))
|
|
|
|
->setWorkflow(true)
|
|
|
|
->setHref($this->getApplicationURI('delete/'.$user->getID().'/')));
|
|
|
|
|
2013-07-10 01:23:45 +02:00
|
|
|
$actions->addAction(
|
|
|
|
id(new PhabricatorActionView())
|
2014-05-12 19:08:32 +02:00
|
|
|
->setIcon('fa-envelope')
|
2014-04-02 21:06:17 +02:00
|
|
|
->setName(pht('Send Welcome Email'))
|
|
|
|
->setWorkflow(true)
|
|
|
|
->setHref($this->getApplicationURI('welcome/'.$user->getID().'/')));
|
2012-01-17 01:54:05 +01:00
|
|
|
}
|
|
|
|
|
2013-10-11 16:53:56 +02:00
|
|
|
$properties = $this->buildPropertyView($user, $actions);
|
2015-02-02 21:13:48 +01:00
|
|
|
$name = $user->getUsername();
|
2013-07-10 14:09:59 +02:00
|
|
|
|
2013-07-10 14:11:08 +02:00
|
|
|
$crumbs = $this->buildApplicationCrumbs();
|
2015-02-02 21:13:48 +01:00
|
|
|
$crumbs->addTextCrumb($name);
|
|
|
|
|
2013-09-29 00:55:38 +02:00
|
|
|
$object_box = id(new PHUIObjectBoxView())
|
|
|
|
->setHeader($header)
|
2013-10-11 16:53:56 +02:00
|
|
|
->addPropertyList($properties);
|
2013-09-29 00:55:38 +02:00
|
|
|
|
[Redesign] People, Profile, Feed UI
Summary: Ref T8099, Mostly a Feed cleanup, removing old CSS, relying on modern display objects, adds back the feed to profile (I miss it, but maybe you don't).
Test Plan: Visit Feed on Profiles, Projects, Feed, and Dashboards. Same UI Everywhere. TODO, "Public Feed".
Reviewers: btrahan, epriestley
Reviewed By: epriestley
Subscribers: Korvin, epriestley
Maniphest Tasks: T8099
Differential Revision: https://secure.phabricator.com/D13101
2015-06-01 20:28:01 +02:00
|
|
|
$feed = id(new PHUIObjectBoxView())
|
|
|
|
->setHeaderText(pht('Recent Activity'))
|
|
|
|
->appendChild($this->buildPeopleFeed($user, $viewer));
|
|
|
|
|
2015-07-23 20:46:34 +02:00
|
|
|
$badges = $this->buildBadgesView($user);
|
|
|
|
|
2015-02-02 21:13:48 +01:00
|
|
|
$nav = $this->buildIconNavView($user);
|
|
|
|
$nav->selectFilter("{$name}/");
|
|
|
|
$nav->appendChild($object_box);
|
2015-07-23 20:46:34 +02:00
|
|
|
$nav->appendChild($badges);
|
[Redesign] People, Profile, Feed UI
Summary: Ref T8099, Mostly a Feed cleanup, removing old CSS, relying on modern display objects, adds back the feed to profile (I miss it, but maybe you don't).
Test Plan: Visit Feed on Profiles, Projects, Feed, and Dashboards. Same UI Everywhere. TODO, "Public Feed".
Reviewers: btrahan, epriestley
Reviewed By: epriestley
Subscribers: Korvin, epriestley
Maniphest Tasks: T8099
Differential Revision: https://secure.phabricator.com/D13101
2015-06-01 20:28:01 +02:00
|
|
|
$nav->appendChild($feed);
|
2015-02-02 21:13:48 +01:00
|
|
|
|
2012-08-14 00:27:21 +02:00
|
|
|
return $this->buildApplicationPage(
|
2015-02-26 19:27:28 +01:00
|
|
|
$nav,
|
2011-02-20 02:33:53 +01:00
|
|
|
array(
|
2011-06-18 10:13:56 +02:00
|
|
|
'title' => $user->getUsername(),
|
2011-02-20 02:33:53 +01:00
|
|
|
));
|
2011-06-18 10:13:56 +02:00
|
|
|
}
|
2011-02-20 02:33:53 +01:00
|
|
|
|
2013-10-11 16:53:56 +02:00
|
|
|
private function buildPropertyView(
|
|
|
|
PhabricatorUser $user,
|
|
|
|
PhabricatorActionListView $actions) {
|
2011-12-24 03:17:40 +01:00
|
|
|
|
2013-10-11 16:53:56 +02:00
|
|
|
$viewer = $this->getRequest()->getUser();
|
|
|
|
$view = id(new PHUIPropertyListView())
|
2013-07-10 14:09:59 +02:00
|
|
|
->setUser($viewer)
|
2013-10-11 16:53:56 +02:00
|
|
|
->setObject($user)
|
|
|
|
->setActionList($actions);
|
2011-02-20 03:28:41 +01:00
|
|
|
|
2013-08-14 18:40:42 +02:00
|
|
|
$field_list = PhabricatorCustomField::getObjectFields(
|
2013-07-10 14:09:59 +02:00
|
|
|
$user,
|
|
|
|
PhabricatorCustomField::ROLE_VIEW);
|
Support configuration-driven custom fields
Summary:
Ref T1702. Ref T3718. There are a couple of things going on here:
**PhabricatorCustomFieldList**: I added `PhabricatorCustomFieldList`, which is just a convenience class for dealing with lists of fields. Often, current field code does something like this inline in a Controller:
foreach ($fields as $field) {
// do some junk
}
Often, that junk has some slightly subtle implications. Move all of it to `$list->doSomeJunk()` methods (like `appendFieldsToForm()`, `loadFieldsFromStorage()`) to reduce code duplication and prevent errors. This additionally moves an existing list-convenience method there, out of `PhabricatorPropertyListView`.
**PhabricatorUserConfiguredCustomFieldStorage**: Adds `PhabricatorUserConfiguredCustomFieldStorage` for storing custom field data (like "ICQ Handle", "Phone Number", "Desk", "Favorite Flower", etc).
**Configuration-Driven Custom Fields**: Previously, I was thinking about doing these with interfaces, but as I thought about it more I started to dislike that approach. Instead, I built proxies into `PhabricatorCustomField`. Basically, this means that fields (like a custom, configuration-driven "Favorite Flower" field) can just use some other Field to actually provide their implementation (like a "standard" field which knows how to render text areas). The previous approach would have involed subclasssing the "standard" field and implementing an interface, but that would mean that every application would have at least two "base" fields and generally just seemed bleh as I worked through it.
The cost of this approach is that we need a bunch of `proxy` junk in the base class, but that's a one-time cost and I think it simplifies all the implementations and makes them a lot less magical (e.g., all of the custom fields now extend the right base field classes).
**Fixed Some Bugs**: Some of this code hadn't really been run yet and had minor bugs.
Test Plan:
{F54240}
{F54241}
{F54242}
Reviewers: btrahan
Reviewed By: btrahan
CC: aran
Maniphest Tasks: T1702, T1703, T3718
Differential Revision: https://secure.phabricator.com/D6749
2013-08-14 17:10:16 +02:00
|
|
|
$field_list->appendFieldsToPropertyList($user, $viewer, $view);
|
2013-07-10 14:09:59 +02:00
|
|
|
|
|
|
|
return $view;
|
2011-12-24 03:17:40 +01:00
|
|
|
}
|
|
|
|
|
2015-07-23 20:46:34 +02:00
|
|
|
private function buildBadgesView(
|
|
|
|
PhabricatorUser $user) {
|
|
|
|
|
|
|
|
$viewer = $this->getViewer();
|
|
|
|
$class = 'PhabricatorBadgesApplication';
|
|
|
|
$box = null;
|
|
|
|
|
|
|
|
if (PhabricatorApplication::isClassInstalledForViewer($class, $viewer)) {
|
|
|
|
$badge_phids = $user->getBadgePHIDs();
|
|
|
|
if ($badge_phids) {
|
|
|
|
$badges = id(new PhabricatorBadgesQuery())
|
|
|
|
->setViewer($viewer)
|
|
|
|
->withPHIDs($badge_phids)
|
|
|
|
->execute();
|
|
|
|
|
|
|
|
$flex = new PHUIBadgeBoxView();
|
|
|
|
foreach ($badges as $badge) {
|
|
|
|
$item = id(new PHUIBadgeView())
|
|
|
|
->setIcon($badge->getIcon())
|
|
|
|
->setHeader($badge->getName())
|
|
|
|
->setSubhead($badge->getFlavor())
|
|
|
|
->setQuality($badge->getQuality());
|
|
|
|
$flex->addItem($item);
|
|
|
|
}
|
|
|
|
|
|
|
|
$box = id(new PHUIObjectBoxView())
|
|
|
|
->setHeaderText(pht('Badges'))
|
|
|
|
->appendChild($flex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $box;
|
|
|
|
}
|
|
|
|
|
[Redesign] People, Profile, Feed UI
Summary: Ref T8099, Mostly a Feed cleanup, removing old CSS, relying on modern display objects, adds back the feed to profile (I miss it, but maybe you don't).
Test Plan: Visit Feed on Profiles, Projects, Feed, and Dashboards. Same UI Everywhere. TODO, "Public Feed".
Reviewers: btrahan, epriestley
Reviewed By: epriestley
Subscribers: Korvin, epriestley
Maniphest Tasks: T8099
Differential Revision: https://secure.phabricator.com/D13101
2015-06-01 20:28:01 +02:00
|
|
|
private function buildPeopleFeed(
|
|
|
|
PhabricatorUser $user,
|
|
|
|
$viewer) {
|
|
|
|
|
|
|
|
$query = new PhabricatorFeedQuery();
|
|
|
|
$query->setFilterPHIDs(
|
|
|
|
array(
|
|
|
|
$user->getPHID(),
|
|
|
|
));
|
|
|
|
$query->setLimit(100);
|
|
|
|
$query->setViewer($viewer);
|
|
|
|
$stories = $query->execute();
|
|
|
|
|
|
|
|
$builder = new PhabricatorFeedBuilder($stories);
|
|
|
|
$builder->setUser($viewer);
|
|
|
|
$builder->setShowHovercards(true);
|
|
|
|
$builder->setNoDataString(pht('To begin on such a grand journey, '.
|
|
|
|
'requires but just a single step.'));
|
|
|
|
$view = $builder->buildView();
|
|
|
|
|
|
|
|
return phutil_tag_div('phabricator-project-feed', $view->render());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2011-01-24 03:09:16 +01:00
|
|
|
}
|