Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2893940
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Advanced/Developer...
View Handle
View Hovercard
Size
45 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php
index f80ad75057..ff0f1cb83e 100644
--- a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php
+++ b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php
@@ -1,625 +1,626 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @group aphront
*/
class AphrontDefaultApplicationConfiguration
extends AphrontApplicationConfiguration {
public function __construct() {
}
public function getApplicationName() {
return 'aphront-default';
}
public function getURIMap() {
return $this->getResourceURIMapRules() + array(
'/(?:(?P<filter>jump)/)?' =>
'PhabricatorDirectoryMainController',
'/(?:(?P<filter>feed)/)' => array(
'public/' => 'PhabricatorFeedPublicStreamController',
'(?:(?P<subfilter>[^/]+)/)?' =>
'PhabricatorDirectoryMainController',
),
'/directory/' => array(
'(?P<id>\d+)/'
=> 'PhabricatorDirectoryCategoryViewController',
'edit/'
=> 'PhabricatorDirectoryEditController',
'item/edit/(?:(?P<id>\d+)/)?'
=> 'PhabricatorDirectoryItemEditController',
'item/delete/(?P<id>\d+)/'
=> 'PhabricatorDirectoryItemDeleteController',
'category/edit/(?:(?P<id>\d+)/)?'
=> 'PhabricatorDirectoryCategoryEditController',
'category/delete/(?P<id>\d+)/'
=> 'PhabricatorDirectoryCategoryDeleteController',
),
'/file/' => array(
'' => 'PhabricatorFileListController',
'filter/(?P<filter>\w+)/' => 'PhabricatorFileListController',
'upload/' => 'PhabricatorFileUploadController',
'dropupload/' => 'PhabricatorFileDropUploadController',
'delete/(?P<id>\d+)/' => 'PhabricatorFileDeleteController',
'info/(?P<phid>[^/]+)/' => 'PhabricatorFileInfoController',
'data/(?P<key>[^/]+)/(?P<phid>[^/]+)/.*'
=> 'PhabricatorFileDataController',
// TODO: This is a deprecated version of /data/. Remove it after
// old links have had a chance to rot.
'alt/(?P<key>[^/]+)/(?P<phid>[^/]+)/'
=> 'PhabricatorFileDataController',
'macro/' => array(
'' => 'PhabricatorFileMacroListController',
'edit/(?:(?P<id>\d+)/)?' => 'PhabricatorFileMacroEditController',
'delete/(?P<id>\d+)/' => 'PhabricatorFileMacroDeleteController',
),
'proxy/' => 'PhabricatorFileProxyController',
'xform/(?P<transform>[^/]+)/(?P<phid>[^/]+)/'
=> 'PhabricatorFileTransformController',
),
'/phid/' => array(
'' => 'PhabricatorPHIDLookupController',
),
'/people/' => array(
'' => 'PhabricatorPeopleListController',
'logs/' => 'PhabricatorPeopleLogsController',
'edit/(?:(?P<id>\d+)/(?:(?P<view>\w+)/)?)?'
=> 'PhabricatorPeopleEditController',
),
'/p/(?P<username>\w+)/(?:(?P<page>\w+)/)?'
=> 'PhabricatorPeopleProfileController',
'/conduit/' => array(
'' => 'PhabricatorConduitConsoleController',
'method/(?P<method>[^/]+)/' => 'PhabricatorConduitConsoleController',
'log/' => 'PhabricatorConduitLogController',
'log/view/(?P<view>[^/]+)/' => 'PhabricatorConduitLogController',
'token/' => 'PhabricatorConduitTokenController',
),
'/api/(?P<method>[^/]+)' => 'PhabricatorConduitAPIController',
'/D(?P<id>\d+)' => 'DifferentialRevisionViewController',
'/differential/' => array(
'' => 'DifferentialRevisionListController',
- 'filter/(?P<filter>\w+)/' => 'DifferentialRevisionListController',
+ 'filter/(?P<filter>\w+)/(?:(?P<username>\w+)/)?' =>
+ 'DifferentialRevisionListController',
'stats/(?P<filter>\w+)/' => 'DifferentialRevisionStatsController',
'diff/' => array(
'(?P<id>\d+)/' => 'DifferentialDiffViewController',
'create/' => 'DifferentialDiffCreateController',
),
'changeset/' => 'DifferentialChangesetViewController',
'revision/edit/(?:(?P<id>\d+)/)?'
=> 'DifferentialRevisionEditController',
'comment/' => array(
'preview/(?P<id>\d+)/' => 'DifferentialCommentPreviewController',
'save/' => 'DifferentialCommentSaveController',
'inline/' => array(
'preview/(?P<id>\d+)/' =>
'DifferentialInlineCommentPreviewController',
'edit/(?P<id>\d+)/' => 'DifferentialInlineCommentEditController',
),
),
'subscribe/(?P<action>add|rem)/(?P<id>\d+)/'
=> 'DifferentialSubscribeController',
),
'/typeahead/' => array(
'common/(?P<type>\w+)/'
=> 'PhabricatorTypeaheadCommonDatasourceController',
),
'/mail/' => array(
'' => 'PhabricatorMetaMTAListController',
'send/' => 'PhabricatorMetaMTASendController',
'view/(?P<id>\d+)/' => 'PhabricatorMetaMTAViewController',
'lists/' => 'PhabricatorMetaMTAMailingListsController',
'lists/edit/(?:(?P<id>\d+)/)?'
=> 'PhabricatorMetaMTAMailingListEditController',
'receive/' => 'PhabricatorMetaMTAReceiveController',
'received/' => 'PhabricatorMetaMTAReceivedListController',
'sendgrid/' => 'PhabricatorMetaMTASendGridReceiveController',
),
'/login/' => array(
'' => 'PhabricatorLoginController',
'email/' => 'PhabricatorEmailLoginController',
'etoken/(?P<token>\w+)/' => 'PhabricatorEmailTokenController',
'refresh/' => 'PhabricatorRefreshCSRFController',
'validate/' => 'PhabricatorLoginValidateController',
),
'/logout/' => 'PhabricatorLogoutController',
'/oauth/' => array(
'(?P<provider>\w+)/' => array(
'login/' => 'PhabricatorOAuthLoginController',
'diagnose/' => 'PhabricatorOAuthDiagnosticsController',
'unlink/' => 'PhabricatorOAuthUnlinkController',
),
),
'/oauthserver/' => array(
'auth/' => 'PhabricatorOAuthServerAuthController',
'test/' => 'PhabricatorOAuthServerTestController',
'token/' => 'PhabricatorOAuthServerTokenController',
'clientauthorization/' => array(
'' => 'PhabricatorOAuthClientAuthorizationListController',
'delete/(?P<phid>[^/]+)/' =>
'PhabricatorOAuthClientAuthorizationDeleteController',
'edit/(?P<phid>[^/]+)/' =>
'PhabricatorOAuthClientAuthorizationEditController',
),
'client/' => array(
'' => 'PhabricatorOAuthClientListController',
'create/' => 'PhabricatorOAuthClientEditController',
'delete/(?P<phid>[^/]+)/' => 'PhabricatorOAuthClientDeleteController',
'edit/(?P<phid>[^/]+)/' => 'PhabricatorOAuthClientEditController',
'view/(?P<phid>[^/]+)/' => 'PhabricatorOAuthClientViewController',
),
),
'/xhprof/' => array(
'profile/(?P<phid>[^/]+)/' => 'PhabricatorXHProfProfileController',
),
'/~/' => 'DarkConsoleController',
'/settings/' => array(
'(?:page/(?P<page>[^/]+)/)?' => 'PhabricatorUserSettingsController',
),
'/maniphest/' => array(
'' => 'ManiphestTaskListController',
'view/(?P<view>\w+)/' => 'ManiphestTaskListController',
'report/(?:(?P<view>\w+)/)?' => 'ManiphestReportController',
'batch/' => 'ManiphestBatchEditController',
'task/' => array(
'create/' => 'ManiphestTaskEditController',
'edit/(?P<id>\d+)/' => 'ManiphestTaskEditController',
'descriptionchange/(?P<id>\d+)/' =>
'ManiphestTaskDescriptionChangeController',
'descriptiondiff/' =>
'ManiphestTaskDescriptionDiffController',
'descriptionpreview/' =>
'ManiphestTaskDescriptionPreviewController',
),
'transaction/' => array(
'save/' => 'ManiphestTransactionSaveController',
'preview/(?P<id>\d+)/' => 'ManiphestTransactionPreviewController',
),
'export/(?P<key>[^/]+)/' => 'ManiphestExportController',
),
'/T(?P<id>\d+)' => 'ManiphestTaskDetailController',
'/repository/' => array(
'' => 'PhabricatorRepositoryListController',
'create/' => 'PhabricatorRepositoryCreateController',
'edit/(?P<id>\d+)/(?:(?P<view>\w+)?/)?' =>
'PhabricatorRepositoryEditController',
'delete/(?P<id>\d+)/' => 'PhabricatorRepositoryDeleteController',
'project/(?P<id>\d+)/' =>
'PhabricatorRepositoryArcanistProjectEditController',
),
'/search/' => array(
'' => 'PhabricatorSearchController',
'(?P<key>[^/]+)/' => 'PhabricatorSearchController',
'attach/(?P<phid>[^/]+)/(?P<type>\w+)/(?:(?P<action>\w+)/)?'
=> 'PhabricatorSearchAttachController',
'select/(?P<type>\w+)/'
=> 'PhabricatorSearchSelectController',
'index/(?P<phid>[^/]+)/' => 'PhabricatorSearchIndexController',
),
'/project/' => array(
'' => 'PhabricatorProjectListController',
'filter/(?P<filter>[^/]+)/' => 'PhabricatorProjectListController',
'edit/(?P<id>\d+)/' => 'PhabricatorProjectProfileEditController',
'view/(?P<id>\d+)/(?:(?P<page>\w+)/)?'
=> 'PhabricatorProjectProfileController',
'create/' => 'PhabricatorProjectCreateController',
'update/(?P<id>\d+)/(?P<action>[^/]+)/'
=> 'PhabricatorProjectUpdateController',
),
'/r(?P<callsign>[A-Z]+)(?P<commit>[a-z0-9]+)'
=> 'DiffusionCommitController',
'/diffusion/' => array(
'' => 'DiffusionHomeController',
'(?P<callsign>[A-Z]+)/' => array(
'' => 'DiffusionRepositoryController',
'repository/'.
'(?P<path>[^/]+)/'
=> 'DiffusionRepositoryController',
'change/'.
'(?P<path>.*?)'.
'(?:[;](?P<commit>[a-z0-9]+))?'
=> 'DiffusionChangeController',
'history/'.
'(?P<path>.*?)'.
'(?:[;](?P<commit>[a-z0-9]+))?'
=> 'DiffusionHistoryController',
'browse/'.
'(?P<path>.*?)'.
'(?:[;](?P<commit>[a-z0-9]+))?'.
'(?:[$](?P<line>\d+(?:-\d+)?))?'
=> 'DiffusionBrowseController',
'diff/'.
'(?P<path>.*?)'.
'(?:[;](?P<commit>[a-z0-9]+))?'
=> 'DiffusionDiffController',
'lastmodified/'.
'(?P<path>.*?)'.
'(?:[;](?P<commit>[a-z0-9]+))?'
=> 'DiffusionLastModifiedController',
),
'services/' => array(
'path/' => array(
'complete/' => 'DiffusionPathCompleteController',
'validate/' => 'DiffusionPathValidateController',
),
),
'symbol/(?P<name>[^/]+)/' => 'DiffusionSymbolController',
),
'/daemon/' => array(
'task/(?P<id>\d+)/' => 'PhabricatorWorkerTaskDetailController',
'task/(?P<id>\d+)/(?P<action>[^/]+)/'
=> 'PhabricatorWorkerTaskUpdateController',
'log/' => array(
'' => 'PhabricatorDaemonLogListController',
'combined/' => 'PhabricatorDaemonCombinedLogController',
'(?P<id>\d+)/' => 'PhabricatorDaemonLogViewController',
),
'timeline/' => 'PhabricatorDaemonTimelineConsoleController',
'timeline/(?P<id>\d+)/' => 'PhabricatorDaemonTimelineEventController',
'' => 'PhabricatorDaemonConsoleController',
),
'/herald/' => array(
'' => 'HeraldHomeController',
'view/(?P<view>[^/]+)/' => array(
'' => 'HeraldHomeController',
'(?P<global>global)/' => 'HeraldHomeController'
),
'new/(?:(?P<type>[^/]+)/)?' => 'HeraldNewController',
'rule/(?:(?P<id>\d+)/)?' => 'HeraldRuleController',
'history/(?P<id>\d+)/' => 'HeraldRuleEditHistoryController',
'delete/(?P<id>\d+)/' => 'HeraldDeleteController',
'test/' => 'HeraldTestConsoleController',
'all/' => array(
'' => 'HeraldAllRulesController',
'view/(?P<view>[^/]+)/' => 'HeraldAllRulesController',
),
'transcript/' => 'HeraldTranscriptListController',
'transcript/(?P<id>\d+)/(?:(?P<filter>\w+)/)?'
=> 'HeraldTranscriptController',
),
'/uiexample/' => array(
'' => 'PhabricatorUIExampleRenderController',
'view/(?P<class>[^/]+)/' => 'PhabricatorUIExampleRenderController',
),
'/owners/' => array(
'' => 'PhabricatorOwnersListController',
'view/(?P<view>[^/]+)/' => 'PhabricatorOwnersListController',
'edit/(?P<id>\d+)/' => 'PhabricatorOwnersEditController',
'new/' => 'PhabricatorOwnersEditController',
'package/(?P<id>\d+)/' => 'PhabricatorOwnersDetailController',
'delete/(?P<id>\d+)/' => 'PhabricatorOwnersDeleteController',
),
'/audit/' => array(
'' => 'PhabricatorAuditListController',
'view/(?P<filter>[^/]+)/(?:(?P<name>[^/]+)/)?'
=> 'PhabricatorAuditListController',
'addcomment/' => 'PhabricatorAuditAddCommentController',
'preview/(?P<id>\d+)/' => 'PhabricatorAuditPreviewController',
),
'/xhpast/' => array(
'' => 'PhabricatorXHPASTViewRunController',
'view/(?P<id>\d+)/'
=> 'PhabricatorXHPASTViewFrameController',
'frameset/(?P<id>\d+)/'
=> 'PhabricatorXHPASTViewFramesetController',
'input/(?P<id>\d+)/'
=> 'PhabricatorXHPASTViewInputController',
'tree/(?P<id>\d+)/'
=> 'PhabricatorXHPASTViewTreeController',
'stream/(?P<id>\d+)/'
=> 'PhabricatorXHPASTViewStreamController',
),
'/status/' => 'PhabricatorStatusController',
'/paste/' => array(
'' => 'PhabricatorPasteListController',
'filter/(?P<filter>\w+)/' => 'PhabricatorPasteListController',
),
'/P(?P<id>\d+)' => 'PhabricatorPasteViewController',
'/help/' => array(
'keyboardshortcut/' => 'PhabricatorHelpKeyboardShortcutController',
),
'/countdown/' => array(
''
=> 'PhabricatorCountdownListController',
'(?P<id>\d+)/'
=> 'PhabricatorCountdownViewController',
'edit/(?:(?P<id>\d+)/)?'
=> 'PhabricatorCountdownEditController',
'delete/(?P<id>\d+)/'
=> 'PhabricatorCountdownDeleteController'
),
'/V(?P<id>\d+)' => 'PhabricatorSlowvotePollController',
'/vote/' => array(
'(?:view/(?P<view>\w+)/)?' => 'PhabricatorSlowvoteListController',
'create/' => 'PhabricatorSlowvoteCreateController',
),
// Match "/w/" with slug "/".
'/w(?P<slug>/)' => 'PhrictionDocumentController',
// Match "/w/x/y/z/" with slug "x/y/z/".
'/w/(?P<slug>.+/)' => 'PhrictionDocumentController',
'/phriction/' => array(
'' => 'PhrictionListController',
'list/(?P<view>[^/]+)/' => 'PhrictionListController',
'history(?P<slug>/)' => 'PhrictionHistoryController',
'history/(?P<slug>.+/)' => 'PhrictionHistoryController',
'edit/(?:(?P<id>\d+)/)?' => 'PhrictionEditController',
'delete/(?P<id>\d+)/' => 'PhrictionDeleteController',
'preview/' => 'PhrictionDocumentPreviewController',
'diff/(?P<id>\d+)/' => 'PhrictionDiffController',
),
'/calendar/' => array(
'' => 'PhabricatorCalendarBrowseController',
),
'/drydock/' => array(
'' => 'DrydockResourceListController',
'resource/' => 'DrydockResourceListController',
'resource/allocate/' => 'DrydockResourceAllocateController',
'host/' => array(
'' => 'DrydockHostListController',
'edit/' => 'DrydockHostEditController',
'edit/(?P<id>\d+)/' => 'DrydockhostEditController',
),
'lease/' => 'DrydockLeaseListController',
),
'/chatlog/' => array(
'' =>
'PhabricatorChatLogChannelListController',
'channel/(?P<channel>[^/]+)/' =>
'PhabricatorChatLogChannelLogController',
),
);
}
protected function getResourceURIMapRules() {
return array(
'/res/' => array(
'(?P<package>pkg/)?(?P<hash>[a-f0-9]{8})/(?P<path>.+\.(?:css|js))'
=> 'CelerityResourceController',
),
);
}
public function buildRequest() {
$request = new AphrontRequest($this->getHost(), $this->getPath());
$request->setRequestData($_GET + $_POST);
$request->setApplicationConfiguration($this);
return $request;
}
public function handleException(Exception $ex) {
// Always log the unhandled exception.
phlog($ex);
$class = phutil_escape_html(get_class($ex));
$message = phutil_escape_html($ex->getMessage());
if (PhabricatorEnv::getEnvConfig('phabricator.show-stack-traces')) {
$trace = $this->renderStackTrace($ex->getTrace());
} else {
$trace = null;
}
$content =
'<div class="aphront-unhandled-exception">'.
'<div class="exception-message">'.$message.'</div>'.
$trace.
'</div>';
$user = $this->getRequest()->getUser();
if (!$user) {
// If we hit an exception very early, we won't have a user.
$user = new PhabricatorUser();
}
$dialog = new AphrontDialogView();
$dialog
->setTitle('Unhandled Exception ("'.$class.'")')
->setClass('aphront-exception-dialog')
->setUser($user)
->appendChild($content);
if ($this->getRequest()->isAjax()) {
$dialog->addCancelButton('/', 'Close');
}
$response = new AphrontDialogResponse();
$response->setDialog($dialog);
return $response;
}
public function willSendResponse(AphrontResponse $response) {
$request = $this->getRequest();
$response->setRequest($request);
if ($response instanceof AphrontDialogResponse) {
if (!$request->isAjax()) {
$view = new PhabricatorStandardPageView();
$view->setRequest($request);
$view->appendChild(
'<div style="padding: 2em 0;">'.
$response->buildResponseString().
'</div>');
$response = new AphrontWebpageResponse();
$response->setContent($view->render());
return $response;
} else {
return id(new AphrontAjaxResponse())
->setContent(array(
'dialog' => $response->buildResponseString(),
));
}
} else if ($response instanceof AphrontRedirectResponse) {
if ($request->isAjax()) {
return id(new AphrontAjaxResponse())
->setContent(
array(
'redirect' => $response->getURI(),
));
}
}
return $response;
}
public function build404Controller() {
return array(new Phabricator404Controller($this->getRequest()), array());
}
public function buildRedirectController($uri) {
return array(
new PhabricatorRedirectController($this->getRequest()),
array(
'uri' => $uri,
));
}
private function renderStackTrace($trace) {
$libraries = PhutilBootloader::getInstance()->getAllLibraries();
// TODO: Make this configurable?
$host = 'https://secure.phabricator.com';
$browse = array(
'arcanist' =>
$host.'/diffusion/ARC/browse/origin:master/src/',
'phutil' =>
$host.'/diffusion/PHU/browse/origin:master/src/',
'phabricator' =>
$host.'/diffusion/P/browse/origin:master/src/',
);
$rows = array();
$depth = count($trace);
foreach ($trace as $part) {
$lib = null;
$file = idx($part, 'file');
$relative = $file;
foreach ($libraries as $library) {
$root = phutil_get_library_root($library);
if (Filesystem::isDescendant($file, $root)) {
$lib = $library;
$relative = Filesystem::readablePath($file, $root);
break;
}
}
$where = '';
if (isset($part['class'])) {
$where .= $part['class'].'::';
}
if (isset($part['function'])) {
$where .= $part['function'].'()';
}
if ($file) {
if (isset($browse[$lib])) {
$file_name = phutil_render_tag(
'a',
array(
'href' => $browse[$lib].$relative.'$'.$part['line'],
'title' => $file,
'target' => '_blank',
),
phutil_escape_html($relative));
} else {
$file_name = phutil_render_tag(
'span',
array(
'title' => $file,
),
phutil_escape_html($relative));
}
$file_name = $file_name.' : '.(int)$part['line'];
} else {
$file_name = '<em>(Internal)</em>';
}
$rows[] = array(
$depth--,
phutil_escape_html($lib),
$file_name,
phutil_escape_html($where),
);
}
$table = new AphrontTableView($rows);
$table->setHeaders(
array(
'Depth',
'Library',
'File',
'Where',
));
$table->setColumnClasses(
array(
'n',
'',
'',
'wide',
));
return
'<div class="exception-trace">'.
'<div class="exception-trace-header">Stack Trace</div>'.
$table->render().
'</div>';
}
}
diff --git a/src/applications/differential/controller/revisionlist/DifferentialRevisionListController.php b/src/applications/differential/controller/revisionlist/DifferentialRevisionListController.php
index f48e260b89..4fb04347f5 100644
--- a/src/applications/differential/controller/revisionlist/DifferentialRevisionListController.php
+++ b/src/applications/differential/controller/revisionlist/DifferentialRevisionListController.php
@@ -1,420 +1,438 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class DifferentialRevisionListController extends DifferentialController {
private $filter;
+ private $username;
public function shouldRequireLogin() {
return !$this->allowsAnonymousAccess();
}
public function willProcessRequest(array $data) {
$this->filter = idx($data, 'filter');
+ $this->username = idx($data, 'username');
}
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
$viewer_is_anonymous = !$user->isLoggedIn();
- $phid_arr = $request->getArr('view_user');
- if ($phid_arr) {
- $view_target = head($phid_arr);
- return id(new AphrontRedirectResponse())
- ->setURI($request->getRequestURI()
- ->alter('phid', $view_target)
- ->setQueryParam('view_user', null));
- }
-
$params = array_filter(
array(
- 'phid' => $request->getStr('phid'),
'status' => $request->getStr('status'),
'order' => $request->getStr('order'),
));
$default_filter = ($viewer_is_anonymous ? 'all' : 'active');
$filters = $this->getFilters();
$this->filter = $this->selectFilter(
$filters,
$this->filter,
$default_filter);
+ // Redirect from search to canonical URL.
+ $phid_arr = $request->getArr('view_user');
+ if ($phid_arr) {
+ $view_user = id(new PhabricatorUser())
+ ->loadOneWhere('phid = %s', head($phid_arr));
+ if (!$view_user) {
+ return new Aphront404Response();
+ }
+ $uri = id(new PhutilURI('/differential/filter/'.$this->filter.'/'.
+ phutil_escape_uri($view_user->getUserName()).'/'))
+ ->setQueryParams($params);
+ return id(new AphrontRedirectResponse())->setURI($uri);
+ }
+
$uri = new PhutilURI('/differential/filter/'.$this->filter.'/');
$uri->setQueryParams($params);
+ $username = '';
+ if ($this->username) {
+ $view_user = id(new PhabricatorUser())
+ ->loadOneWhere('userName = %s', $this->username);
+ if (!$view_user) {
+ return new Aphront404Response();
+ }
+ $username = phutil_escape_uri($this->username).'/';
+ $uri->setPath('/differential/filter/'.$this->filter.'/'.$username);
+ $params['phid'] = $view_user->getPHID();
+ }
+
// Fill in the defaults we'll actually use for calculations if any
// parameters are missing.
$params += array(
'phid' => $user->getPHID(),
'status' => 'all',
'order' => 'modified',
);
$side_nav = new AphrontSideNavView();
foreach ($filters as $filter) {
list($filter_name, $display_name) = $filter;
if ($filter_name) {
$href = clone $uri;
- $href->setPath('/differential/filter/'.$filter_name.'/');
+ $href->setPath('/differential/filter/'.$filter_name.'/'.$username);
if ($filter_name == $this->filter) {
$class = 'aphront-side-nav-selected';
} else {
$class = null;
}
$item = phutil_render_tag(
'a',
array(
'href' => (string)$href,
'class' => $class,
),
phutil_escape_html($display_name));
} else {
$item = phutil_render_tag(
'span',
array(),
phutil_escape_html($display_name));
}
$side_nav->addNavItem($item);
}
$panels = array();
$handles = array();
$controls = $this->getFilterControls($this->filter);
if ($this->getFilterRequiresUser($this->filter) && !$params['phid']) {
// In the anonymous case, we still want to let you see some user's
// list, but we don't have a default PHID to provide (normally, we use
// the viewing user's). Show a warning instead.
$warning = new AphrontErrorView();
$warning->setSeverity(AphrontErrorView::SEVERITY_WARNING);
$warning->setTitle('User Required');
$warning->appendChild(
'This filter requires that a user be specified above.');
$panels[] = $warning;
} else {
$query = $this->buildQuery($this->filter, $params['phid']);
$pager = null;
if ($this->getFilterAllowsPaging($this->filter)) {
$pager = new AphrontPagerView();
$pager->setOffset($request->getInt('page'));
$pager->setPageSize(1000);
$pager->setURI($uri, 'page');
$query->setOffset($pager->getOffset());
$query->setLimit($pager->getPageSize() + 1);
}
foreach ($controls as $control) {
$this->applyControlToQuery($control, $query, $params);
}
$revisions = $query->execute();
if ($pager) {
$revisions = $pager->sliceResults($revisions);
}
$views = $this->buildViews($this->filter, $params['phid'], $revisions);
$view_objects = ipull($views, 'view');
$phids = array_mergev(mpull($view_objects, 'getRequiredHandlePHIDs'));
$phids[] = $params['phid'];
$handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
foreach ($views as $view) {
$view['view']->setHandles($handles);
$panel = new AphrontPanelView();
$panel->setHeader($view['title']);
$panel->appendChild($view['view']);
if ($pager) {
$panel->appendChild($pager);
}
$panels[] = $panel;
}
}
$filter_form = id(new AphrontFormView())
->setMethod('GET')
->setAction('/differential/filter/'.$this->filter.'/')
->setUser($user);
foreach ($controls as $control) {
$control_view = $this->renderControl($control, $handles, $uri, $params);
$filter_form->appendChild($control_view);
}
$filter_form
->addHiddenInput('status', $params['status'])
->addHiddenInput('order', $params['order'])
->appendChild(
id(new AphrontFormSubmitControl())
->setValue('Filter Revisions'));
$filter_view = new AphrontListFilterView();
$filter_view->appendChild($filter_form);
if (!$viewer_is_anonymous) {
$create_uri = new PhutilURI('/differential/diff/create/');
$filter_view->addButton(
phutil_render_tag(
'a',
array(
'href' => (string)$create_uri,
'class' => 'green button',
),
'Create Revision'));
}
$side_nav->appendChild($filter_view);
foreach ($panels as $panel) {
$side_nav->appendChild($panel);
}
return $this->buildStandardPageResponse(
$side_nav,
array(
'title' => 'Differential Home',
'tab' => 'revisions',
));
}
private function getFilters() {
return array(
array(null, 'User Revisions'),
array('active', 'Active'),
array('revisions', 'Revisions'),
array('reviews', 'Reviews'),
array('subscribed', 'Subscribed'),
array(null, 'All Revisions'),
array('all', 'All'),
);
}
private function selectFilter(
array $filters,
$requested_filter,
$default_filter) {
// If the user requested a filter, make sure it actually exists.
if ($requested_filter) {
foreach ($filters as $filter) {
if ($filter[0] === $requested_filter) {
return $requested_filter;
}
}
}
// If not, return the default filter.
return $default_filter;
}
private function getFilterRequiresUser($filter) {
static $requires = array(
'active' => true,
'revisions' => true,
'reviews' => true,
'subscribed' => true,
'all' => false,
);
if (!isset($requires[$filter])) {
throw new Exception("Unknown filter '{$filter}'!");
}
return $requires[$filter];
}
private function getFilterAllowsPaging($filter) {
static $allows = array(
'active' => false,
'revisions' => true,
'reviews' => true,
'subscribed' => true,
'all' => true,
);
if (!isset($allows[$filter])) {
throw new Exception("Unknown filter '{$filter}'!");
}
return $allows[$filter];
}
private function getFilterControls($filter) {
static $controls = array(
'active' => array('phid'),
'revisions' => array('phid', 'status', 'order'),
'reviews' => array('phid', 'status', 'order'),
'subscribed' => array('phid', 'status', 'order'),
'all' => array('status', 'order'),
);
if (!isset($controls[$filter])) {
throw new Exception("Unknown filter '{$filter}'!");
}
return $controls[$filter];
}
private function buildQuery($filter, $user_phid) {
$query = new DifferentialRevisionQuery();
$query->needRelationships(true);
switch ($filter) {
case 'active':
$query->withResponsibleUsers(array($user_phid));
$query->withStatus(DifferentialRevisionQuery::STATUS_OPEN);
$query->setLimit(null);
break;
case 'revisions':
$query->withAuthors(array($user_phid));
break;
case 'reviews':
$query->withReviewers(array($user_phid));
break;
case 'subscribed':
$query->withSubscribers(array($user_phid));
break;
case 'all':
break;
default:
throw new Exception("Unknown filter '{$filter}'!");
}
return $query;
}
private function renderControl(
$control,
array $handles,
PhutilURI $uri,
array $params) {
switch ($control) {
case 'phid':
$view_phid = $params['phid'];
$value = array();
if ($view_phid) {
$value = array(
$view_phid => $handles[$view_phid]->getFullName(),
);
}
return id(new AphrontFormTokenizerControl())
->setDatasource('/typeahead/common/users/')
->setLabel('View User')
->setName('view_user')
->setValue($value)
->setLimit(1);
case 'status':
return id(new AphrontFormToggleButtonsControl())
->setLabel('Status')
->setValue($params['status'])
->setBaseURI($uri, 'status')
->setButtons(
array(
'all' => 'All',
'open' => 'Open',
'committed' => 'Committed',
));
case 'order':
return id(new AphrontFormToggleButtonsControl())
->setLabel('Order')
->setValue($params['order'])
->setBaseURI($uri, 'order')
->setButtons(
array(
'modified' => 'Updated',
'created' => 'Created',
));
default:
throw new Exception("Unknown control '{$control}'!");
}
}
private function applyControlToQuery($control, $query, array $params) {
switch ($control) {
case 'phid':
// Already applied by query construction.
break;
case 'status':
if ($params['status'] == 'open') {
$query->withStatus(DifferentialRevisionQuery::STATUS_OPEN);
} elseif ($params['status'] == 'committed') {
$query->withStatus(DifferentialRevisionQuery::STATUS_COMMITTED);
}
break;
case 'order':
if ($params['order'] == 'created') {
$query->setOrder(DifferentialRevisionQuery::ORDER_CREATED);
}
break;
default:
throw new Exception("Unknown control '{$control}'!");
}
}
private function buildViews($filter, $user_phid, array $revisions) {
$user = $this->getRequest()->getUser();
$template = id(new DifferentialRevisionListView())
->setUser($user)
->setFields(DifferentialRevisionListView::getDefaultFields());
$views = array();
switch ($filter) {
case 'active':
list($active, $waiting) = DifferentialRevisionQuery::splitResponsible(
$revisions,
$user_phid);
$view = id(clone $template)
->setRevisions($active)
->setNoDataString("You have no active revisions requiring action.");
$views[] = array(
'title' => 'Action Required',
'view' => $view,
);
$view = id(clone $template)
->setRevisions($waiting)
->setNoDataString("You have no active revisions waiting on others.");
$views[] = array(
'title' => 'Waiting On Others',
'view' => $view,
);
break;
case 'revisions':
case 'reviews':
case 'subscribed':
case 'all':
$titles = array(
'revisions' => 'Revisions by Author',
'reviews' => 'Revisions by Reviewer',
'subscribed' => 'Revisions by Subscriber',
'all' => 'Revisions',
);
$view = id(clone $template)
->setRevisions($revisions);
$views[] = array(
'title' => idx($titles, $filter),
'view' => $view,
);
break;
default:
throw new Exception("Unknown filter '{$filter}'!");
}
return $views;
}
}
diff --git a/src/applications/differential/controller/revisionlist/__init__.php b/src/applications/differential/controller/revisionlist/__init__.php
index a0972ce79f..202761bb78 100644
--- a/src/applications/differential/controller/revisionlist/__init__.php
+++ b/src/applications/differential/controller/revisionlist/__init__.php
@@ -1,29 +1,31 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
+phutil_require_module('phabricator', 'aphront/response/404');
phutil_require_module('phabricator', 'aphront/response/redirect');
phutil_require_module('phabricator', 'applications/differential/controller/base');
phutil_require_module('phabricator', 'applications/differential/query/revision');
phutil_require_module('phabricator', 'applications/differential/view/revisionlist');
+phutil_require_module('phabricator', 'applications/people/storage/user');
phutil_require_module('phabricator', 'applications/phid/handle/data');
phutil_require_module('phabricator', 'view/control/pager');
phutil_require_module('phabricator', 'view/form/base');
phutil_require_module('phabricator', 'view/form/control/submit');
phutil_require_module('phabricator', 'view/form/control/togglebuttons');
phutil_require_module('phabricator', 'view/form/control/tokenizer');
phutil_require_module('phabricator', 'view/form/error');
phutil_require_module('phabricator', 'view/layout/listfilter');
phutil_require_module('phabricator', 'view/layout/panel');
phutil_require_module('phabricator', 'view/layout/sidenav');
phutil_require_module('phutil', 'markup');
phutil_require_module('phutil', 'parser/uri');
phutil_require_module('phutil', 'utils');
phutil_require_source('DifferentialRevisionListController.php');
diff --git a/src/applications/people/controller/profile/PhabricatorPeopleProfileController.php b/src/applications/people/controller/profile/PhabricatorPeopleProfileController.php
index 43369cea89..066c9448bc 100644
--- a/src/applications/people/controller/profile/PhabricatorPeopleProfileController.php
+++ b/src/applications/people/controller/profile/PhabricatorPeopleProfileController.php
@@ -1,220 +1,221 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class PhabricatorPeopleProfileController extends PhabricatorPeopleController {
private $username;
private $page;
public function willProcessRequest(array $data) {
$this->username = idx($data, 'username');
$this->page = idx($data, 'page');
}
public function processRequest() {
$viewer = $this->getRequest()->getUser();
$user = id(new PhabricatorUser())->loadOneWhere(
'userName = %s',
$this->username);
if (!$user) {
return new Aphront404Response();
}
require_celerity_resource('phabricator-profile-css');
$profile = id(new PhabricatorUserProfile())->loadOneWhere(
'userPHID = %s',
$user->getPHID());
if (!$profile) {
$profile = new PhabricatorUserProfile();
}
+ $username = phutil_escape_uri($user->getUserName());
$nav = new AphrontSideNavFilterView();
- $nav->setBaseURI(new PhutilURI('/p/'.$user->getUserName().'/'));
+ $nav->setBaseURI(new PhutilURI('/p/'.$username.'/'));
$nav->addFilter('feed', 'Feed');
$nav->addFilter('about', 'About');
$nav->addSpacer();
$nav->addLabel('Activity');
$external_arrow = "\xE2\x86\x97";
$nav->addFilter(
null,
"Revisions {$external_arrow}",
- '/differential/filter/revisions/?phid='.$user->getPHID());
+ '/differential/filter/revisions/'.$username.'/');
$nav->addFilter(
null,
"Tasks {$external_arrow}",
'/maniphest/view/action/?users='.$user->getPHID());
$nav->addFilter(
null,
"Commits {$external_arrow}",
- '/audit/view/author/'.phutil_escape_uri($user->getUserName()).'/');
+ '/audit/view/author/'.$username.'/');
$oauths = id(new PhabricatorUserOAuthInfo())->loadAllWhere(
'userID = %d',
$user->getID());
$oauths = mpull($oauths, null, 'getOAuthProvider');
$providers = PhabricatorOAuthProvider::getAllProviders();
$added_spacer = false;
foreach ($providers as $provider) {
if (!$provider->isProviderEnabled()) {
continue;
}
$provider_key = $provider->getProviderKey();
if (!isset($oauths[$provider_key])) {
continue;
}
$name = $provider->getProviderName().' Profile';
$href = $oauths[$provider_key]->getAccountURI();
if ($href) {
if (!$added_spacer) {
$nav->addSpacer();
$nav->addLabel('Linked Accounts');
$added_spacer = true;
}
$nav->addFilter(null, $name.' '.$external_arrow, $href);
}
}
$this->page = $nav->selectFilter($this->page, 'feed');
switch ($this->page) {
case 'feed':
$content = $this->renderUserFeed($user);
break;
case 'about':
$content = $this->renderBasicInformation($user, $profile);
break;
default:
throw new Exception("Unknown page '{$this->page}'!");
}
$src_phid = $user->getProfileImagePHID();
$file = id(new PhabricatorFile())->loadOneWhere('phid = %s', $src_phid);
if ($file) {
$picture = $file->getBestURI();
} else {
$picture = null;
}
$header = new PhabricatorProfileHeaderView();
$header
->setProfilePicture($picture)
->setName($user->getUserName().' ('.$user->getRealName().')')
->setDescription($profile->getTitle());
$header->appendChild($nav);
$nav->appendChild(
'<div style="padding: 1em;">'.$content.'</div>');
if ($user->getPHID() == $viewer->getPHID()) {
$nav->addSpacer();
$nav->addFilter(null, 'Edit Profile...', '/settings/page/profile/');
}
if ($viewer->getIsAdmin()) {
$nav->addSpacer();
$nav->addFilter(
null,
'Administrate User...',
'/people/edit/'.$user->getID().'/');
}
return $this->buildStandardPageResponse(
$header,
array(
'title' => $user->getUsername(),
));
}
private function renderBasicInformation($user, $profile) {
$blurb = nonempty(
$profile->getBlurb(),
'//Nothing is known about this rare specimen.//');
$engine = PhabricatorMarkupEngine::newProfileMarkupEngine();
$blurb = $engine->markupText($blurb);
$viewer = $this->getRequest()->getUser();
$content =
'<div class="phabricator-profile-info-group">
<h1 class="phabricator-profile-info-header">Basic Information</h1>
<div class="phabricator-profile-info-pane">
<table class="phabricator-profile-info-table">
<tr>
<th>PHID</th>
<td>'.phutil_escape_html($user->getPHID()).'</td>
</tr>
<tr>
<th>User Since</th>
<td>'.phabricator_datetime($user->getDateCreated(),
$viewer).
'</td>
</tr>
</table>
</div>
</div>';
$content .=
'<div class="phabricator-profile-info-group">
<h1 class="phabricator-profile-info-header">Flavor Text</h1>
<div class="phabricator-profile-info-pane">
<table class="phabricator-profile-info-table">
<tr>
<th>Blurb</th>
<td>'.$blurb.'</td>
</tr>
</table>
</div>
</div>';
return $content;
}
private function renderUserFeed(PhabricatorUser $user) {
$query = new PhabricatorFeedQuery();
$query->setFilterPHIDs(
array(
$user->getPHID(),
));
$stories = $query->execute();
$builder = new PhabricatorFeedBuilder($stories);
$builder->setUser($this->getRequest()->getUser());
$view = $builder->buildView();
return
'<div class="phabricator-profile-info-group">
<h1 class="phabricator-profile-info-header">Activity Feed</h1>
<div class="phabricator-profile-info-pane">
'.$view->render().'
</div>
</div>';
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Jan 19 2025, 19:10 (5 w, 18 m ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1127802
Default Alt Text
(45 KB)
Attached To
Mode
rP Phorge
Attached
Detach File
Event Timeline
Log In to Comment