1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-25 08:12:40 +01:00

(stable) Promote 2016 Week 12

This commit is contained in:
epriestley 2016-03-19 05:34:06 -07:00
commit 741e2ef4b1
110 changed files with 3080 additions and 1370 deletions

View file

@ -7,12 +7,12 @@
*/ */
return array( return array(
'names' => array( 'names' => array(
'core.pkg.css' => '9c8e888d', 'core.pkg.css' => 'a93de192',
'core.pkg.js' => '7d8faf57', 'core.pkg.js' => '7d8faf57',
'darkconsole.pkg.js' => 'e7393ebb', 'darkconsole.pkg.js' => 'e7393ebb',
'differential.pkg.css' => '7d0a63a7', 'differential.pkg.css' => '7ba78475',
'differential.pkg.js' => 'd0cd0df6', 'differential.pkg.js' => 'd0cd0df6',
'diffusion.pkg.css' => 'f45955ed', 'diffusion.pkg.css' => 'dc8e0cc2',
'diffusion.pkg.js' => '3a9a8bfa', 'diffusion.pkg.js' => '3a9a8bfa',
'maniphest.pkg.css' => '4845691a', 'maniphest.pkg.css' => '4845691a',
'maniphest.pkg.js' => '949a7498', 'maniphest.pkg.js' => '949a7498',
@ -57,16 +57,16 @@ return array(
'rsrc/css/application/dashboard/dashboard.css' => 'eb458607', 'rsrc/css/application/dashboard/dashboard.css' => 'eb458607',
'rsrc/css/application/diff/inline-comment-summary.css' => '51efda3a', 'rsrc/css/application/diff/inline-comment-summary.css' => '51efda3a',
'rsrc/css/application/differential/add-comment.css' => 'c47f8c40', 'rsrc/css/application/differential/add-comment.css' => 'c47f8c40',
'rsrc/css/application/differential/changeset-view.css' => 'b6b0d1bb', 'rsrc/css/application/differential/changeset-view.css' => '3e3b0b76',
'rsrc/css/application/differential/core.css' => '7ac3cabc', 'rsrc/css/application/differential/core.css' => '5b7b8ff4',
'rsrc/css/application/differential/phui-inline-comment.css' => '5953c28e', 'rsrc/css/application/differential/phui-inline-comment.css' => '5953c28e',
'rsrc/css/application/differential/revision-comment.css' => '14b8565a', 'rsrc/css/application/differential/revision-comment.css' => '14b8565a',
'rsrc/css/application/differential/revision-history.css' => '0e8eb855', 'rsrc/css/application/differential/revision-history.css' => '0e8eb855',
'rsrc/css/application/differential/revision-list.css' => 'f3c47d33', 'rsrc/css/application/differential/revision-list.css' => 'f3c47d33',
'rsrc/css/application/differential/table-of-contents.css' => 'ae4b7a55', 'rsrc/css/application/differential/table-of-contents.css' => 'ae4b7a55',
'rsrc/css/application/diffusion/diffusion-icons.css' => '2941baf1', 'rsrc/css/application/diffusion/diffusion-icons.css' => '3311444d',
'rsrc/css/application/diffusion/diffusion-readme.css' => '356a4f3c', 'rsrc/css/application/diffusion/diffusion-readme.css' => '297373eb',
'rsrc/css/application/diffusion/diffusion-source.css' => '075ba788', 'rsrc/css/application/diffusion/diffusion-source.css' => '68b30fd3',
'rsrc/css/application/feed/feed.css' => 'ecd4ec57', 'rsrc/css/application/feed/feed.css' => 'ecd4ec57',
'rsrc/css/application/files/global-drag-and-drop.css' => '5c1b47c2', 'rsrc/css/application/files/global-drag-and-drop.css' => '5c1b47c2',
'rsrc/css/application/flag/flag.css' => '5337623f', 'rsrc/css/application/flag/flag.css' => '5337623f',
@ -123,7 +123,7 @@ return array(
'rsrc/css/phui/phui-action-panel.css' => '91c7b835', 'rsrc/css/phui/phui-action-panel.css' => '91c7b835',
'rsrc/css/phui/phui-badge.css' => 'f25c3476', 'rsrc/css/phui/phui-badge.css' => 'f25c3476',
'rsrc/css/phui/phui-big-info-view.css' => 'bd903741', 'rsrc/css/phui/phui-big-info-view.css' => 'bd903741',
'rsrc/css/phui/phui-box.css' => '3830ab21', 'rsrc/css/phui/phui-box.css' => 'b2d49bae',
'rsrc/css/phui/phui-button.css' => 'a64a8de6', 'rsrc/css/phui/phui-button.css' => 'a64a8de6',
'rsrc/css/phui/phui-chart.css' => '6bf6f78e', 'rsrc/css/phui/phui-chart.css' => '6bf6f78e',
'rsrc/css/phui/phui-crumbs-view.css' => '79d536e5', 'rsrc/css/phui/phui-crumbs-view.css' => '79d536e5',
@ -135,28 +135,28 @@ return array(
'rsrc/css/phui/phui-fontkit.css' => '9cda225e', 'rsrc/css/phui/phui-fontkit.css' => '9cda225e',
'rsrc/css/phui/phui-form-view.css' => '4a1a0f5e', 'rsrc/css/phui/phui-form-view.css' => '4a1a0f5e',
'rsrc/css/phui/phui-form.css' => 'aac1d51d', 'rsrc/css/phui/phui-form.css' => 'aac1d51d',
'rsrc/css/phui/phui-head-thing.css' => '31638812', 'rsrc/css/phui/phui-head-thing.css' => 'fd311e5f',
'rsrc/css/phui/phui-header-view.css' => '26cffd3d', 'rsrc/css/phui/phui-header-view.css' => '230254d3',
'rsrc/css/phui/phui-hovercard.css' => 'de1a2119', 'rsrc/css/phui/phui-hovercard.css' => 'de1a2119',
'rsrc/css/phui/phui-icon-set-selector.css' => '1ab67aad', 'rsrc/css/phui/phui-icon-set-selector.css' => '1ab67aad',
'rsrc/css/phui/phui-icon.css' => '3f33ab57', 'rsrc/css/phui/phui-icon.css' => '3f33ab57',
'rsrc/css/phui/phui-image-mask.css' => 'a8498f9c', 'rsrc/css/phui/phui-image-mask.css' => 'a8498f9c',
'rsrc/css/phui/phui-info-panel.css' => '27ea50a1', 'rsrc/css/phui/phui-info-panel.css' => '27ea50a1',
'rsrc/css/phui/phui-info-view.css' => '6d7c3509', 'rsrc/css/phui/phui-info-view.css' => '28efab79',
'rsrc/css/phui/phui-list.css' => '9da2aa00', 'rsrc/css/phui/phui-list.css' => '9da2aa00',
'rsrc/css/phui/phui-object-box.css' => '91628842', 'rsrc/css/phui/phui-object-box.css' => '6b487c57',
'rsrc/css/phui/phui-object-item-list-view.css' => '18b2ce8e', 'rsrc/css/phui/phui-object-item-list-view.css' => '18b2ce8e',
'rsrc/css/phui/phui-pager.css' => 'bea33d23', 'rsrc/css/phui/phui-pager.css' => 'bea33d23',
'rsrc/css/phui/phui-pinboard-view.css' => '2495140e', 'rsrc/css/phui/phui-pinboard-view.css' => '2495140e',
'rsrc/css/phui/phui-profile-menu.css' => '7e92a89a', 'rsrc/css/phui/phui-profile-menu.css' => '7e92a89a',
'rsrc/css/phui/phui-property-list-view.css' => 'b12e801c', 'rsrc/css/phui/phui-property-list-view.css' => '1d42ee7c',
'rsrc/css/phui/phui-remarkup-preview.css' => '1a8f2591', 'rsrc/css/phui/phui-remarkup-preview.css' => '1a8f2591',
'rsrc/css/phui/phui-segment-bar-view.css' => '46342871', 'rsrc/css/phui/phui-segment-bar-view.css' => '46342871',
'rsrc/css/phui/phui-spacing.css' => '042804d6', 'rsrc/css/phui/phui-spacing.css' => '042804d6',
'rsrc/css/phui/phui-status.css' => '37309046', 'rsrc/css/phui/phui-status.css' => '37309046',
'rsrc/css/phui/phui-tag-view.css' => '6bbd83e2', 'rsrc/css/phui/phui-tag-view.css' => '6bbd83e2',
'rsrc/css/phui/phui-timeline-view.css' => 'a0173eba', 'rsrc/css/phui/phui-timeline-view.css' => 'a0173eba',
'rsrc/css/phui/phui-two-column-view.css' => 'e6bf86b6', 'rsrc/css/phui/phui-two-column-view.css' => '37d704f3',
'rsrc/css/phui/workboards/phui-workboard-color.css' => 'ac6fe6a7', 'rsrc/css/phui/workboards/phui-workboard-color.css' => 'ac6fe6a7',
'rsrc/css/phui/workboards/phui-workboard.css' => 'e6d89647', 'rsrc/css/phui/workboards/phui-workboard.css' => 'e6d89647',
'rsrc/css/phui/workboards/phui-workcard.css' => '3646fb96', 'rsrc/css/phui/workboards/phui-workcard.css' => '3646fb96',
@ -545,17 +545,17 @@ return array(
'conpherence-update-css' => 'faf6be09', 'conpherence-update-css' => 'faf6be09',
'conpherence-widget-pane-css' => '775eaaba', 'conpherence-widget-pane-css' => '775eaaba',
'd3' => 'a11a5ff2', 'd3' => 'a11a5ff2',
'differential-changeset-view-css' => 'b6b0d1bb', 'differential-changeset-view-css' => '3e3b0b76',
'differential-core-view-css' => '7ac3cabc', 'differential-core-view-css' => '5b7b8ff4',
'differential-inline-comment-editor' => '64a5550f', 'differential-inline-comment-editor' => '64a5550f',
'differential-revision-add-comment-css' => 'c47f8c40', 'differential-revision-add-comment-css' => 'c47f8c40',
'differential-revision-comment-css' => '14b8565a', 'differential-revision-comment-css' => '14b8565a',
'differential-revision-history-css' => '0e8eb855', 'differential-revision-history-css' => '0e8eb855',
'differential-revision-list-css' => 'f3c47d33', 'differential-revision-list-css' => 'f3c47d33',
'differential-table-of-contents-css' => 'ae4b7a55', 'differential-table-of-contents-css' => 'ae4b7a55',
'diffusion-icons-css' => '2941baf1', 'diffusion-icons-css' => '3311444d',
'diffusion-readme-css' => '356a4f3c', 'diffusion-readme-css' => '297373eb',
'diffusion-source-css' => '075ba788', 'diffusion-source-css' => '68b30fd3',
'diviner-shared-css' => 'aa3656aa', 'diviner-shared-css' => 'aa3656aa',
'font-aleo' => '8bdb2835', 'font-aleo' => '8bdb2835',
'font-fontawesome' => 'c43323c5', 'font-fontawesome' => 'c43323c5',
@ -805,7 +805,7 @@ return array(
'phui-action-panel-css' => '91c7b835', 'phui-action-panel-css' => '91c7b835',
'phui-badge-view-css' => 'f25c3476', 'phui-badge-view-css' => 'f25c3476',
'phui-big-info-view-css' => 'bd903741', 'phui-big-info-view-css' => 'bd903741',
'phui-box-css' => '3830ab21', 'phui-box-css' => 'b2d49bae',
'phui-button-css' => 'a64a8de6', 'phui-button-css' => 'a64a8de6',
'phui-calendar-css' => 'ccabe893', 'phui-calendar-css' => 'ccabe893',
'phui-calendar-day-css' => 'd1cf6f93', 'phui-calendar-day-css' => 'd1cf6f93',
@ -822,23 +822,23 @@ return array(
'phui-fontkit-css' => '9cda225e', 'phui-fontkit-css' => '9cda225e',
'phui-form-css' => 'aac1d51d', 'phui-form-css' => 'aac1d51d',
'phui-form-view-css' => '4a1a0f5e', 'phui-form-view-css' => '4a1a0f5e',
'phui-head-thing-view-css' => '31638812', 'phui-head-thing-view-css' => 'fd311e5f',
'phui-header-view-css' => '26cffd3d', 'phui-header-view-css' => '230254d3',
'phui-hovercard' => '1bd28176', 'phui-hovercard' => '1bd28176',
'phui-hovercard-view-css' => 'de1a2119', 'phui-hovercard-view-css' => 'de1a2119',
'phui-icon-set-selector-css' => '1ab67aad', 'phui-icon-set-selector-css' => '1ab67aad',
'phui-icon-view-css' => '3f33ab57', 'phui-icon-view-css' => '3f33ab57',
'phui-image-mask-css' => 'a8498f9c', 'phui-image-mask-css' => 'a8498f9c',
'phui-info-panel-css' => '27ea50a1', 'phui-info-panel-css' => '27ea50a1',
'phui-info-view-css' => '6d7c3509', 'phui-info-view-css' => '28efab79',
'phui-inline-comment-view-css' => '5953c28e', 'phui-inline-comment-view-css' => '5953c28e',
'phui-list-view-css' => '9da2aa00', 'phui-list-view-css' => '9da2aa00',
'phui-object-box-css' => '91628842', 'phui-object-box-css' => '6b487c57',
'phui-object-item-list-view-css' => '18b2ce8e', 'phui-object-item-list-view-css' => '18b2ce8e',
'phui-pager-css' => 'bea33d23', 'phui-pager-css' => 'bea33d23',
'phui-pinboard-view-css' => '2495140e', 'phui-pinboard-view-css' => '2495140e',
'phui-profile-menu-css' => '7e92a89a', 'phui-profile-menu-css' => '7e92a89a',
'phui-property-list-view-css' => 'b12e801c', 'phui-property-list-view-css' => '1d42ee7c',
'phui-remarkup-preview-css' => '1a8f2591', 'phui-remarkup-preview-css' => '1a8f2591',
'phui-segment-bar-view-css' => '46342871', 'phui-segment-bar-view-css' => '46342871',
'phui-spacing-css' => '042804d6', 'phui-spacing-css' => '042804d6',
@ -846,7 +846,7 @@ return array(
'phui-tag-view-css' => '6bbd83e2', 'phui-tag-view-css' => '6bbd83e2',
'phui-theme-css' => '027ba77e', 'phui-theme-css' => '027ba77e',
'phui-timeline-view-css' => 'a0173eba', 'phui-timeline-view-css' => 'a0173eba',
'phui-two-column-view-css' => 'e6bf86b6', 'phui-two-column-view-css' => '37d704f3',
'phui-workboard-color-css' => 'ac6fe6a7', 'phui-workboard-color-css' => 'ac6fe6a7',
'phui-workboard-view-css' => 'e6d89647', 'phui-workboard-view-css' => 'e6d89647',
'phui-workcard-view-css' => '3646fb96', 'phui-workcard-view-css' => '3646fb96',
@ -1124,6 +1124,9 @@ return array(
'javelin-util', 'javelin-util',
'javelin-uri', 'javelin-uri',
), ),
'3e3b0b76' => array(
'phui-inline-comment-view-css',
),
'3f5d6dbf' => array( '3f5d6dbf' => array(
'javelin-behavior', 'javelin-behavior',
'javelin-dom', 'javelin-dom',
@ -1791,9 +1794,6 @@ return array(
'javelin-json', 'javelin-json',
'phabricator-draggable-list', 'phabricator-draggable-list',
), ),
'b6b0d1bb' => array(
'phui-inline-comment-view-css',
),
'bae58312' => array( 'bae58312' => array(
'javelin-install', 'javelin-install',
'javelin-workboard-card', 'javelin-workboard-card',

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_auth.auth_temporarytoken
CHANGE objectPHID tokenResource VARBINARY(64) NOT NULL;

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_auth.auth_temporarytoken
ADD userPHID VARBINARY(64);

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_auth.auth_temporarytoken
ADD properties LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT};

View file

@ -0,0 +1,2 @@
UPDATE {$NAMESPACE}_auth.auth_temporarytoken
SET properties = '{}' WHERE properties = '';

View file

@ -0,0 +1,11 @@
CREATE TABLE {$NAMESPACE}_repository.repository_gitlfsref (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
repositoryPHID VARBINARY(64) NOT NULL,
objectHash BINARY(64) NOT NULL,
byteSize BIGINT UNSIGNED NOT NULL,
authorPHID VARBINARY(64) NOT NULL,
filePHID VARBINARY(64) NOT NULL,
dateCreated INT UNSIGNED NOT NULL,
dateModified INT UNSIGNED NOT NULL,
UNIQUE KEY `key_hash` (repositoryPHID, objectHash)
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};

View file

@ -473,7 +473,6 @@ phutil_register_library_map(array(
'DifferentialParseCommitMessageConduitAPIMethod' => 'applications/differential/conduit/DifferentialParseCommitMessageConduitAPIMethod.php', 'DifferentialParseCommitMessageConduitAPIMethod' => 'applications/differential/conduit/DifferentialParseCommitMessageConduitAPIMethod.php',
'DifferentialParseRenderTestCase' => 'applications/differential/__tests__/DifferentialParseRenderTestCase.php', 'DifferentialParseRenderTestCase' => 'applications/differential/__tests__/DifferentialParseRenderTestCase.php',
'DifferentialPathField' => 'applications/differential/customfield/DifferentialPathField.php', 'DifferentialPathField' => 'applications/differential/customfield/DifferentialPathField.php',
'DifferentialPrimaryPaneView' => 'applications/differential/view/DifferentialPrimaryPaneView.php',
'DifferentialProjectReviewersField' => 'applications/differential/customfield/DifferentialProjectReviewersField.php', 'DifferentialProjectReviewersField' => 'applications/differential/customfield/DifferentialProjectReviewersField.php',
'DifferentialProjectsField' => 'applications/differential/customfield/DifferentialProjectsField.php', 'DifferentialProjectsField' => 'applications/differential/customfield/DifferentialProjectsField.php',
'DifferentialQueryConduitAPIMethod' => 'applications/differential/conduit/DifferentialQueryConduitAPIMethod.php', 'DifferentialQueryConduitAPIMethod' => 'applications/differential/conduit/DifferentialQueryConduitAPIMethod.php',
@ -508,7 +507,6 @@ phutil_register_library_map(array(
'DifferentialRevisionControlSystem' => 'applications/differential/constants/DifferentialRevisionControlSystem.php', 'DifferentialRevisionControlSystem' => 'applications/differential/constants/DifferentialRevisionControlSystem.php',
'DifferentialRevisionDependedOnByRevisionEdgeType' => 'applications/differential/edge/DifferentialRevisionDependedOnByRevisionEdgeType.php', 'DifferentialRevisionDependedOnByRevisionEdgeType' => 'applications/differential/edge/DifferentialRevisionDependedOnByRevisionEdgeType.php',
'DifferentialRevisionDependsOnRevisionEdgeType' => 'applications/differential/edge/DifferentialRevisionDependsOnRevisionEdgeType.php', 'DifferentialRevisionDependsOnRevisionEdgeType' => 'applications/differential/edge/DifferentialRevisionDependsOnRevisionEdgeType.php',
'DifferentialRevisionDetailView' => 'applications/differential/view/DifferentialRevisionDetailView.php',
'DifferentialRevisionEditController' => 'applications/differential/controller/DifferentialRevisionEditController.php', 'DifferentialRevisionEditController' => 'applications/differential/controller/DifferentialRevisionEditController.php',
'DifferentialRevisionFulltextEngine' => 'applications/differential/search/DifferentialRevisionFulltextEngine.php', 'DifferentialRevisionFulltextEngine' => 'applications/differential/search/DifferentialRevisionFulltextEngine.php',
'DifferentialRevisionHasCommitEdgeType' => 'applications/differential/edge/DifferentialRevisionHasCommitEdgeType.php', 'DifferentialRevisionHasCommitEdgeType' => 'applications/differential/edge/DifferentialRevisionHasCommitEdgeType.php',
@ -635,6 +633,9 @@ phutil_register_library_map(array(
'DiffusionGitBranch' => 'applications/diffusion/data/DiffusionGitBranch.php', 'DiffusionGitBranch' => 'applications/diffusion/data/DiffusionGitBranch.php',
'DiffusionGitBranchTestCase' => 'applications/diffusion/data/__tests__/DiffusionGitBranchTestCase.php', 'DiffusionGitBranchTestCase' => 'applications/diffusion/data/__tests__/DiffusionGitBranchTestCase.php',
'DiffusionGitFileContentQuery' => 'applications/diffusion/query/filecontent/DiffusionGitFileContentQuery.php', 'DiffusionGitFileContentQuery' => 'applications/diffusion/query/filecontent/DiffusionGitFileContentQuery.php',
'DiffusionGitLFSAuthenticateWorkflow' => 'applications/diffusion/gitlfs/DiffusionGitLFSAuthenticateWorkflow.php',
'DiffusionGitLFSResponse' => 'applications/diffusion/response/DiffusionGitLFSResponse.php',
'DiffusionGitLFSTemporaryTokenType' => 'applications/diffusion/gitlfs/DiffusionGitLFSTemporaryTokenType.php',
'DiffusionGitRawDiffQuery' => 'applications/diffusion/query/rawdiff/DiffusionGitRawDiffQuery.php', 'DiffusionGitRawDiffQuery' => 'applications/diffusion/query/rawdiff/DiffusionGitRawDiffQuery.php',
'DiffusionGitReceivePackSSHWorkflow' => 'applications/diffusion/ssh/DiffusionGitReceivePackSSHWorkflow.php', 'DiffusionGitReceivePackSSHWorkflow' => 'applications/diffusion/ssh/DiffusionGitReceivePackSSHWorkflow.php',
'DiffusionGitRequest' => 'applications/diffusion/request/DiffusionGitRequest.php', 'DiffusionGitRequest' => 'applications/diffusion/request/DiffusionGitRequest.php',
@ -1818,6 +1819,8 @@ phutil_register_library_map(array(
'PhabricatorAuthNewController' => 'applications/auth/controller/config/PhabricatorAuthNewController.php', 'PhabricatorAuthNewController' => 'applications/auth/controller/config/PhabricatorAuthNewController.php',
'PhabricatorAuthOldOAuthRedirectController' => 'applications/auth/controller/PhabricatorAuthOldOAuthRedirectController.php', 'PhabricatorAuthOldOAuthRedirectController' => 'applications/auth/controller/PhabricatorAuthOldOAuthRedirectController.php',
'PhabricatorAuthOneTimeLoginController' => 'applications/auth/controller/PhabricatorAuthOneTimeLoginController.php', 'PhabricatorAuthOneTimeLoginController' => 'applications/auth/controller/PhabricatorAuthOneTimeLoginController.php',
'PhabricatorAuthOneTimeLoginTemporaryTokenType' => 'applications/auth/tokentype/PhabricatorAuthOneTimeLoginTemporaryTokenType.php',
'PhabricatorAuthPasswordResetTemporaryTokenType' => 'applications/auth/tokentype/PhabricatorAuthPasswordResetTemporaryTokenType.php',
'PhabricatorAuthProvider' => 'applications/auth/provider/PhabricatorAuthProvider.php', 'PhabricatorAuthProvider' => 'applications/auth/provider/PhabricatorAuthProvider.php',
'PhabricatorAuthProviderConfig' => 'applications/auth/storage/PhabricatorAuthProviderConfig.php', 'PhabricatorAuthProviderConfig' => 'applications/auth/storage/PhabricatorAuthProviderConfig.php',
'PhabricatorAuthProviderConfigController' => 'applications/auth/controller/config/PhabricatorAuthProviderConfigController.php', 'PhabricatorAuthProviderConfigController' => 'applications/auth/controller/config/PhabricatorAuthProviderConfigController.php',
@ -1843,9 +1846,12 @@ phutil_register_library_map(array(
'PhabricatorAuthSessionQuery' => 'applications/auth/query/PhabricatorAuthSessionQuery.php', 'PhabricatorAuthSessionQuery' => 'applications/auth/query/PhabricatorAuthSessionQuery.php',
'PhabricatorAuthSetupCheck' => 'applications/config/check/PhabricatorAuthSetupCheck.php', 'PhabricatorAuthSetupCheck' => 'applications/config/check/PhabricatorAuthSetupCheck.php',
'PhabricatorAuthStartController' => 'applications/auth/controller/PhabricatorAuthStartController.php', 'PhabricatorAuthStartController' => 'applications/auth/controller/PhabricatorAuthStartController.php',
'PhabricatorAuthTOTPKeyTemporaryTokenType' => 'applications/auth/factor/PhabricatorAuthTOTPKeyTemporaryTokenType.php',
'PhabricatorAuthTemporaryToken' => 'applications/auth/storage/PhabricatorAuthTemporaryToken.php', 'PhabricatorAuthTemporaryToken' => 'applications/auth/storage/PhabricatorAuthTemporaryToken.php',
'PhabricatorAuthTemporaryTokenGarbageCollector' => 'applications/auth/garbagecollector/PhabricatorAuthTemporaryTokenGarbageCollector.php', 'PhabricatorAuthTemporaryTokenGarbageCollector' => 'applications/auth/garbagecollector/PhabricatorAuthTemporaryTokenGarbageCollector.php',
'PhabricatorAuthTemporaryTokenQuery' => 'applications/auth/query/PhabricatorAuthTemporaryTokenQuery.php', 'PhabricatorAuthTemporaryTokenQuery' => 'applications/auth/query/PhabricatorAuthTemporaryTokenQuery.php',
'PhabricatorAuthTemporaryTokenType' => 'applications/auth/tokentype/PhabricatorAuthTemporaryTokenType.php',
'PhabricatorAuthTemporaryTokenTypeModule' => 'applications/auth/tokentype/PhabricatorAuthTemporaryTokenTypeModule.php',
'PhabricatorAuthTerminateSessionController' => 'applications/auth/controller/PhabricatorAuthTerminateSessionController.php', 'PhabricatorAuthTerminateSessionController' => 'applications/auth/controller/PhabricatorAuthTerminateSessionController.php',
'PhabricatorAuthTryFactorAction' => 'applications/auth/action/PhabricatorAuthTryFactorAction.php', 'PhabricatorAuthTryFactorAction' => 'applications/auth/action/PhabricatorAuthTryFactorAction.php',
'PhabricatorAuthUnlinkController' => 'applications/auth/controller/PhabricatorAuthUnlinkController.php', 'PhabricatorAuthUnlinkController' => 'applications/auth/controller/PhabricatorAuthUnlinkController.php',
@ -2349,6 +2355,7 @@ phutil_register_library_map(array(
'PhabricatorFeedStoryPublisher' => 'applications/feed/PhabricatorFeedStoryPublisher.php', 'PhabricatorFeedStoryPublisher' => 'applications/feed/PhabricatorFeedStoryPublisher.php',
'PhabricatorFeedStoryReference' => 'applications/feed/storage/PhabricatorFeedStoryReference.php', 'PhabricatorFeedStoryReference' => 'applications/feed/storage/PhabricatorFeedStoryReference.php',
'PhabricatorFile' => 'applications/files/storage/PhabricatorFile.php', 'PhabricatorFile' => 'applications/files/storage/PhabricatorFile.php',
'PhabricatorFileAccessTemporaryTokenType' => 'applications/files/temporarytoken/PhabricatorFileAccessTemporaryTokenType.php',
'PhabricatorFileBundleLoader' => 'applications/files/query/PhabricatorFileBundleLoader.php', 'PhabricatorFileBundleLoader' => 'applications/files/query/PhabricatorFileBundleLoader.php',
'PhabricatorFileChunk' => 'applications/files/storage/PhabricatorFileChunk.php', 'PhabricatorFileChunk' => 'applications/files/storage/PhabricatorFileChunk.php',
'PhabricatorFileChunkIterator' => 'applications/files/engine/PhabricatorFileChunkIterator.php', 'PhabricatorFileChunkIterator' => 'applications/files/engine/PhabricatorFileChunkIterator.php',
@ -2447,6 +2454,7 @@ phutil_register_library_map(array(
'PhabricatorHandlePool' => 'applications/phid/handle/pool/PhabricatorHandlePool.php', 'PhabricatorHandlePool' => 'applications/phid/handle/pool/PhabricatorHandlePool.php',
'PhabricatorHandlePoolTestCase' => 'applications/phid/handle/pool/__tests__/PhabricatorHandlePoolTestCase.php', 'PhabricatorHandlePoolTestCase' => 'applications/phid/handle/pool/__tests__/PhabricatorHandlePoolTestCase.php',
'PhabricatorHandleQuery' => 'applications/phid/query/PhabricatorHandleQuery.php', 'PhabricatorHandleQuery' => 'applications/phid/query/PhabricatorHandleQuery.php',
'PhabricatorHandleRemarkupRule' => 'applications/phid/remarkup/PhabricatorHandleRemarkupRule.php',
'PhabricatorHandlesEditField' => 'applications/transactions/editfield/PhabricatorHandlesEditField.php', 'PhabricatorHandlesEditField' => 'applications/transactions/editfield/PhabricatorHandlesEditField.php',
'PhabricatorHarbormasterApplication' => 'applications/harbormaster/application/PhabricatorHarbormasterApplication.php', 'PhabricatorHarbormasterApplication' => 'applications/harbormaster/application/PhabricatorHarbormasterApplication.php',
'PhabricatorHarbormasterConfigOptions' => 'applications/harbormaster/config/PhabricatorHarbormasterConfigOptions.php', 'PhabricatorHarbormasterConfigOptions' => 'applications/harbormaster/config/PhabricatorHarbormasterConfigOptions.php',
@ -2493,6 +2501,7 @@ phutil_register_library_map(array(
'PhabricatorInvalidConfigSetupCheck' => 'applications/config/check/PhabricatorInvalidConfigSetupCheck.php', 'PhabricatorInvalidConfigSetupCheck' => 'applications/config/check/PhabricatorInvalidConfigSetupCheck.php',
'PhabricatorIteratedMD5PasswordHasher' => 'infrastructure/util/password/PhabricatorIteratedMD5PasswordHasher.php', 'PhabricatorIteratedMD5PasswordHasher' => 'infrastructure/util/password/PhabricatorIteratedMD5PasswordHasher.php',
'PhabricatorIteratedMD5PasswordHasherTestCase' => 'infrastructure/util/password/__tests__/PhabricatorIteratedMD5PasswordHasherTestCase.php', 'PhabricatorIteratedMD5PasswordHasherTestCase' => 'infrastructure/util/password/__tests__/PhabricatorIteratedMD5PasswordHasherTestCase.php',
'PhabricatorIteratorFileUploadSource' => 'applications/files/uploadsource/PhabricatorIteratorFileUploadSource.php',
'PhabricatorJIRAAuthProvider' => 'applications/auth/provider/PhabricatorJIRAAuthProvider.php', 'PhabricatorJIRAAuthProvider' => 'applications/auth/provider/PhabricatorJIRAAuthProvider.php',
'PhabricatorJavelinLinter' => 'infrastructure/lint/linter/PhabricatorJavelinLinter.php', 'PhabricatorJavelinLinter' => 'infrastructure/lint/linter/PhabricatorJavelinLinter.php',
'PhabricatorJiraIssueHasObjectEdgeType' => 'applications/doorkeeper/edge/PhabricatorJiraIssueHasObjectEdgeType.php', 'PhabricatorJiraIssueHasObjectEdgeType' => 'applications/doorkeeper/edge/PhabricatorJiraIssueHasObjectEdgeType.php',
@ -2669,6 +2678,7 @@ phutil_register_library_map(array(
'PhabricatorNotificationsApplication' => 'applications/notification/application/PhabricatorNotificationsApplication.php', 'PhabricatorNotificationsApplication' => 'applications/notification/application/PhabricatorNotificationsApplication.php',
'PhabricatorNuanceApplication' => 'applications/nuance/application/PhabricatorNuanceApplication.php', 'PhabricatorNuanceApplication' => 'applications/nuance/application/PhabricatorNuanceApplication.php',
'PhabricatorOAuth1AuthProvider' => 'applications/auth/provider/PhabricatorOAuth1AuthProvider.php', 'PhabricatorOAuth1AuthProvider' => 'applications/auth/provider/PhabricatorOAuth1AuthProvider.php',
'PhabricatorOAuth1SecretTemporaryTokenType' => 'applications/auth/provider/PhabricatorOAuth1SecretTemporaryTokenType.php',
'PhabricatorOAuth2AuthProvider' => 'applications/auth/provider/PhabricatorOAuth2AuthProvider.php', 'PhabricatorOAuth2AuthProvider' => 'applications/auth/provider/PhabricatorOAuth2AuthProvider.php',
'PhabricatorOAuthAuthProvider' => 'applications/auth/provider/PhabricatorOAuthAuthProvider.php', 'PhabricatorOAuthAuthProvider' => 'applications/auth/provider/PhabricatorOAuthAuthProvider.php',
'PhabricatorOAuthClientAuthorization' => 'applications/oauthserver/storage/PhabricatorOAuthClientAuthorization.php', 'PhabricatorOAuthClientAuthorization' => 'applications/oauthserver/storage/PhabricatorOAuthClientAuthorization.php',
@ -3091,6 +3101,8 @@ phutil_register_library_map(array(
'PhabricatorRepositoryEngine' => 'applications/repository/engine/PhabricatorRepositoryEngine.php', 'PhabricatorRepositoryEngine' => 'applications/repository/engine/PhabricatorRepositoryEngine.php',
'PhabricatorRepositoryGitCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/PhabricatorRepositoryGitCommitChangeParserWorker.php', 'PhabricatorRepositoryGitCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/PhabricatorRepositoryGitCommitChangeParserWorker.php',
'PhabricatorRepositoryGitCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/PhabricatorRepositoryGitCommitMessageParserWorker.php', 'PhabricatorRepositoryGitCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/PhabricatorRepositoryGitCommitMessageParserWorker.php',
'PhabricatorRepositoryGitLFSRef' => 'applications/repository/storage/PhabricatorRepositoryGitLFSRef.php',
'PhabricatorRepositoryGitLFSRefQuery' => 'applications/repository/query/PhabricatorRepositoryGitLFSRefQuery.php',
'PhabricatorRepositoryGraphCache' => 'applications/repository/graphcache/PhabricatorRepositoryGraphCache.php', 'PhabricatorRepositoryGraphCache' => 'applications/repository/graphcache/PhabricatorRepositoryGraphCache.php',
'PhabricatorRepositoryGraphStream' => 'applications/repository/daemon/PhabricatorRepositoryGraphStream.php', 'PhabricatorRepositoryGraphStream' => 'applications/repository/daemon/PhabricatorRepositoryGraphStream.php',
'PhabricatorRepositoryManagementCacheWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementCacheWorkflow.php', 'PhabricatorRepositoryManagementCacheWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementCacheWorkflow.php',
@ -4580,7 +4592,6 @@ phutil_register_library_map(array(
'DifferentialParseCommitMessageConduitAPIMethod' => 'DifferentialConduitAPIMethod', 'DifferentialParseCommitMessageConduitAPIMethod' => 'DifferentialConduitAPIMethod',
'DifferentialParseRenderTestCase' => 'PhabricatorTestCase', 'DifferentialParseRenderTestCase' => 'PhabricatorTestCase',
'DifferentialPathField' => 'DifferentialCustomField', 'DifferentialPathField' => 'DifferentialCustomField',
'DifferentialPrimaryPaneView' => 'AphrontView',
'DifferentialProjectReviewersField' => 'DifferentialCustomField', 'DifferentialProjectReviewersField' => 'DifferentialCustomField',
'DifferentialProjectsField' => 'DifferentialCoreCustomField', 'DifferentialProjectsField' => 'DifferentialCoreCustomField',
'DifferentialQueryConduitAPIMethod' => 'DifferentialConduitAPIMethod', 'DifferentialQueryConduitAPIMethod' => 'DifferentialConduitAPIMethod',
@ -4630,7 +4641,6 @@ phutil_register_library_map(array(
'DifferentialRevisionControlSystem' => 'Phobject', 'DifferentialRevisionControlSystem' => 'Phobject',
'DifferentialRevisionDependedOnByRevisionEdgeType' => 'PhabricatorEdgeType', 'DifferentialRevisionDependedOnByRevisionEdgeType' => 'PhabricatorEdgeType',
'DifferentialRevisionDependsOnRevisionEdgeType' => 'PhabricatorEdgeType', 'DifferentialRevisionDependsOnRevisionEdgeType' => 'PhabricatorEdgeType',
'DifferentialRevisionDetailView' => 'AphrontView',
'DifferentialRevisionEditController' => 'DifferentialController', 'DifferentialRevisionEditController' => 'DifferentialController',
'DifferentialRevisionFulltextEngine' => 'PhabricatorFulltextEngine', 'DifferentialRevisionFulltextEngine' => 'PhabricatorFulltextEngine',
'DifferentialRevisionHasCommitEdgeType' => 'PhabricatorEdgeType', 'DifferentialRevisionHasCommitEdgeType' => 'PhabricatorEdgeType',
@ -4757,6 +4767,9 @@ phutil_register_library_map(array(
'DiffusionGitBranch' => 'Phobject', 'DiffusionGitBranch' => 'Phobject',
'DiffusionGitBranchTestCase' => 'PhabricatorTestCase', 'DiffusionGitBranchTestCase' => 'PhabricatorTestCase',
'DiffusionGitFileContentQuery' => 'DiffusionFileContentQuery', 'DiffusionGitFileContentQuery' => 'DiffusionFileContentQuery',
'DiffusionGitLFSAuthenticateWorkflow' => 'DiffusionGitSSHWorkflow',
'DiffusionGitLFSResponse' => 'AphrontResponse',
'DiffusionGitLFSTemporaryTokenType' => 'PhabricatorAuthTemporaryTokenType',
'DiffusionGitRawDiffQuery' => 'DiffusionRawDiffQuery', 'DiffusionGitRawDiffQuery' => 'DiffusionRawDiffQuery',
'DiffusionGitReceivePackSSHWorkflow' => 'DiffusionGitSSHWorkflow', 'DiffusionGitReceivePackSSHWorkflow' => 'DiffusionGitSSHWorkflow',
'DiffusionGitRequest' => 'DiffusionRequest', 'DiffusionGitRequest' => 'DiffusionRequest',
@ -6127,6 +6140,8 @@ phutil_register_library_map(array(
'PhabricatorAuthNewController' => 'PhabricatorAuthProviderConfigController', 'PhabricatorAuthNewController' => 'PhabricatorAuthProviderConfigController',
'PhabricatorAuthOldOAuthRedirectController' => 'PhabricatorAuthController', 'PhabricatorAuthOldOAuthRedirectController' => 'PhabricatorAuthController',
'PhabricatorAuthOneTimeLoginController' => 'PhabricatorAuthController', 'PhabricatorAuthOneTimeLoginController' => 'PhabricatorAuthController',
'PhabricatorAuthOneTimeLoginTemporaryTokenType' => 'PhabricatorAuthTemporaryTokenType',
'PhabricatorAuthPasswordResetTemporaryTokenType' => 'PhabricatorAuthTemporaryTokenType',
'PhabricatorAuthProvider' => 'Phobject', 'PhabricatorAuthProvider' => 'Phobject',
'PhabricatorAuthProviderConfig' => array( 'PhabricatorAuthProviderConfig' => array(
'PhabricatorAuthDAO', 'PhabricatorAuthDAO',
@ -6163,12 +6178,15 @@ phutil_register_library_map(array(
'PhabricatorAuthSessionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorAuthSessionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorAuthSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorAuthSetupCheck' => 'PhabricatorSetupCheck',
'PhabricatorAuthStartController' => 'PhabricatorAuthController', 'PhabricatorAuthStartController' => 'PhabricatorAuthController',
'PhabricatorAuthTOTPKeyTemporaryTokenType' => 'PhabricatorAuthTemporaryTokenType',
'PhabricatorAuthTemporaryToken' => array( 'PhabricatorAuthTemporaryToken' => array(
'PhabricatorAuthDAO', 'PhabricatorAuthDAO',
'PhabricatorPolicyInterface', 'PhabricatorPolicyInterface',
), ),
'PhabricatorAuthTemporaryTokenGarbageCollector' => 'PhabricatorGarbageCollector', 'PhabricatorAuthTemporaryTokenGarbageCollector' => 'PhabricatorGarbageCollector',
'PhabricatorAuthTemporaryTokenQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorAuthTemporaryTokenQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorAuthTemporaryTokenType' => 'Phobject',
'PhabricatorAuthTemporaryTokenTypeModule' => 'PhabricatorConfigModule',
'PhabricatorAuthTerminateSessionController' => 'PhabricatorAuthController', 'PhabricatorAuthTerminateSessionController' => 'PhabricatorAuthController',
'PhabricatorAuthTryFactorAction' => 'PhabricatorSystemAction', 'PhabricatorAuthTryFactorAction' => 'PhabricatorSystemAction',
'PhabricatorAuthUnlinkController' => 'PhabricatorAuthController', 'PhabricatorAuthUnlinkController' => 'PhabricatorAuthController',
@ -6763,6 +6781,7 @@ phutil_register_library_map(array(
'PhabricatorPolicyInterface', 'PhabricatorPolicyInterface',
'PhabricatorDestructibleInterface', 'PhabricatorDestructibleInterface',
), ),
'PhabricatorFileAccessTemporaryTokenType' => 'PhabricatorAuthTemporaryTokenType',
'PhabricatorFileBundleLoader' => 'Phobject', 'PhabricatorFileBundleLoader' => 'Phobject',
'PhabricatorFileChunk' => array( 'PhabricatorFileChunk' => array(
'PhabricatorFileDAO', 'PhabricatorFileDAO',
@ -6882,6 +6901,7 @@ phutil_register_library_map(array(
'PhabricatorHandlePool' => 'Phobject', 'PhabricatorHandlePool' => 'Phobject',
'PhabricatorHandlePoolTestCase' => 'PhabricatorTestCase', 'PhabricatorHandlePoolTestCase' => 'PhabricatorTestCase',
'PhabricatorHandleQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorHandleQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorHandleRemarkupRule' => 'PhutilRemarkupRule',
'PhabricatorHandlesEditField' => 'PhabricatorPHIDListEditField', 'PhabricatorHandlesEditField' => 'PhabricatorPHIDListEditField',
'PhabricatorHarbormasterApplication' => 'PhabricatorApplication', 'PhabricatorHarbormasterApplication' => 'PhabricatorApplication',
'PhabricatorHarbormasterConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorHarbormasterConfigOptions' => 'PhabricatorApplicationConfigOptions',
@ -6928,6 +6948,7 @@ phutil_register_library_map(array(
'PhabricatorInvalidConfigSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorInvalidConfigSetupCheck' => 'PhabricatorSetupCheck',
'PhabricatorIteratedMD5PasswordHasher' => 'PhabricatorPasswordHasher', 'PhabricatorIteratedMD5PasswordHasher' => 'PhabricatorPasswordHasher',
'PhabricatorIteratedMD5PasswordHasherTestCase' => 'PhabricatorTestCase', 'PhabricatorIteratedMD5PasswordHasherTestCase' => 'PhabricatorTestCase',
'PhabricatorIteratorFileUploadSource' => 'PhabricatorFileUploadSource',
'PhabricatorJIRAAuthProvider' => 'PhabricatorOAuth1AuthProvider', 'PhabricatorJIRAAuthProvider' => 'PhabricatorOAuth1AuthProvider',
'PhabricatorJavelinLinter' => 'ArcanistLinter', 'PhabricatorJavelinLinter' => 'ArcanistLinter',
'PhabricatorJiraIssueHasObjectEdgeType' => 'PhabricatorEdgeType', 'PhabricatorJiraIssueHasObjectEdgeType' => 'PhabricatorEdgeType',
@ -7116,6 +7137,7 @@ phutil_register_library_map(array(
'PhabricatorNotificationsApplication' => 'PhabricatorApplication', 'PhabricatorNotificationsApplication' => 'PhabricatorApplication',
'PhabricatorNuanceApplication' => 'PhabricatorApplication', 'PhabricatorNuanceApplication' => 'PhabricatorApplication',
'PhabricatorOAuth1AuthProvider' => 'PhabricatorOAuthAuthProvider', 'PhabricatorOAuth1AuthProvider' => 'PhabricatorOAuthAuthProvider',
'PhabricatorOAuth1SecretTemporaryTokenType' => 'PhabricatorAuthTemporaryTokenType',
'PhabricatorOAuth2AuthProvider' => 'PhabricatorOAuthAuthProvider', 'PhabricatorOAuth2AuthProvider' => 'PhabricatorOAuthAuthProvider',
'PhabricatorOAuthAuthProvider' => 'PhabricatorAuthProvider', 'PhabricatorOAuthAuthProvider' => 'PhabricatorAuthProvider',
'PhabricatorOAuthClientAuthorization' => array( 'PhabricatorOAuthClientAuthorization' => array(
@ -7647,6 +7669,12 @@ phutil_register_library_map(array(
'PhabricatorRepositoryEngine' => 'Phobject', 'PhabricatorRepositoryEngine' => 'Phobject',
'PhabricatorRepositoryGitCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker', 'PhabricatorRepositoryGitCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker',
'PhabricatorRepositoryGitCommitMessageParserWorker' => 'PhabricatorRepositoryCommitMessageParserWorker', 'PhabricatorRepositoryGitCommitMessageParserWorker' => 'PhabricatorRepositoryCommitMessageParserWorker',
'PhabricatorRepositoryGitLFSRef' => array(
'PhabricatorRepositoryDAO',
'PhabricatorPolicyInterface',
'PhabricatorDestructibleInterface',
),
'PhabricatorRepositoryGitLFSRefQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorRepositoryGraphCache' => 'Phobject', 'PhabricatorRepositoryGraphCache' => 'Phobject',
'PhabricatorRepositoryGraphStream' => 'Phobject', 'PhabricatorRepositoryGraphStream' => 'Phobject',
'PhabricatorRepositoryManagementCacheWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementCacheWorkflow' => 'PhabricatorRepositoryManagementWorkflow',

View file

@ -25,12 +25,19 @@ class AphrontDefaultApplicationConfiguration
$content_type = idx($_SERVER, 'CONTENT_TYPE'); $content_type = idx($_SERVER, 'CONTENT_TYPE');
$is_form_data = preg_match('@^multipart/form-data@i', $content_type); $is_form_data = preg_match('@^multipart/form-data@i', $content_type);
$request_method = idx($_SERVER, 'REQUEST_METHOD');
if ($request_method === 'PUT') {
// For PUT requests, do nothing: in particular, do NOT read input. This
// allows us to stream input later and process very large PUT requests,
// like those coming from Git LFS.
} else {
$raw_input = PhabricatorStartup::getRawInput(); $raw_input = PhabricatorStartup::getRawInput();
if (strlen($raw_input) && !$is_form_data) { if (strlen($raw_input) && !$is_form_data) {
$data += $parser->parseQueryString($raw_input); $data += $parser->parseQueryString($raw_input);
} else if ($_POST) { } else if ($_POST) {
$data += $_POST; $data += $_POST;
} }
}
$data += $parser->parseQueryString(idx($_SERVER, 'QUERY_STRING', '')); $data += $parser->parseQueryString(idx($_SERVER, 'QUERY_STRING', ''));

View file

@ -37,9 +37,11 @@ final class PhabricatorAuditCommitStatusConstants extends Phobject {
$color = 'red'; $color = 'red';
break; break;
case self::NEEDS_AUDIT: case self::NEEDS_AUDIT:
case self::PARTIALLY_AUDITED:
$color = 'orange'; $color = 'orange';
break; break;
case self::PARTIALLY_AUDITED:
$color = 'yellow';
break;
case self::FULLY_AUDITED: case self::FULLY_AUDITED:
$color = 'green'; $color = 'green';
break; break;
@ -53,11 +55,11 @@ final class PhabricatorAuditCommitStatusConstants extends Phobject {
public static function getStatusIcon($code) { public static function getStatusIcon($code) {
switch ($code) { switch ($code) {
case self::CONCERN_RAISED: case self::CONCERN_RAISED:
$icon = 'fa-exclamation-triangle'; $icon = 'fa-exclamation-circle';
break; break;
case self::NEEDS_AUDIT: case self::NEEDS_AUDIT:
case self::PARTIALLY_AUDITED: case self::PARTIALLY_AUDITED:
$icon = 'fa-exclamation-triangle'; $icon = 'fa-exclamation-circle';
break; break;
case self::FULLY_AUDITED: case self::FULLY_AUDITED:
$icon = 'fa-check'; $icon = 'fa-check';

View file

@ -117,12 +117,37 @@ final class PhabricatorAuditTransaction
return 'red'; return 'red';
case PhabricatorAuditActionConstants::ACCEPT: case PhabricatorAuditActionConstants::ACCEPT:
return 'green'; return 'green';
case PhabricatorAuditActionConstants::RESIGN:
return 'black';
case PhabricatorAuditActionConstants::CLOSE:
return 'indigo';
} }
} }
return parent::getColor(); return parent::getColor();
} }
public function getIcon() {
$type = $this->getTransactionType();
switch ($type) {
case PhabricatorAuditActionConstants::ACTION:
switch ($this->getNewValue()) {
case PhabricatorAuditActionConstants::CONCERN:
return 'fa-exclamation-circle';
case PhabricatorAuditActionConstants::ACCEPT:
return 'fa-check';
case PhabricatorAuditActionConstants::RESIGN:
return 'fa-plane';
case PhabricatorAuditActionConstants::CLOSE:
return 'fa-check';
}
}
return parent::getIcon();
}
public function getTitle() { public function getTitle() {
$old = $this->getOldValue(); $old = $this->getOldValue();
$new = $this->getNewValue(); $new = $this->getNewValue();

View file

@ -105,23 +105,17 @@ final class PhabricatorAuthOneTimeLoginController
// the link in the "Welcome" email is good enough, without requiring users // the link in the "Welcome" email is good enough, without requiring users
// to go through a second round of email verification. // to go through a second round of email verification.
$editor = id(new PhabricatorUserEditor())
->setActor($target_user);
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
// Nuke the token and all other outstanding password reset tokens. // Nuke the token and all other outstanding password reset tokens.
// There is no particular security benefit to destroying them all, but // There is no particular security benefit to destroying them all, but
// it should reduce HackerOne reports of nebulous harm. // it should reduce HackerOne reports of nebulous harm.
$editor->revokePasswordResetLinks($target_user);
PhabricatorAuthTemporaryToken::revokeTokens(
$target_user,
array($target_user->getPHID()),
array(
PhabricatorAuthSessionEngine::ONETIME_TEMPORARY_TOKEN_TYPE,
PhabricatorAuthSessionEngine::PASSWORD_TEMPORARY_TOKEN_TYPE,
));
if ($target_email) { if ($target_email) {
id(new PhabricatorUserEditor()) $editor->verifyEmail($target_user, $target_email);
->setActor($target_user)
->verifyEmail($target_user, $target_email);
} }
unset($unguarded); unset($unguarded);
@ -133,12 +127,13 @@ final class PhabricatorAuthOneTimeLoginController
// We're going to let the user reset their password without knowing // We're going to let the user reset their password without knowing
// the old one. Generate a one-time token for that. // the old one. Generate a one-time token for that.
$key = Filesystem::readRandomCharacters(16); $key = Filesystem::readRandomCharacters(16);
$password_type =
PhabricatorAuthPasswordResetTemporaryTokenType::TOKENTYPE;
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
id(new PhabricatorAuthTemporaryToken()) id(new PhabricatorAuthTemporaryToken())
->setObjectPHID($target_user->getPHID()) ->setTokenResource($target_user->getPHID())
->setTokenType( ->setTokenType($password_type)
PhabricatorAuthSessionEngine::PASSWORD_TEMPORARY_TOKEN_TYPE)
->setTokenExpires(time() + phutil_units('1 hour in seconds')) ->setTokenExpires(time() + phutil_units('1 hour in seconds'))
->setTokenCode(PhabricatorHash::digest($key)) ->setTokenCode(PhabricatorHash::digest($key))
->save(); ->save();

View file

@ -11,7 +11,7 @@ final class PhabricatorAuthRevokeTokenController
$query = id(new PhabricatorAuthTemporaryTokenQuery()) $query = id(new PhabricatorAuthTemporaryTokenQuery())
->setViewer($viewer) ->setViewer($viewer)
->withObjectPHIDs(array($viewer->getPHID())); ->withTokenResources(array($viewer->getPHID()));
if (!$is_all) { if (!$is_all) {
$query->withIDs(array($id)); $query->withIDs(array($id));
} }

View file

@ -39,17 +39,6 @@ final class PhabricatorAuthSessionEngine extends Phobject {
const KIND_UNKNOWN = '?'; const KIND_UNKNOWN = '?';
/**
* Temporary tokens for one time logins.
*/
const ONETIME_TEMPORARY_TOKEN_TYPE = 'login:onetime';
/**
* Temporary tokens for password recovery after one time login.
*/
const PASSWORD_TEMPORARY_TOKEN_TYPE = 'login:password';
const ONETIME_RECOVER = 'recover'; const ONETIME_RECOVER = 'recover';
const ONETIME_RESET = 'reset'; const ONETIME_RESET = 'reset';
const ONETIME_WELCOME = 'welcome'; const ONETIME_WELCOME = 'welcome';
@ -642,11 +631,12 @@ final class PhabricatorAuthSessionEngine extends Phobject {
$key = Filesystem::readRandomCharacters(32); $key = Filesystem::readRandomCharacters(32);
$key_hash = $this->getOneTimeLoginKeyHash($user, $email, $key); $key_hash = $this->getOneTimeLoginKeyHash($user, $email, $key);
$onetime_type = PhabricatorAuthOneTimeLoginTemporaryTokenType::TOKENTYPE;
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
id(new PhabricatorAuthTemporaryToken()) id(new PhabricatorAuthTemporaryToken())
->setObjectPHID($user->getPHID()) ->setTokenResource($user->getPHID())
->setTokenType(self::ONETIME_TEMPORARY_TOKEN_TYPE) ->setTokenType($onetime_type)
->setTokenExpires(time() + phutil_units('1 day in seconds')) ->setTokenExpires(time() + phutil_units('1 day in seconds'))
->setTokenCode($key_hash) ->setTokenCode($key_hash)
->save(); ->save();
@ -685,11 +675,12 @@ final class PhabricatorAuthSessionEngine extends Phobject {
$key = null) { $key = null) {
$key_hash = $this->getOneTimeLoginKeyHash($user, $email, $key); $key_hash = $this->getOneTimeLoginKeyHash($user, $email, $key);
$onetime_type = PhabricatorAuthOneTimeLoginTemporaryTokenType::TOKENTYPE;
return id(new PhabricatorAuthTemporaryTokenQuery()) return id(new PhabricatorAuthTemporaryTokenQuery())
->setViewer($user) ->setViewer($user)
->withObjectPHIDs(array($user->getPHID())) ->withTokenResources(array($user->getPHID()))
->withTokenTypes(array(self::ONETIME_TEMPORARY_TOKEN_TYPE)) ->withTokenTypes(array($onetime_type))
->withTokenCodes(array($key_hash)) ->withTokenCodes(array($key_hash))
->withExpired(false) ->withExpired(false)
->executeOne(); ->executeOne();

View file

@ -0,0 +1,17 @@
<?php
final class PhabricatorAuthTOTPKeyTemporaryTokenType
extends PhabricatorAuthTemporaryTokenType {
const TOKENTYPE = 'mfa:totp:key';
public function getTokenTypeDisplayName() {
return pht('TOTP Synchronization');
}
public function getTokenReadableTypeName(
PhabricatorAuthTemporaryToken $token) {
return pht('TOTP Sync Token');
}
}

View file

@ -2,8 +2,6 @@
final class PhabricatorTOTPAuthFactor extends PhabricatorAuthFactor { final class PhabricatorTOTPAuthFactor extends PhabricatorAuthFactor {
const TEMPORARY_TOKEN_TYPE = 'mfa:totp:key';
public function getFactorKey() { public function getFactorKey() {
return 'totp'; return 'totp';
} }
@ -24,6 +22,8 @@ final class PhabricatorTOTPAuthFactor extends PhabricatorAuthFactor {
AphrontRequest $request, AphrontRequest $request,
PhabricatorUser $user) { PhabricatorUser $user) {
$totp_token_type = PhabricatorAuthTOTPKeyTemporaryTokenType::TOKENTYPE;
$key = $request->getStr('totpkey'); $key = $request->getStr('totpkey');
if (strlen($key)) { if (strlen($key)) {
// If the user is providing a key, make sure it's a key we generated. // If the user is providing a key, make sure it's a key we generated.
@ -36,8 +36,8 @@ final class PhabricatorTOTPAuthFactor extends PhabricatorAuthFactor {
$temporary_token = id(new PhabricatorAuthTemporaryTokenQuery()) $temporary_token = id(new PhabricatorAuthTemporaryTokenQuery())
->setViewer($user) ->setViewer($user)
->withObjectPHIDs(array($user->getPHID())) ->withTokenResources(array($user->getPHID()))
->withTokenTypes(array(self::TEMPORARY_TOKEN_TYPE)) ->withTokenTypes(array($totp_token_type))
->withExpired(false) ->withExpired(false)
->withTokenCodes(array(PhabricatorHash::digest($key))) ->withTokenCodes(array(PhabricatorHash::digest($key)))
->executeOne(); ->executeOne();
@ -55,8 +55,8 @@ final class PhabricatorTOTPAuthFactor extends PhabricatorAuthFactor {
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
id(new PhabricatorAuthTemporaryToken()) id(new PhabricatorAuthTemporaryToken())
->setObjectPHID($user->getPHID()) ->setTokenResource($user->getPHID())
->setTokenType(self::TEMPORARY_TOKEN_TYPE) ->setTokenType($totp_token_type)
->setTokenExpires(time() + phutil_units('1 hour in seconds')) ->setTokenExpires(time() + phutil_units('1 hour in seconds'))
->setTokenCode(PhabricatorHash::digest($key)) ->setTokenCode(PhabricatorHash::digest($key))
->save(); ->save();

View file

@ -9,8 +9,6 @@ abstract class PhabricatorOAuth1AuthProvider
const PROPERTY_CONSUMER_SECRET = 'oauth1:consumer:secret'; const PROPERTY_CONSUMER_SECRET = 'oauth1:consumer:secret';
const PROPERTY_PRIVATE_KEY = 'oauth1:private:key'; const PROPERTY_PRIVATE_KEY = 'oauth1:private:key';
const TEMPORARY_TOKEN_TYPE = 'oauth1:request:secret';
protected function getIDKey() { protected function getIDKey() {
return self::PROPERTY_CONSUMER_KEY; return self::PROPERTY_CONSUMER_KEY;
} }
@ -215,13 +213,14 @@ abstract class PhabricatorOAuth1AuthProvider
private function saveHandshakeTokenSecret($client_code, $secret) { private function saveHandshakeTokenSecret($client_code, $secret) {
$secret_type = PhabricatorOAuth1SecretTemporaryTokenType::TOKENTYPE;
$key = $this->getHandshakeTokenKeyFromClientCode($client_code); $key = $this->getHandshakeTokenKeyFromClientCode($client_code);
$type = $this->getTemporaryTokenType(self::TEMPORARY_TOKEN_TYPE); $type = $this->getTemporaryTokenType($secret_type);
// Wipe out an existing token, if one exists. // Wipe out an existing token, if one exists.
$token = id(new PhabricatorAuthTemporaryTokenQuery()) $token = id(new PhabricatorAuthTemporaryTokenQuery())
->setViewer(PhabricatorUser::getOmnipotentUser()) ->setViewer(PhabricatorUser::getOmnipotentUser())
->withObjectPHIDs(array($key)) ->withTokenResources(array($key))
->withTokenTypes(array($type)) ->withTokenTypes(array($type))
->executeOne(); ->executeOne();
if ($token) { if ($token) {
@ -230,7 +229,7 @@ abstract class PhabricatorOAuth1AuthProvider
// Save the new secret. // Save the new secret.
id(new PhabricatorAuthTemporaryToken()) id(new PhabricatorAuthTemporaryToken())
->setObjectPHID($key) ->setTokenResource($key)
->setTokenType($type) ->setTokenType($type)
->setTokenExpires(time() + phutil_units('1 hour in seconds')) ->setTokenExpires(time() + phutil_units('1 hour in seconds'))
->setTokenCode($secret) ->setTokenCode($secret)
@ -238,12 +237,13 @@ abstract class PhabricatorOAuth1AuthProvider
} }
private function loadHandshakeTokenSecret($client_code) { private function loadHandshakeTokenSecret($client_code) {
$secret_type = PhabricatorOAuth1SecretTemporaryTokenType::TOKENTYPE;
$key = $this->getHandshakeTokenKeyFromClientCode($client_code); $key = $this->getHandshakeTokenKeyFromClientCode($client_code);
$type = $this->getTemporaryTokenType(self::TEMPORARY_TOKEN_TYPE); $type = $this->getTemporaryTokenType($secret_type);
$token = id(new PhabricatorAuthTemporaryTokenQuery()) $token = id(new PhabricatorAuthTemporaryTokenQuery())
->setViewer(PhabricatorUser::getOmnipotentUser()) ->setViewer(PhabricatorUser::getOmnipotentUser())
->withObjectPHIDs(array($key)) ->withTokenResources(array($key))
->withTokenTypes(array($type)) ->withTokenTypes(array($type))
->withExpired(false) ->withExpired(false)
->executeOne(); ->executeOne();
@ -263,6 +263,9 @@ abstract class PhabricatorOAuth1AuthProvider
// others' toes if a user starts Mediawiki and Bitbucket auth at the // others' toes if a user starts Mediawiki and Bitbucket auth at the
// same time. // same time.
// TODO: This isn't really a proper use of the table and should get
// cleaned up some day: the type should be constant.
return $core_type.':'.$this->getProviderConfig()->getID(); return $core_type.':'.$this->getProviderConfig()->getID();
} }

View file

@ -0,0 +1,17 @@
<?php
final class PhabricatorOAuth1SecretTemporaryTokenType
extends PhabricatorAuthTemporaryTokenType {
const TOKENTYPE = 'oauth1:request:secret';
public function getTokenTypeDisplayName() {
return pht('OAuth1 Handshake Secret');
}
public function getTokenReadableTypeName(
PhabricatorAuthTemporaryToken $token) {
return pht('OAuth1 Handshake Token');
}
}

View file

@ -4,8 +4,9 @@ final class PhabricatorAuthTemporaryTokenQuery
extends PhabricatorCursorPagedPolicyAwareQuery { extends PhabricatorCursorPagedPolicyAwareQuery {
private $ids; private $ids;
private $objectPHIDs; private $tokenResources;
private $tokenTypes; private $tokenTypes;
private $userPHIDs;
private $expired; private $expired;
private $tokenCodes; private $tokenCodes;
@ -14,8 +15,8 @@ final class PhabricatorAuthTemporaryTokenQuery
return $this; return $this;
} }
public function withObjectPHIDs(array $object_phids) { public function withTokenResources(array $resources) {
$this->objectPHIDs = $object_phids; $this->tokenResources = $resources;
return $this; return $this;
} }
@ -34,41 +35,39 @@ final class PhabricatorAuthTemporaryTokenQuery
return $this; return $this;
} }
protected function loadPage() { public function withUserPHIDs(array $phids) {
$table = new PhabricatorAuthTemporaryToken(); $this->userPHIDs = $phids;
$conn_r = $table->establishConnection('r'); return $this;
$data = queryfx_all(
$conn_r,
'SELECT * FROM %T %Q %Q %Q',
$table->getTableName(),
$this->buildWhereClause($conn_r),
$this->buildOrderClause($conn_r),
$this->buildLimitClause($conn_r));
return $table->loadAllFromArray($data);
} }
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) { public function newResultObject() {
$where = array(); return new PhabricatorAuthTemporaryToken();
}
protected function loadPage() {
return $this->loadStandardPage($this->newResultObject());
}
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
$where = parent::buildWhereClauseParts($conn);
if ($this->ids !== null) { if ($this->ids !== null) {
$where[] = qsprintf( $where[] = qsprintf(
$conn_r, $conn,
'id IN (%Ld)', 'id IN (%Ld)',
$this->ids); $this->ids);
} }
if ($this->objectPHIDs !== null) { if ($this->tokenResources !== null) {
$where[] = qsprintf( $where[] = qsprintf(
$conn_r, $conn,
'objectPHID IN (%Ls)', 'tokenResource IN (%Ls)',
$this->objectPHIDs); $this->tokenResources);
} }
if ($this->tokenTypes !== null) { if ($this->tokenTypes !== null) {
$where[] = qsprintf( $where[] = qsprintf(
$conn_r, $conn,
'tokenType IN (%Ls)', 'tokenType IN (%Ls)',
$this->tokenTypes); $this->tokenTypes);
} }
@ -76,12 +75,12 @@ final class PhabricatorAuthTemporaryTokenQuery
if ($this->expired !== null) { if ($this->expired !== null) {
if ($this->expired) { if ($this->expired) {
$where[] = qsprintf( $where[] = qsprintf(
$conn_r, $conn,
'tokenExpires <= %d', 'tokenExpires <= %d',
time()); time());
} else { } else {
$where[] = qsprintf( $where[] = qsprintf(
$conn_r, $conn,
'tokenExpires > %d', 'tokenExpires > %d',
time()); time());
} }
@ -89,14 +88,19 @@ final class PhabricatorAuthTemporaryTokenQuery
if ($this->tokenCodes !== null) { if ($this->tokenCodes !== null) {
$where[] = qsprintf( $where[] = qsprintf(
$conn_r, $conn,
'tokenCode IN (%Ls)', 'tokenCode IN (%Ls)',
$this->tokenCodes); $this->tokenCodes);
} }
$where[] = $this->buildPagingClause($conn_r); if ($this->userPHIDs !== null) {
$where[] = qsprintf(
$conn,
'userPHID IN (%Ls)',
$this->userPHIDs);
}
return $this->formatWhereClause($where); return $where;
} }
public function getQueryApplicationClass() { public function getQueryApplicationClass() {

View file

@ -3,42 +3,58 @@
final class PhabricatorAuthTemporaryToken extends PhabricatorAuthDAO final class PhabricatorAuthTemporaryToken extends PhabricatorAuthDAO
implements PhabricatorPolicyInterface { implements PhabricatorPolicyInterface {
// TODO: OAuth1 stores a client identifier here, which is not a real PHID. // NOTE: This is usually a PHID, but may be some other kind of resource
// At some point, we should rename this column to be a little more generic. // identifier for some token types.
protected $objectPHID; protected $tokenResource;
protected $tokenType; protected $tokenType;
protected $tokenExpires; protected $tokenExpires;
protected $tokenCode; protected $tokenCode;
protected $userPHID;
protected $properties;
protected function getConfiguration() { protected function getConfiguration() {
return array( return array(
self::CONFIG_TIMESTAMPS => false, self::CONFIG_TIMESTAMPS => false,
self::CONFIG_SERIALIZATION => array(
'properties' => self::SERIALIZATION_JSON,
),
self::CONFIG_COLUMN_SCHEMA => array( self::CONFIG_COLUMN_SCHEMA => array(
'tokenResource' => 'phid',
'tokenType' => 'text64', 'tokenType' => 'text64',
'tokenExpires' => 'epoch', 'tokenExpires' => 'epoch',
'tokenCode' => 'text64', 'tokenCode' => 'text64',
'userPHID' => 'phid?',
), ),
self::CONFIG_KEY_SCHEMA => array( self::CONFIG_KEY_SCHEMA => array(
'key_token' => array( 'key_token' => array(
'columns' => array('objectPHID', 'tokenType', 'tokenCode'), 'columns' => array('tokenResource', 'tokenType', 'tokenCode'),
'unique' => true, 'unique' => true,
), ),
'key_expires' => array( 'key_expires' => array(
'columns' => array('tokenExpires'), 'columns' => array('tokenExpires'),
), ),
'key_user' => array(
'columns' => array('userPHID'),
),
), ),
) + parent::getConfiguration(); ) + parent::getConfiguration();
} }
private function newTokenTypeImplementation() {
$types = PhabricatorAuthTemporaryTokenType::getAllTypes();
$type = idx($types, $this->tokenType);
if ($type) {
return clone $type;
}
return null;
}
public function getTokenReadableTypeName() { public function getTokenReadableTypeName() {
// Eventually, it would be nice to let applications implement token types $type = $this->newTokenTypeImplementation();
// so we can put this in modular subclasses. if ($type) {
switch ($this->tokenType) { return $type->getTokenReadableTypeName($this);
case PhabricatorAuthSessionEngine::ONETIME_TEMPORARY_TOKEN_TYPE:
return pht('One-Time Login Token');
case PhabricatorAuthSessionEngine::PASSWORD_TEMPORARY_TOKEN_TYPE:
return pht('Password Reset Token');
} }
return $this->tokenType; return $this->tokenType;
@ -49,10 +65,9 @@ final class PhabricatorAuthTemporaryToken extends PhabricatorAuthDAO
return false; return false;
} }
switch ($this->tokenType) { $type = $this->newTokenTypeImplementation();
case PhabricatorAuthSessionEngine::ONETIME_TEMPORARY_TOKEN_TYPE: if ($type) {
case PhabricatorAuthSessionEngine::PASSWORD_TEMPORARY_TOKEN_TYPE: return $type->isTokenRevocable($this);
return true;
} }
return false; return false;
@ -67,12 +82,12 @@ final class PhabricatorAuthTemporaryToken extends PhabricatorAuthDAO
public static function revokeTokens( public static function revokeTokens(
PhabricatorUser $viewer, PhabricatorUser $viewer,
array $object_phids, array $token_resources,
array $token_types) { array $token_types) {
$tokens = id(new PhabricatorAuthTemporaryTokenQuery()) $tokens = id(new PhabricatorAuthTemporaryTokenQuery())
->setViewer($viewer) ->setViewer($viewer)
->withObjectPHIDs($object_phids) ->withTokenResources($token_resources)
->withTokenTypes($token_types) ->withTokenTypes($token_types)
->withExpired(false) ->withExpired(false)
->execute(); ->execute();
@ -82,6 +97,15 @@ final class PhabricatorAuthTemporaryToken extends PhabricatorAuthDAO
} }
} }
public function getTemporaryTokenProperty($key, $default = null) {
return idx($this->properties, $key, $default);
}
public function setTemporaryTokenProperty($key, $value) {
$this->properties[$key] = $value;
return $this;
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */ /* -( PhabricatorPolicyInterface )----------------------------------------- */

View file

@ -0,0 +1,21 @@
<?php
final class PhabricatorAuthOneTimeLoginTemporaryTokenType
extends PhabricatorAuthTemporaryTokenType {
const TOKENTYPE = 'login:onetime';
public function getTokenTypeDisplayName() {
return pht('One-Time Login');
}
public function getTokenReadableTypeName(
PhabricatorAuthTemporaryToken $token) {
return pht('One-Time Login Token');
}
public function isTokenRevocable(PhabricatorAuthTemporaryToken $token) {
return true;
}
}

View file

@ -0,0 +1,21 @@
<?php
final class PhabricatorAuthPasswordResetTemporaryTokenType
extends PhabricatorAuthTemporaryTokenType {
const TOKENTYPE = 'login:password';
public function getTokenTypeDisplayName() {
return pht('Password Reset');
}
public function getTokenReadableTypeName(
PhabricatorAuthTemporaryToken $token) {
return pht('Password Reset Token');
}
public function isTokenRevocable(PhabricatorAuthTemporaryToken $token) {
return true;
}
}

View file

@ -0,0 +1,25 @@
<?php
abstract class PhabricatorAuthTemporaryTokenType
extends Phobject {
abstract public function getTokenTypeDisplayName();
abstract public function getTokenReadableTypeName(
PhabricatorAuthTemporaryToken $token);
public function isTokenRevocable(PhabricatorAuthTemporaryToken $token) {
return false;
}
final public function getTokenTypeConstant() {
return $this->getPhobjectClassConstant('TOKENTYPE', 64);
}
final public static function getAllTypes() {
return id(new PhutilClassMapQuery())
->setAncestorClass(__CLASS__)
->setUniqueMethod('getTokenTypeConstant')
->execute();
}
}

View file

@ -0,0 +1,47 @@
<?php
final class PhabricatorAuthTemporaryTokenTypeModule
extends PhabricatorConfigModule {
public function getModuleKey() {
return 'temporarytoken';
}
public function getModuleName() {
return pht('Temporary Tokens');
}
public function renderModuleStatus(AphrontRequest $request) {
$viewer = $request->getViewer();
$types = PhabricatorAuthTemporaryTokenType::getAllTypes();
$rows = array();
foreach ($types as $type) {
$rows[] = array(
get_class($type),
$type->getTokenTypeConstant(),
$type->getTokenTypeDisplayName(),
);
}
$table = id(new AphrontTableView($rows))
->setHeaders(
array(
pht('Class'),
pht('Key'),
pht('Name'),
))
->setColumnClasses(
array(
null,
null,
'wide pri',
));
return id(new PHUIObjectBoxView())
->setHeaderText(pht('Temporary Token Types'))
->setTable($table);
}
}

View file

@ -81,6 +81,21 @@ final class DifferentialChangeType extends Phobject {
return idx($icons, $type, 'fa-file'); return idx($icons, $type, 'fa-file');
} }
public static function getIconColorForFileType($type) {
static $icons = array(
self::FILE_TEXT => 'black',
self::FILE_IMAGE => 'black',
self::FILE_BINARY => 'green',
self::FILE_DIRECTORY => 'blue',
self::FILE_SYMLINK => 'blue',
self::FILE_DELETED => 'red',
self::FILE_NORMAL => 'black',
self::FILE_SUBMODULE => 'blue',
);
return idx($icons, $type, 'black');
}
public static function isOldLocationChangeType($type) { public static function isOldLocationChangeType($type) {
static $types = array( static $types = array(
self::TYPE_MOVE_AWAY => true, self::TYPE_MOVE_AWAY => true,

View file

@ -28,7 +28,8 @@ abstract class DifferentialController extends PhabricatorController {
$viewer = $this->getViewer(); $viewer = $this->getViewer();
$toc_view = id(new PHUIDiffTableOfContentsListView()) $toc_view = id(new PHUIDiffTableOfContentsListView())
->setUser($viewer); ->setUser($viewer)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);
$have_owners = PhabricatorApplication::isClassInstalledForViewer( $have_owners = PhabricatorApplication::isClassInstalledForViewer(
'PhabricatorOwnersApplication', 'PhabricatorOwnersApplication',

View file

@ -126,27 +126,40 @@ final class DifferentialDiffViewController extends DifferentialController {
->setRenderingReferences($refs) ->setRenderingReferences($refs)
->setStandaloneURI('/differential/changeset/') ->setStandaloneURI('/differential/changeset/')
->setDiff($diff) ->setDiff($diff)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTitle(pht('Diff %d', $diff->getID())) ->setTitle(pht('Diff %d', $diff->getID()))
->setUser($request->getUser()); ->setUser($request->getUser());
$title = pht('Diff %d', $diff->getID());
$crumbs = $this->buildApplicationCrumbs(); $crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Diff %d', $diff->getID())); $crumbs->addTextCrumb($title);
$crumbs->setBorder(true);
$header = id(new PHUIHeaderView())
->setHeader($title);
$prop_box = id(new PHUIObjectBoxView()) $prop_box = id(new PHUIObjectBoxView())
->setHeader($property_head) ->setHeader($property_head)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($property_view) ->addPropertyList($property_view)
->setForm($form); ->setForm($form);
return $this->buildApplicationPage( $view = id(new PHUITwoColumnView())
array( ->setHeader($header)
$crumbs, ->setMainColumn(array(
))
->setFooter(array(
$prop_box, $prop_box,
$table_of_contents, $table_of_contents,
$details, $details,
),
array(
'title' => pht('Diff View'),
)); ));
$page = $this->newPage()
->setTitle(pht('Diff View'))
->setCrumbs($crumbs)
->appendChild($view);
return $page;
} }
private function loadSelectableRevisions( private function loadSelectableRevisions(

View file

@ -40,7 +40,6 @@ final class DifferentialRevisionViewController extends DifferentialController {
$revision->attachActiveDiff(last($diffs)); $revision->attachActiveDiff(last($diffs));
$diff_vs = $request->getInt('vs'); $diff_vs = $request->getInt('vs');
$target_id = $request->getInt('id'); $target_id = $request->getInt('id');
$target = idx($diffs, $target_id, end($diffs)); $target = idx($diffs, $target_id, end($diffs));
@ -210,14 +209,10 @@ final class DifferentialRevisionViewController extends DifferentialController {
$commits_for_links = array(); $commits_for_links = array();
} }
$revision_detail = id(new DifferentialRevisionDetailView()) $header = $this->buildHeader($revision);
->setUser($viewer) $subheader = $this->buildSubheaderView($revision);
->setRevision($revision) $details = $this->buildDetails($revision, $field_list);
->setDiff(end($diffs)) $curtain = $this->buildCurtain($revision);
->setCustomFields($field_list)
->setURI($request->getRequestURI());
$actions = $this->getRevisionActions($revision);
$whitespace = $request->getStr( $whitespace = $request->getStr(
'whitespace', 'whitespace',
@ -232,21 +227,16 @@ final class DifferentialRevisionViewController extends DifferentialController {
$symbol_indexes = array(); $symbol_indexes = array();
} }
$revision_detail->setActions($actions);
$revision_detail->setUser($viewer);
$revision_detail_box = $revision_detail->render();
$revision_warnings = $this->buildRevisionWarnings( $revision_warnings = $this->buildRevisionWarnings(
$revision, $revision,
$field_list, $field_list,
$warning_handle_map, $warning_handle_map,
$handles); $handles);
$info_view = null;
if ($revision_warnings) { if ($revision_warnings) {
$revision_warnings = id(new PHUIInfoView()) $info_view = id(new PHUIInfoView())
->setSeverity(PHUIInfoView::SEVERITY_WARNING) ->setSeverity(PHUIInfoView::SEVERITY_WARNING)
->setErrors($revision_warnings); ->setErrors($revision_warnings);
$revision_detail_box->setInfoView($revision_warnings);
} }
$detail_diffs = array_select_keys( $detail_diffs = array_select_keys(
@ -277,39 +267,31 @@ final class DifferentialRevisionViewController extends DifferentialController {
$comment_view->setQuoteTargetID('comment-content'); $comment_view->setQuoteTargetID('comment-content');
} }
$wrap_id = celerity_generate_unique_node_id(); $changeset_view = id(new DifferentialChangesetListView())
$comment_view = phutil_tag( ->setChangesets($changesets)
'div', ->setVisibleChangesets($visible_changesets)
array( ->setStandaloneURI('/differential/changeset/')
'id' => $wrap_id, ->setRawFileURIs(
), '/differential/changeset/?view=old',
$comment_view); '/differential/changeset/?view=new')
->setUser($viewer)
->setDiff($target)
->setRenderingReferences($rendering_references)
->setVsMap($vs_map)
->setWhitespace($whitespace)
->setSymbolIndexes($symbol_indexes)
->setTitle(pht('Diff %s', $target->getID()))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);
$changeset_view = new DifferentialChangesetListView(); if ($repository) {
$changeset_view->setChangesets($changesets); $changeset_view->setRepository($repository);
$changeset_view->setVisibleChangesets($visible_changesets); }
if (!$viewer_is_anonymous) { if (!$viewer_is_anonymous) {
$changeset_view->setInlineCommentControllerURI( $changeset_view->setInlineCommentControllerURI(
'/differential/comment/inline/edit/'.$revision->getID().'/'); '/differential/comment/inline/edit/'.$revision->getID().'/');
} }
$changeset_view->setStandaloneURI('/differential/changeset/');
$changeset_view->setRawFileURIs(
'/differential/changeset/?view=old',
'/differential/changeset/?view=new');
$changeset_view->setUser($viewer);
$changeset_view->setDiff($target);
$changeset_view->setRenderingReferences($rendering_references);
$changeset_view->setVsMap($vs_map);
$changeset_view->setWhitespace($whitespace);
if ($repository) {
$changeset_view->setRepository($repository);
}
$changeset_view->setSymbolIndexes($symbol_indexes);
$changeset_view->setTitle(pht('Diff %s', $target->getID()));
$diff_history = id(new DifferentialRevisionUpdateHistoryView()) $diff_history = id(new DifferentialRevisionUpdateHistoryView())
->setUser($viewer) ->setUser($viewer)
->setDiffs($diffs) ->setDiffs($diffs)
@ -344,6 +326,233 @@ final class DifferentialRevisionViewController extends DifferentialController {
$comment_form = null; $comment_form = null;
if (!$viewer_is_anonymous) { if (!$viewer_is_anonymous) {
$comment_form = $this->buildCommentForm($revision, $field_list);
}
$signatures = DifferentialRequiredSignaturesField::loadForRevision(
$revision);
$missing_signatures = false;
foreach ($signatures as $phid => $signed) {
if (!$signed) {
$missing_signatures = true;
}
}
$footer = array();
$signature_message = null;
if ($missing_signatures) {
$signature_message = id(new PHUIInfoView())
->setTitle(pht('Content Hidden'))
->appendChild(
pht(
'The content of this revision is hidden until the author has '.
'signed all of the required legal agreements.'));
} else {
$footer[] =
array(
$diff_history,
$warning,
$local_view,
$toc_view,
$other_view,
$changeset_view,
);
}
if ($comment_form) {
$footer[] = $comment_form;
} else {
// TODO: For now, just use this to get "Login to Comment".
$footer[] = id(new PhabricatorApplicationTransactionCommentView())
->setUser($viewer)
->setRequestURI($request->getRequestURI());
}
$object_id = 'D'.$revision->getID();
$operations_box = $this->buildOperationsBox($revision);
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb($object_id, '/'.$object_id);
$crumbs->setBorder(true);
$prefs = $viewer->loadPreferences();
$pref_filetree = PhabricatorUserPreferences::PREFERENCE_DIFF_FILETREE;
$nav = null;
if ($prefs->getPreference($pref_filetree)) {
$collapsed = $prefs->getPreference(
PhabricatorUserPreferences::PREFERENCE_NAV_COLLAPSED,
false);
$nav = id(new DifferentialChangesetFileTreeSideNavBuilder())
->setTitle('D'.$revision->getID())
->setBaseURI(new PhutilURI('/D'.$revision->getID()))
->setCollapsed((bool)$collapsed)
->build($changesets);
}
// Haunt Mode
$pane_id = celerity_generate_unique_node_id();
Javelin::initBehavior(
'differential-keyboard-navigation',
array(
'haunt' => $pane_id,
));
Javelin::initBehavior('differential-user-select');
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setSubheader($subheader)
->setCurtain($curtain)
->setID($pane_id)
->setMainColumn(array(
$operations_box,
$info_view,
$details,
$diff_detail_box,
$unit_box,
$comment_view,
$signature_message,
))
->setFooter($footer);
$page = $this->newPage()
->setTitle($object_id.' '.$revision->getTitle())
->setCrumbs($crumbs)
->setPageObjectPHIDs(array($revision->getPHID()))
->appendChild($view);
if ($nav) {
$page->setNavigation($nav);
}
return $page;
}
private function buildHeader(DifferentialRevision $revision) {
$view = id(new PHUIHeaderView())
->setHeader($revision->getTitle($revision))
->setUser($this->getViewer())
->setPolicyObject($revision)
->setHeaderIcon('fa-cog');
$status = $revision->getStatus();
$status_name =
DifferentialRevisionStatus::renderFullDescription($status);
$view->addProperty(PHUIHeaderView::PROPERTY_STATUS, $status_name);
return $view;
}
private function buildSubheaderView(DifferentialRevision $revision) {
$viewer = $this->getViewer();
$author_phid = $revision->getAuthorPHID();
$author = $viewer->renderHandle($author_phid)->render();
$date = phabricator_datetime($revision->getDateCreated(), $viewer);
$author = phutil_tag('strong', array(), $author);
$handles = $viewer->loadHandles(array($author_phid));
$image_uri = $handles[$author_phid]->getImageURI();
$image_href = $handles[$author_phid]->getURI();
$content = pht('Authored by %s on %s.', $author, $date);
return id(new PHUIHeadThingView())
->setImage($image_uri)
->setImageHref($image_href)
->setContent($content);
}
private function buildDetails(
DifferentialRevision $revision,
$custom_fields) {
$viewer = $this->getViewer();
$properties = id(new PHUIPropertyListView())
->setUser($viewer);
if ($custom_fields) {
$custom_fields->appendFieldsToPropertyList(
$revision,
$viewer,
$properties);
}
$header = id(new PHUIHeaderView())
->setHeader(pht('DETAILS'));
return id(new PHUIObjectBoxView())
->setHeader($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->appendChild($properties);
}
private function buildCurtain(DifferentialRevision $revision) {
$viewer = $this->getViewer();
$revision_id = $revision->getID();
$revision_phid = $revision->getPHID();
$curtain = $this->newCurtainView($revision);
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$revision,
PhabricatorPolicyCapability::CAN_EDIT);
$curtain->addAction(
id(new PhabricatorActionView())
->setIcon('fa-pencil')
->setHref("/differential/revision/edit/{$revision_id}/")
->setName(pht('Edit Revision'))
->setDisabled(!$can_edit)
->setWorkflow(!$can_edit));
$curtain->addAction(
id(new PhabricatorActionView())
->setIcon('fa-upload')
->setHref("/differential/revision/update/{$revision_id}/")
->setName(pht('Update Diff'))
->setDisabled(!$can_edit)
->setWorkflow(!$can_edit));
$this->requireResource('phabricator-object-selector-css');
$this->requireResource('javelin-behavior-phabricator-object-selector');
$curtain->addAction(
id(new PhabricatorActionView())
->setIcon('fa-link')
->setName(pht('Edit Dependencies'))
->setHref("/search/attach/{$revision_phid}/DREV/dependencies/")
->setWorkflow(true)
->setDisabled(!$can_edit));
$maniphest = 'PhabricatorManiphestApplication';
if (PhabricatorApplication::isClassInstalled($maniphest)) {
$curtain->addAction(
id(new PhabricatorActionView())
->setIcon('fa-anchor')
->setName(pht('Edit Maniphest Tasks'))
->setHref("/search/attach/{$revision_phid}/TASK/")
->setWorkflow(true)
->setDisabled(!$can_edit));
}
$request_uri = $this->getRequest()->getRequestURI();
$curtain->addAction(
id(new PhabricatorActionView())
->setIcon('fa-download')
->setName(pht('Download Raw Diff'))
->setHref($request_uri->alter('download', 'true')));
return $curtain;
}
private function buildCommentForm(
DifferentialRevision $revision,
$field_list) {
$viewer = $this->getViewer();
$draft = id(new PhabricatorDraft())->loadOneWhere( $draft = id(new PhabricatorDraft())->loadOneWhere(
'authorPHID = %s AND draftKey = %s', 'authorPHID = %s AND draftKey = %s',
$viewer->getPHID(), $viewer->getPHID(),
@ -361,8 +570,8 @@ final class DifferentialRevisionViewController extends DifferentialController {
} }
} }
$comment_form = new DifferentialAddCommentView(); $comment_form = id(new DifferentialAddCommentView())
$comment_form->setRevision($revision); ->setRevision($revision);
$review_warnings = array(); $review_warnings = array();
foreach ($field_list->getFields() as $field) { foreach ($field_list->getFields() as $field) {
@ -377,15 +586,15 @@ final class DifferentialRevisionViewController extends DifferentialController {
$comment_form->setInfoView($review_warnings_panel); $comment_form->setInfoView($review_warnings_panel);
} }
$comment_form->setActions($this->getRevisionCommentActions($revision));
$action_uri = $this->getApplicationURI( $action_uri = $this->getApplicationURI(
'comment/save/'.$revision->getID().'/'); 'comment/save/'.$revision->getID().'/');
$comment_form->setActionURI($action_uri); $comment_form->setActions($this->getRevisionCommentActions($revision))
$comment_form->setUser($viewer); ->setActionURI($action_uri)
$comment_form->setDraft($draft); ->setUser($viewer)
$comment_form->setReviewers(mpull($reviewers, 'getFullName', 'getPHID')); ->setDraft($draft)
$comment_form->setCCs(mpull($ccs, 'getFullName', 'getPHID')); ->setReviewers(mpull($reviewers, 'getFullName', 'getPHID'))
->setCCs(mpull($ccs, 'getFullName', 'getPHID'));
// TODO: This just makes the "Z" key work. Generalize this and remove // TODO: This just makes the "Z" key work. Generalize this and remove
// it at some point. // it at some point.
@ -395,162 +604,7 @@ final class DifferentialRevisionViewController extends DifferentialController {
'class' => 'differential-add-comment-panel', 'class' => 'differential-add-comment-panel',
), ),
$comment_form); $comment_form);
} return $comment_form;
$pane_id = celerity_generate_unique_node_id();
Javelin::initBehavior(
'differential-keyboard-navigation',
array(
'haunt' => $pane_id,
));
Javelin::initBehavior('differential-user-select');
$page_pane = id(new DifferentialPrimaryPaneView())
->setID($pane_id)
->appendChild($comment_view);
$signatures = DifferentialRequiredSignaturesField::loadForRevision(
$revision);
$missing_signatures = false;
foreach ($signatures as $phid => $signed) {
if (!$signed) {
$missing_signatures = true;
}
}
if ($missing_signatures) {
$signature_message = id(new PHUIInfoView())
->setErrors(
array(
array(
phutil_tag('strong', array(), pht('Content Hidden:')),
' ',
pht(
'The content of this revision is hidden until the author has '.
'signed all of the required legal agreements.'),
),
));
$page_pane->appendChild($signature_message);
} else {
$page_pane->appendChild(
array(
$diff_history,
$warning,
$local_view,
$toc_view,
$other_view,
$changeset_view,
));
}
if ($comment_form) {
$page_pane->appendChild($comment_form);
} else {
// TODO: For now, just use this to get "Login to Comment".
$page_pane->appendChild(
id(new PhabricatorApplicationTransactionCommentView())
->setUser($viewer)
->setRequestURI($request->getRequestURI()));
}
$object_id = 'D'.$revision->getID();
$operations_box = $this->buildOperationsBox($revision);
$content = array(
$operations_box,
$revision_detail_box,
$diff_detail_box,
$unit_box,
$page_pane,
);
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb($object_id, '/'.$object_id);
$prefs = $viewer->loadPreferences();
$pref_filetree = PhabricatorUserPreferences::PREFERENCE_DIFF_FILETREE;
if ($prefs->getPreference($pref_filetree)) {
$collapsed = $prefs->getPreference(
PhabricatorUserPreferences::PREFERENCE_NAV_COLLAPSED,
false);
$nav = id(new DifferentialChangesetFileTreeSideNavBuilder())
->setTitle('D'.$revision->getID())
->setBaseURI(new PhutilURI('/D'.$revision->getID()))
->setCollapsed((bool)$collapsed)
->build($changesets);
} else {
$nav = null;
}
$page = $this->newPage()
->setTitle($object_id.' '.$revision->getTitle())
->setCrumbs($crumbs)
->setPageObjectPHIDs(array($revision->getPHID()))
->appendChild($content);
if ($nav) {
$page->setNavigation($nav);
}
return $page;
}
private function getRevisionActions(DifferentialRevision $revision) {
$viewer = $this->getRequest()->getUser();
$revision_id = $revision->getID();
$revision_phid = $revision->getPHID();
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$revision,
PhabricatorPolicyCapability::CAN_EDIT);
$actions = array();
$actions[] = id(new PhabricatorActionView())
->setIcon('fa-pencil')
->setHref("/differential/revision/edit/{$revision_id}/")
->setName(pht('Edit Revision'))
->setDisabled(!$can_edit)
->setWorkflow(!$can_edit);
$actions[] = id(new PhabricatorActionView())
->setIcon('fa-upload')
->setHref("/differential/revision/update/{$revision_id}/")
->setName(pht('Update Diff'))
->setDisabled(!$can_edit)
->setWorkflow(!$can_edit);
$this->requireResource('phabricator-object-selector-css');
$this->requireResource('javelin-behavior-phabricator-object-selector');
$actions[] = id(new PhabricatorActionView())
->setIcon('fa-link')
->setName(pht('Edit Dependencies'))
->setHref("/search/attach/{$revision_phid}/DREV/dependencies/")
->setWorkflow(true)
->setDisabled(!$can_edit);
$maniphest = 'PhabricatorManiphestApplication';
if (PhabricatorApplication::isClassInstalled($maniphest)) {
$actions[] = id(new PhabricatorActionView())
->setIcon('fa-anchor')
->setName(pht('Edit Maniphest Tasks'))
->setHref("/search/attach/{$revision_phid}/TASK/")
->setWorkflow(true)
->setDisabled(!$can_edit);
}
$request_uri = $this->getRequest()->getRequestURI();
$actions[] = id(new PhabricatorActionView())
->setIcon('fa-download')
->setName(pht('Download Raw Diff'))
->setHref($request_uri->alter('download', 'true'));
return $actions;
} }
private function getRevisionCommentActions(DifferentialRevision $revision) { private function getRevisionCommentActions(DifferentialRevision $revision) {
@ -558,7 +612,7 @@ final class DifferentialRevisionViewController extends DifferentialController {
DifferentialAction::ACTION_COMMENT => true, DifferentialAction::ACTION_COMMENT => true,
); );
$viewer = $this->getRequest()->getUser(); $viewer = $this->getViewer();
$viewer_phid = $viewer->getPHID(); $viewer_phid = $viewer->getPHID();
$viewer_is_owner = ($viewer_phid == $revision->getAuthorPHID()); $viewer_is_owner = ($viewer_phid == $revision->getAuthorPHID());
$viewer_is_reviewer = in_array($viewer_phid, $revision->getReviewers()); $viewer_is_reviewer = in_array($viewer_phid, $revision->getReviewers());
@ -814,11 +868,12 @@ final class DifferentialRevisionViewController extends DifferentialController {
$viewer = $this->getViewer(); $viewer = $this->getViewer();
$header = id(new PHUIHeaderView()) $header = id(new PHUIHeaderView())
->setHeader(pht('Recent Similar Open Revisions')); ->setHeader(pht('Recent Similar Revisions'));
$view = id(new DifferentialRevisionListView()) $view = id(new DifferentialRevisionListView())
->setHeader($header) ->setHeader($header)
->setRevisions($revisions) ->setRevisions($revisions)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setUser($viewer); ->setUser($viewer);
$phids = $view->getRequiredHandlePHIDs(); $phids = $view->getRequiredHandlePHIDs();
@ -845,7 +900,7 @@ final class DifferentialRevisionViewController extends DifferentialController {
assert_instances_of($changesets, 'DifferentialChangeset'); assert_instances_of($changesets, 'DifferentialChangeset');
assert_instances_of($vs_changesets, 'DifferentialChangeset'); assert_instances_of($vs_changesets, 'DifferentialChangeset');
$viewer = $this->getRequest()->getUser(); $viewer = $this->getViewer();
id(new DifferentialHunkQuery()) id(new DifferentialHunkQuery())
->setViewer($viewer) ->setViewer($viewer)
@ -978,7 +1033,8 @@ final class DifferentialRevisionViewController extends DifferentialController {
} }
$box = id(new PHUIObjectBoxView()) $box = id(new PHUIObjectBoxView())
->setHeaderText(pht('Diff Detail')) ->setHeaderText(pht('DIFF DETAIL'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setUser($viewer); ->setUser($viewer);
$last_tab = null; $last_tab = null;
@ -1061,7 +1117,8 @@ final class DifferentialRevisionViewController extends DifferentialController {
} }
$box_view = id(new PHUIObjectBoxView()) $box_view = id(new PHUIObjectBoxView())
->setHeaderText(pht('Active Operations')); ->setHeaderText(pht('ACTIVE OPERATIONS'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);
return id(new DrydockRepositoryOperationStatusView()) return id(new DrydockRepositoryOperationStatusView())
->setUser($viewer) ->setUser($viewer)
@ -1074,11 +1131,11 @@ final class DifferentialRevisionViewController extends DifferentialController {
DifferentialRevision $revision) { DifferentialRevision $revision) {
$viewer = $this->getViewer(); $viewer = $this->getViewer();
if (!$diff->getUnitMessages()) { if (!$diff->getBuildable()) {
return null; return null;
} }
if (!$diff->getBuildable()) { if (!$diff->getUnitMessages()) {
return null; return null;
} }
@ -1109,6 +1166,7 @@ final class DifferentialRevisionViewController extends DifferentialController {
->setBuildable($diff->getBuildable()) ->setBuildable($diff->getBuildable())
->setUnitMessages($diff->getUnitMessages()) ->setUnitMessages($diff->getUnitMessages())
->setLimit(5) ->setLimit(5)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setShowViewAll(true); ->setShowViewAll(true);
} }

View file

@ -20,7 +20,7 @@ final class DifferentialAuthorField
} }
public function shouldAppearInPropertyView() { public function shouldAppearInPropertyView() {
return true; return false;
} }
public function renderPropertyViewLabel() { public function renderPropertyViewLabel() {

View file

@ -70,8 +70,6 @@ final class DifferentialHovercardEngineExtension
$hovercard->addField(pht('Summary'), $summary); $hovercard->addField(pht('Summary'), $summary);
} }
$tag = DifferentialRevisionDetailView::renderTagForRevision($revision);
$hovercard->addTag($tag);
} }
} }

View file

@ -163,7 +163,7 @@ final class DifferentialAddCommentView extends AphrontView {
$is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
$header_text = $is_serious $header_text = $is_serious
? pht('Add Comment') ? pht('Add Comment')
: pht('Leap Into Action'); : pht('Leap Into Action!');
$header = id(new PHUIHeaderView()) $header = id(new PHUIHeaderView())
->setHeader($header_text); ->setHeader($header_text);

View file

@ -8,6 +8,8 @@ final class DifferentialChangesetListView extends AphrontView {
private $inlineURI; private $inlineURI;
private $renderURI = '/differential/changeset/'; private $renderURI = '/differential/changeset/';
private $whitespace; private $whitespace;
private $background;
private $header;
private $standaloneURI; private $standaloneURI;
private $leftRawFileURI; private $leftRawFileURI;
@ -112,6 +114,16 @@ final class DifferentialChangesetListView extends AphrontView {
return $this; return $this;
} }
public function setBackground($background) {
$this->background = $background;
return $this;
}
public function setHeader($header) {
$this->header = $header;
return $this;
}
public function render() { public function render() {
$viewer = $this->getViewer(); $viewer = $this->getViewer();
@ -240,8 +252,12 @@ final class DifferentialChangesetListView extends AphrontView {
)); ));
} }
if ($this->header) {
$header = $this->header;
} else {
$header = id(new PHUIHeaderView()) $header = id(new PHUIHeaderView())
->setHeader($this->getTitle()); ->setHeader($this->getTitle());
}
$content = phutil_tag( $content = phutil_tag(
'div', 'div',
@ -253,6 +269,7 @@ final class DifferentialChangesetListView extends AphrontView {
$object_box = id(new PHUIObjectBoxView()) $object_box = id(new PHUIObjectBoxView())
->setHeader($header) ->setHeader($header)
->setBackground($this->background)
->setCollapsed(true) ->setCollapsed(true)
->appendChild($content); ->appendChild($content);

View file

@ -127,6 +127,7 @@ final class DifferentialLocalCommitsView extends AphrontView {
return id(new PHUIObjectBoxView()) return id(new PHUIObjectBoxView())
->setHeaderText(pht('Local Commits')) ->setHeaderText(pht('Local Commits'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($table); ->setTable($table);
} }

View file

@ -1,23 +0,0 @@
<?php
final class DifferentialPrimaryPaneView extends AphrontView {
private $id;
public function setID($id) {
$this->id = $id;
return $this;
}
public function render() {
return phutil_tag(
'div',
array(
'class' => 'differential-primary-pane',
'id' => $this->id,
),
$this->renderChildren());
}
}

View file

@ -1,121 +0,0 @@
<?php
final class DifferentialRevisionDetailView extends AphrontView {
private $revision;
private $actions;
private $customFields;
private $diff;
private $uri;
private $actionList;
public function setURI($uri) {
$this->uri = $uri;
return $this;
}
public function getURI() {
return $this->uri;
}
public function setDiff(DifferentialDiff $diff) {
$this->diff = $diff;
return $this;
}
private function getDiff() {
return $this->diff;
}
public function setRevision(DifferentialRevision $revision) {
$this->revision = $revision;
return $this;
}
public function setActions(array $actions) {
$this->actions = $actions;
return $this;
}
private function getActions() {
return $this->actions;
}
public function setActionList(PhabricatorActionListView $list) {
$this->actionList = $list;
return $this;
}
public function getActionList() {
return $this->actionList;
}
public function setCustomFields(PhabricatorCustomFieldList $list) {
$this->customFields = $list;
return $this;
}
public function render() {
$this->requireResource('differential-core-view-css');
$revision = $this->revision;
$user = $this->getUser();
$header = $this->renderHeader($revision);
$actions = id(new PhabricatorActionListView())
->setUser($user)
->setObject($revision);
foreach ($this->getActions() as $action) {
$actions->addAction($action);
}
$properties = id(new PHUIPropertyListView())
->setUser($user)
->setObject($revision);
$properties->setHasKeyboardShortcuts(true);
$properties->setActionList($actions);
$this->setActionList($actions);
$field_list = $this->customFields;
if ($field_list) {
$field_list->appendFieldsToPropertyList(
$revision,
$user,
$properties);
}
$object_box = id(new PHUIObjectBoxView())
->setHeader($header)
->addPropertyList($properties);
return $object_box;
}
private function renderHeader(DifferentialRevision $revision) {
$view = id(new PHUIHeaderView())
->setHeader($revision->getTitle($revision))
->setUser($this->getUser())
->setPolicyObject($revision);
$status = $revision->getStatus();
$status_name =
DifferentialRevisionStatus::renderFullDescription($status);
$view->addProperty(PHUIHeaderView::PROPERTY_STATUS, $status_name);
return $view;
}
public static function renderTagForRevision(
DifferentialRevision $revision) {
$status = $revision->getStatus();
$status_name =
ArcanistDifferentialRevisionStatus::getNameForRevisionStatus($status);
return id(new PHUITagView())
->setType(PHUITagView::TYPE_STATE)
->setName($status_name);
}
}

View file

@ -11,6 +11,7 @@ final class DifferentialRevisionListView extends AphrontView {
private $header; private $header;
private $noDataString; private $noDataString;
private $noBox; private $noBox;
private $background = null;
public function setNoDataString($no_data_string) { public function setNoDataString($no_data_string) {
$this->noDataString = $no_data_string; $this->noDataString = $no_data_string;
@ -38,6 +39,11 @@ final class DifferentialRevisionListView extends AphrontView {
return $this; return $this;
} }
public function setBackground($background) {
$this->background = $background;
return $this;
}
public function getRequiredHandlePHIDs() { public function getRequiredHandlePHIDs() {
$phids = array(); $phids = array();
foreach ($this->revisions as $revision) { foreach ($this->revisions as $revision) {
@ -192,6 +198,7 @@ final class DifferentialRevisionListView extends AphrontView {
if ($this->header && !$this->noBox) { if ($this->header && !$this->noBox) {
$list->setFlush(true); $list->setFlush(true);
$list = id(new PHUIObjectBoxView()) $list = id(new PHUIObjectBoxView())
->setBackground($this->background)
->setObjectList($list); ->setObjectList($list);
if ($this->header instanceof PHUIHeaderView) { if ($this->header instanceof PHUIHeaderView) {

View file

@ -305,7 +305,7 @@ final class DifferentialRevisionUpdateHistoryView extends AphrontView {
return id(new PHUIObjectBoxView()) return id(new PHUIObjectBoxView())
->setHeaderText(pht('Revision Update History')) ->setHeaderText(pht('Revision Update History'))
->setFlush(true) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($content); ->setTable($content);
} }

View file

@ -48,26 +48,37 @@ final class DiffusionBranchTableController extends DiffusionController {
->withRepository($repository) ->withRepository($repository)
->execute(); ->execute();
$view = id(new DiffusionBranchTableView()) $table = id(new DiffusionBranchTableView())
->setUser($viewer) ->setUser($viewer)
->setBranches($branches) ->setBranches($branches)
->setCommits($commits) ->setCommits($commits)
->setDiffusionRequest($drequest); ->setDiffusionRequest($drequest);
$panel = id(new PHUIObjectBoxView()) $content = id(new PHUIObjectBoxView())
->setHeaderText(pht('Branches')) ->setHeaderText($repository->getName())
->setTable($view); ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($table);
$content = $panel;
} }
$crumbs = $this->buildCrumbs( $crumbs = $this->buildCrumbs(
array( array(
'branches' => true, 'branches' => true,
)); ));
$crumbs->setBorder(true);
$pager_box = $this->renderTablePagerBox($pager); $pager_box = $this->renderTablePagerBox($pager);
$header = id(new PHUIHeaderView())
->setHeader(pht('Branches'))
->setHeaderIcon('fa-code-fork');
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter(array(
$content,
$pager_box,
));
return $this->newPage() return $this->newPage()
->setTitle( ->setTitle(
array( array(
@ -77,8 +88,7 @@ final class DiffusionBranchTableController extends DiffusionController {
->setCrumbs($crumbs) ->setCrumbs($crumbs)
->appendChild( ->appendChild(
array( array(
$content, $view,
$pager_box,
)); ));
} }

View file

@ -55,20 +55,17 @@ final class DiffusionBrowseController extends DiffusionController {
} }
private function browseSearch() { private function browseSearch() {
$drequest = $this->getDiffusionRequest(); $drequest = $this->getDiffusionRequest();
$header = $this->buildHeaderView($drequest);
$actions = $this->buildActionView($drequest); $search_form = $this->renderSearchForm();
$properties = $this->buildPropertyView($drequest, $actions); $search_results = $this->renderSearchResults();
$object_box = id(new PHUIObjectBoxView()) $search_form = id(new PHUIObjectBoxView())
->setHeader($this->buildHeaderView($drequest)) ->setHeaderText(pht('Search'))
->addPropertyList($properties); ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->appendChild($search_form);
$content = array();
$content[] = $object_box;
$content[] = $this->renderSearchForm($collapsed = false);
$content[] = $this->renderSearchResults();
$crumbs = $this->buildCrumbs( $crumbs = $this->buildCrumbs(
array( array(
@ -76,6 +73,14 @@ final class DiffusionBrowseController extends DiffusionController {
'path' => true, 'path' => true,
'view' => 'browse', 'view' => 'browse',
)); ));
$crumbs->setBorder(true);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter(array(
$search_form,
$search_results,
));
return $this->newPage() return $this->newPage()
->setTitle( ->setTitle(
@ -84,7 +89,7 @@ final class DiffusionBrowseController extends DiffusionController {
$drequest->getRepository()->getDisplayName(), $drequest->getRepository()->getDisplayName(),
)) ))
->setCrumbs($crumbs) ->setCrumbs($crumbs)
->appendChild($content); ->appendChild($view);
} }
private function browseFile() { private function browseFile() {
@ -187,7 +192,25 @@ final class DiffusionBrowseController extends DiffusionController {
} }
$data = $file->loadFileData(); $data = $file->loadFileData();
if (ArcanistDiffUtils::isHeuristicBinaryFile($data)) {
$ref = $this->getGitLFSRef($repository, $data);
if ($ref) {
if ($view == 'git-lfs') {
$file = $this->loadGitLFSFile($ref);
// Rename the file locally so we generate a better vanity URI for
// it. In storage, it just has a name like "lfs-13f9a94c0923...",
// since we don't get any hints about possible human-readable names
// at upload time.
$basename = basename($drequest->getPath());
$file->makeEphemeral();
$file->setName($basename);
return $file->getRedirectResponse();
} else {
$corpus = $this->buildGitLFSCorpus($ref);
}
} else if (ArcanistDiffUtils::isHeuristicBinaryFile($data)) {
$file_uri = $file->getBestURI(); $file_uri = $file->getBestURI();
if ($file->isViewableImage()) { if ($file->isViewableImage()) {
@ -218,20 +241,18 @@ final class DiffusionBrowseController extends DiffusionController {
require_celerity_resource('diffusion-source-css'); require_celerity_resource('diffusion-source-css');
// Render the page. // Render the page.
$view = $this->buildActionView($drequest); $view = $this->buildCurtain($drequest);
$action_list = $this->enrichActionView( $curtain = $this->enrichCurtain(
$view, $view,
$drequest, $drequest,
$show_blame, $show_blame,
$show_color); $show_color);
$properties = $this->buildPropertyView($drequest, $action_list); $properties = $this->buildPropertyView($drequest);
$object_box = id(new PHUIObjectBoxView()) $header = $this->buildHeaderView($drequest);
->setHeader($this->buildHeaderView($drequest)) $header->setHeaderIcon('fa-file-code-o');
->addPropertyList($properties);
$content = array(); $content = array();
$content[] = $object_box;
$follow = $request->getStr('follow'); $follow = $request->getStr('follow');
if ($follow) { if ($follow) {
@ -277,17 +298,31 @@ final class DiffusionBrowseController extends DiffusionController {
'path' => true, 'path' => true,
'view' => 'browse', 'view' => 'browse',
)); ));
$crumbs->setBorder(true);
$basename = basename($this->getDiffusionRequest()->getPath()); $basename = basename($this->getDiffusionRequest()->getPath());
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setCurtain($curtain)
->setMainColumn(array(
$content,
));
if ($properties) {
$view->addPropertySection(pht('DETAILS'), $properties);
}
$title = array($basename, $repository->getDisplayName());
return $this->newPage() return $this->newPage()
->setTitle( ->setTitle($title)
array(
$basename,
$repository->getDisplayName(),
))
->setCrumbs($crumbs) ->setCrumbs($crumbs)
->appendChild($content); ->appendChild(
array(
$view,
));
} }
public function browseDirectory( public function browseDirectory(
@ -300,23 +335,21 @@ final class DiffusionBrowseController extends DiffusionController {
$reason = $results->getReasonForEmptyResultSet(); $reason = $results->getReasonForEmptyResultSet();
$content = array(); $curtain = $this->buildCurtain($drequest);
$actions = $this->buildActionView($drequest); $details = $this->buildPropertyView($drequest);
$properties = $this->buildPropertyView($drequest, $actions);
$object_box = id(new PHUIObjectBoxView()) $header = $this->buildHeaderView($drequest);
->setHeader($this->buildHeaderView($drequest)) $header->setHeaderIcon('fa-folder-open');
->addPropertyList($properties);
$content[] = $object_box; $search_form = $this->renderSearchForm();
$content[] = $this->renderSearchForm($collapsed = true);
$empty_result = null;
$browse_panel = null;
if (!$results->isValidResults()) { if (!$results->isValidResults()) {
$empty_result = new DiffusionEmptyResultView(); $empty_result = new DiffusionEmptyResultView();
$empty_result->setDiffusionRequest($drequest); $empty_result->setDiffusionRequest($drequest);
$empty_result->setDiffusionBrowseResultSet($results); $empty_result->setDiffusionBrowseResultSet($results);
$empty_result->setView($request->getStr('view')); $empty_result->setView($request->getStr('view'));
$content[] = $empty_result;
} else { } else {
$phids = array(); $phids = array();
foreach ($results->getPaths() as $result) { foreach ($results->getPaths() as $result) {
@ -331,21 +364,30 @@ final class DiffusionBrowseController extends DiffusionController {
$phids = array_keys($phids); $phids = array_keys($phids);
$handles = $this->loadViewerHandles($phids); $handles = $this->loadViewerHandles($phids);
$browse_table = new DiffusionBrowseTableView(); $browse_table = id(new DiffusionBrowseTableView())
$browse_table->setDiffusionRequest($drequest); ->setDiffusionRequest($drequest)
$browse_table->setHandles($handles); ->setHandles($handles)
$browse_table->setPaths($results->getPaths()); ->setPaths($results->getPaths())
$browse_table->setUser($request->getUser()); ->setUser($request->getUser());
$browse_panel = new PHUIObjectBoxView(); $browse_header = id(new PHUIHeaderView())
$browse_panel->setHeaderText($drequest->getPath(), '/'); ->setHeader(nonempty(basename($drequest->getPath()), '/'))
$browse_panel->setTable($browse_table); ->setHeaderIcon('fa-folder-open');
$content[] = $browse_panel; $browse_panel = id(new PHUIObjectBoxView())
->setHeader($browse_header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($browse_table);
$browse_panel->setShowHide(
array(pht('Show Search')),
pht('Hide Search'),
$search_form,
'#');
} }
$content[] = $this->buildOpenRevisions(); $open_revisions = $this->buildOpenRevisions();
$content[] = $this->renderDirectoryReadme($results); $readme = $this->renderDirectoryReadme($results);
$crumbs = $this->buildCrumbs( $crumbs = $this->buildCrumbs(
array( array(
@ -355,18 +397,34 @@ final class DiffusionBrowseController extends DiffusionController {
)); ));
$pager_box = $this->renderTablePagerBox($pager); $pager_box = $this->renderTablePagerBox($pager);
$crumbs->setBorder(true);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setCurtain($curtain)
->setMainColumn(array(
$empty_result,
$browse_panel,
))
->setFooter(array(
$open_revisions,
$readme,
$pager_box,
));
if ($details) {
$view->addPropertySection(pht('DETAILS'), $details);
}
return $this->newPage() return $this->newPage()
->setTitle( ->setTitle(array(
array(
nonempty(basename($drequest->getPath()), '/'), nonempty(basename($drequest->getPath()), '/'),
$repository->getDisplayName(), $repository->getDisplayName(),
)) ))
->setCrumbs($crumbs) ->setCrumbs($crumbs)
->appendChild( ->appendChild(
array( array(
$content, $view,
$pager_box,
)); ));
} }
@ -431,6 +489,7 @@ final class DiffusionBrowseController extends DiffusionController {
$box = id(new PHUIObjectBoxView()) $box = id(new PHUIObjectBoxView())
->setHeaderText($header) ->setHeaderText($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($table); ->setTable($table);
$pager_box = $this->renderTablePagerBox($pager); $pager_box = $this->renderTablePagerBox($pager);
@ -697,12 +756,14 @@ final class DiffusionBrowseController extends DiffusionController {
$edit = $this->renderEditButton(); $edit = $this->renderEditButton();
$file = $this->renderFileButton(); $file = $this->renderFileButton();
$header = id(new PHUIHeaderView()) $header = id(new PHUIHeaderView())
->setHeader(pht('File Contents')) ->setHeader(basename($this->getDiffusionRequest()->getPath()))
->setHeaderIcon('fa-file-code-o')
->addActionLink($edit) ->addActionLink($edit)
->addActionLink($file); ->addActionLink($file);
$corpus = id(new PHUIObjectBoxView()) $corpus = id(new PHUIObjectBoxView())
->setHeader($header) ->setHeader($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->appendChild($corpus) ->appendChild($corpus)
->setCollapsed(true); ->setCollapsed(true);
@ -737,16 +798,16 @@ final class DiffusionBrowseController extends DiffusionController {
return $corpus; return $corpus;
} }
private function enrichActionView( private function enrichCurtain(
PhabricatorActionListView $view, PHUICurtainView $curtain,
DiffusionRequest $drequest, DiffusionRequest $drequest,
$show_blame, $show_blame,
$show_color) { $show_color) {
$viewer = $this->getRequest()->getUser(); $viewer = $this->getViewer();
$base_uri = $this->getRequest()->getRequestURI(); $base_uri = $this->getRequest()->getRequestURI();
$view->addAction( $curtain->addAction(
id(new PhabricatorActionView()) id(new PhabricatorActionView())
->setName(pht('Show Last Change')) ->setName(pht('Show Last Change'))
->setHref( ->setHref(
@ -766,7 +827,7 @@ final class DiffusionBrowseController extends DiffusionController {
$blame_value = 1; $blame_value = 1;
} }
$view->addAction( $curtain->addAction(
id(new PhabricatorActionView()) id(new PhabricatorActionView())
->setName($blame_text) ->setName($blame_text)
->setHref($base_uri->alter('blame', $blame_value)) ->setHref($base_uri->alter('blame', $blame_value))
@ -784,7 +845,7 @@ final class DiffusionBrowseController extends DiffusionController {
$highlight_value = 1; $highlight_value = 1;
} }
$view->addAction( $curtain->addAction(
id(new PhabricatorActionView()) id(new PhabricatorActionView())
->setName($highlight_text) ->setName($highlight_text)
->setHref($base_uri->alter('color', $highlight_value)) ->setHref($base_uri->alter('color', $highlight_value))
@ -809,14 +870,57 @@ final class DiffusionBrowseController extends DiffusionController {
))->alter('lint', ''); ))->alter('lint', '');
} }
$view->addAction( $curtain->addAction(
id(new PhabricatorActionView()) id(new PhabricatorActionView())
->setName($lint_text) ->setName($lint_text)
->setHref($href) ->setHref($href)
->setIcon('fa-exclamation-triangle') ->setIcon('fa-exclamation-triangle')
->setDisabled(!$href)); ->setDisabled(!$href));
return $view;
$repository = $drequest->getRepository();
$owners = 'PhabricatorOwnersApplication';
if (PhabricatorApplication::isClassInstalled($owners)) {
$package_query = id(new PhabricatorOwnersPackageQuery())
->setViewer($viewer)
->withStatuses(array(PhabricatorOwnersPackage::STATUS_ACTIVE))
->withControl(
$repository->getPHID(),
array(
$drequest->getPath(),
));
$package_query->execute();
$packages = $package_query->getControllingPackagesForPath(
$repository->getPHID(),
$drequest->getPath());
if ($packages) {
$ownership = id(new PHUIStatusListView())
->setUser($viewer);
foreach ($packages as $package) {
$icon = 'fa-list-alt';
$color = 'grey';
$item = id(new PHUIStatusItemView())
->setIcon($icon, $color)
->setTarget($viewer->renderHandle($package->getPHID()));
$ownership->addItem($item);
}
} else {
$ownership = phutil_tag('em', array(), pht('None'));
}
$curtain->newPanel()
->setHeaderText(pht('Owners'))
->appendChild($ownership);
}
return $curtain;
} }
private function renderEditButton() { private function renderEditButton() {
@ -844,7 +948,7 @@ final class DiffusionBrowseController extends DiffusionController {
return $button; return $button;
} }
private function renderFileButton($file_uri = null) { private function renderFileButton($file_uri = null, $label = null) {
$base_uri = $this->getRequest()->getRequestURI(); $base_uri = $this->getRequest()->getRequestURI();
@ -858,6 +962,10 @@ final class DiffusionBrowseController extends DiffusionController {
$icon = 'fa-file-text'; $icon = 'fa-file-text';
} }
if ($label !== null) {
$text = $label;
}
$button = id(new PHUIButtonView()) $button = id(new PHUIButtonView())
->setTag('a') ->setTag('a')
->setText($text) ->setText($text)
@ -867,6 +975,21 @@ final class DiffusionBrowseController extends DiffusionController {
return $button; return $button;
} }
private function renderGitLFSButton() {
$viewer = $this->getViewer();
$uri = $this->getRequest()->getRequestURI();
$href = $uri->alter('view', 'git-lfs');
$text = pht('Download from Git LFS');
$icon = 'fa-download';
return id(new PHUIButtonView())
->setTag('a')
->setText($text)
->setHref($href)
->setIcon($icon);
}
private function buildDisplayRows( private function buildDisplayRows(
array $lines, array $lines,
@ -1265,11 +1388,13 @@ final class DiffusionBrowseController extends DiffusionController {
$file = $this->renderFileButton($file_uri); $file = $this->renderFileButton($file_uri);
$header = id(new PHUIHeaderView()) $header = id(new PHUIHeaderView())
->setHeader(pht('Image')) ->setHeader(basename($this->getDiffusionRequest()->getPath()))
->addActionLink($file); ->addActionLink($file)
->setHeaderIcon('fa-file-image-o');
return id(new PHUIObjectBoxView()) return id(new PHUIObjectBoxView())
->setHeader($header) ->setHeader($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($properties); ->addPropertyList($properties);
} }
@ -1282,11 +1407,12 @@ final class DiffusionBrowseController extends DiffusionController {
$file = $this->renderFileButton($file_uri); $file = $this->renderFileButton($file_uri);
$header = id(new PHUIHeaderView()) $header = id(new PHUIHeaderView())
->setHeader(pht('Details')) ->setHeader(pht('DETAILS'))
->addActionLink($file); ->addActionLink($file);
$box = id(new PHUIObjectBoxView()) $box = id(new PHUIObjectBoxView())
->setHeader($header) ->setHeader($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->appendChild($text); ->appendChild($text);
return $box; return $box;
@ -1298,7 +1424,7 @@ final class DiffusionBrowseController extends DiffusionController {
->appendChild($message); ->appendChild($message);
$header = id(new PHUIHeaderView()) $header = id(new PHUIHeaderView())
->setHeader(pht('Details')); ->setHeader(pht('DETAILS'));
$box = id(new PHUIObjectBoxView()) $box = id(new PHUIObjectBoxView())
->setHeader($header) ->setHeader($header)
@ -1461,12 +1587,12 @@ final class DiffusionBrowseController extends DiffusionController {
return "{$summary}\n{$date} \xC2\xB7 {$author}"; return "{$summary}\n{$date} \xC2\xB7 {$author}";
} }
protected function renderSearchForm($collapsed) { protected function renderSearchForm() {
$drequest = $this->getDiffusionRequest(); $drequest = $this->getDiffusionRequest();
$forms = array(); $forms = array();
$form = id(new AphrontFormView()) $form = id(new AphrontFormView())
->setUser($this->getRequest()->getUser()) ->setUser($this->getViewer())
->setMethod('GET'); ->setMethod('GET');
switch ($drequest->getRepository()->getVersionControlSystem()) { switch ($drequest->getRepository()->getVersionControlSystem()) {
@ -1492,22 +1618,10 @@ final class DiffusionBrowseController extends DiffusionController {
break; break;
} }
$filter = new AphrontListFilterView(); require_celerity_resource('diffusion-icons-css');
$filter->appendChild($forms); $form_box = phutil_tag_div('diffusion-search-boxen', $forms);
if ($collapsed) { return $form_box;
$filter->setCollapsed(
pht('Show Search'),
pht('Hide Search'),
pht('Search for file names or content in this directory.'),
'#');
}
$filter = id(new PHUIBoxView())
->addClass('mlt mlb')
->appendChild($filter);
return $filter;
} }
protected function markupText($text) { protected function markupText($text) {
@ -1526,28 +1640,29 @@ final class DiffusionBrowseController extends DiffusionController {
} }
protected function buildHeaderView(DiffusionRequest $drequest) { protected function buildHeaderView(DiffusionRequest $drequest) {
$viewer = $this->getRequest()->getUser(); $viewer = $this->getViewer();
$tag = $this->renderCommitHashTag($drequest);
$header = id(new PHUIHeaderView()) $header = id(new PHUIHeaderView())
->setUser($viewer) ->setUser($viewer)
->setHeader($this->renderPathLinks($drequest, $mode = 'browse')) ->setHeader($this->renderPathLinks($drequest, $mode = 'browse'))
->setPolicyObject($drequest->getRepository()); ->addTag($tag);
return $header; return $header;
} }
protected function buildActionView(DiffusionRequest $drequest) { protected function buildCurtain(DiffusionRequest $drequest) {
$viewer = $this->getRequest()->getUser(); $viewer = $this->getViewer();
$view = id(new PhabricatorActionListView()) $curtain = $this->newCurtainView($drequest);
->setUser($viewer);
$history_uri = $drequest->generateURI( $history_uri = $drequest->generateURI(
array( array(
'action' => 'history', 'action' => 'history',
)); ));
$view->addAction( $curtain->addAction(
id(new PhabricatorActionView()) id(new PhabricatorActionView())
->setName(pht('View History')) ->setName(pht('View History'))
->setHref($history_uri) ->setHref($history_uri)
@ -1559,40 +1674,22 @@ final class DiffusionBrowseController extends DiffusionController {
'commit' => '', 'commit' => '',
'action' => 'browse', 'action' => 'browse',
)); ));
$view->addAction( $curtain->addAction(
id(new PhabricatorActionView()) id(new PhabricatorActionView())
->setName(pht('Jump to HEAD')) ->setName(pht('Jump to HEAD'))
->setHref($head_uri) ->setHref($head_uri)
->setIcon('fa-home') ->setIcon('fa-home')
->setDisabled(!$behind_head)); ->setDisabled(!$behind_head));
return $view; return $curtain;
} }
protected function buildPropertyView( protected function buildPropertyView(
DiffusionRequest $drequest, DiffusionRequest $drequest) {
PhabricatorActionListView $actions) {
$viewer = $this->getViewer(); $viewer = $this->getViewer();
$view = id(new PHUIPropertyListView()) $view = id(new PHUIPropertyListView())
->setUser($viewer) ->setUser($viewer);
->setActionList($actions);
$stable_commit = $drequest->getStableCommit();
$view->addProperty(
pht('Commit'),
phutil_tag(
'a',
array(
'href' => $drequest->generateURI(
array(
'action' => 'commit',
'commit' => $stable_commit,
)),
),
$drequest->getRepository()->formatCommitName($stable_commit)));
if ($drequest->getSymbolicType() == 'tag') { if ($drequest->getSymbolicType() == 'tag') {
$symbolic = $drequest->getSymbolicCommit(); $symbolic = $drequest->getSymbolicCommit();
@ -1616,49 +1713,13 @@ final class DiffusionBrowseController extends DiffusionController {
} }
} }
$repository = $drequest->getRepository(); if ($view->hasAnyProperties()) {
$owners = 'PhabricatorOwnersApplication';
if (PhabricatorApplication::isClassInstalled($owners)) {
$package_query = id(new PhabricatorOwnersPackageQuery())
->setViewer($viewer)
->withStatuses(array(PhabricatorOwnersPackage::STATUS_ACTIVE))
->withControl(
$repository->getPHID(),
array(
$drequest->getPath(),
));
$package_query->execute();
$packages = $package_query->getControllingPackagesForPath(
$repository->getPHID(),
$drequest->getPath());
if ($packages) {
$ownership = id(new PHUIStatusListView())
->setUser($viewer);
foreach ($packages as $package) {
$icon = 'fa-list-alt';
$color = 'grey';
$item = id(new PHUIStatusItemView())
->setIcon($icon, $color)
->setTarget($viewer->renderHandle($package->getPHID()));
$ownership->addItem($item);
}
} else {
$ownership = phutil_tag('em', array(), pht('None'));
}
$view->addProperty(pht('Packages'), $ownership);
}
return $view; return $view;
} }
return null;
}
private function buildOpenRevisions() { private function buildOpenRevisions() {
$viewer = $this->getViewer(); $viewer = $this->getViewer();
@ -1865,4 +1926,90 @@ final class DiffusionBrowseController extends DiffusionController {
$corpus); $corpus);
} }
private function getGitLFSRef(PhabricatorRepository $repository, $data) {
if (!$repository->canUseGitLFS()) {
return null;
}
$lfs_pattern = '(^version https://git-lfs\\.github\\.com/spec/v1[\r\n])';
if (!preg_match($lfs_pattern, $data)) {
return null;
}
$matches = null;
if (!preg_match('(^oid sha256:(.*)$)m', $data, $matches)) {
return null;
}
$hash = $matches[1];
$hash = trim($hash);
return id(new PhabricatorRepositoryGitLFSRefQuery())
->setViewer($this->getViewer())
->withRepositoryPHIDs(array($repository->getPHID()))
->withObjectHashes(array($hash))
->executeOne();
}
private function buildGitLFSCorpus(PhabricatorRepositoryGitLFSRef $ref) {
// TODO: We should probably test if we can load the file PHID here and
// show the user an error if we can't, rather than making them click
// through to hit an error.
$header = id(new PHUIHeaderView())
->setHeader(basename($this->getDiffusionRequest()->getPath()))
->setHeaderIcon('fa-archive');
$severity = PHUIInfoView::SEVERITY_NOTICE;
$messages = array();
$messages[] = pht(
'This %s file is stored in Git Large File Storage.',
phutil_format_bytes($ref->getByteSize()));
try {
$file = $this->loadGitLFSFile($ref);
$data = $this->renderGitLFSButton();
$header->addActionLink($data);
} catch (Exception $ex) {
$severity = PHUIInfoView::SEVERITY_ERROR;
$messages[] = pht('The data for this file could not be loaded.');
}
$raw = $this->renderFileButton(null, pht('View Raw LFS Pointer'));
$header->addActionLink($raw);
$corpus = id(new PHUIObjectBoxView())
->setHeader($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setCollapsed(true);
if ($messages) {
$corpus->setInfoView(
id(new PHUIInfoView())
->setSeverity($severity)
->setErrors($messages));
}
return $corpus;
}
private function loadGitLFSFile(PhabricatorRepositoryGitLFSRef $ref) {
$viewer = $this->getViewer();
$file = id(new PhabricatorFileQuery())
->setViewer($viewer)
->withPHIDs(array($ref->getFilePHID()))
->executeOne();
if (!$file) {
throw new Exception(
pht(
'Failed to load file object for Git LFS ref "%s"!',
$ref->getObjectHash()));
}
return $file;
}
} }

View file

@ -15,8 +15,6 @@ final class DiffusionChangeController extends DiffusionController {
$viewer = $this->getViewer(); $viewer = $this->getViewer();
$drequest = $this->getDiffusionRequest(); $drequest = $this->getDiffusionRequest();
$content = array();
$data = $this->callConduitWithDiffusionRequest( $data = $this->callConduitWithDiffusionRequest(
'diffusion.diffquery', 'diffusion.diffquery',
array( array(
@ -42,9 +40,11 @@ final class DiffusionChangeController extends DiffusionController {
0 => $changeset, 0 => $changeset,
); );
$changeset_header = $this->buildChangesetHeader($drequest);
$changeset_view = new DifferentialChangesetListView(); $changeset_view = new DifferentialChangesetListView();
$changeset_view->setTitle(pht('Change'));
$changeset_view->setChangesets($changesets); $changeset_view->setChangesets($changesets);
$changeset_view->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);
$changeset_view->setVisibleChangesets($changesets); $changeset_view->setVisibleChangesets($changesets);
$changeset_view->setRenderingReferences( $changeset_view->setRenderingReferences(
array( array(
@ -68,11 +68,11 @@ final class DiffusionChangeController extends DiffusionController {
$changeset_view->setWhitespace( $changeset_view->setWhitespace(
DifferentialChangesetParser::WHITESPACE_SHOW_ALL); DifferentialChangesetParser::WHITESPACE_SHOW_ALL);
$changeset_view->setUser($viewer); $changeset_view->setUser($viewer);
$changeset_view->setHeader($changeset_header);
// TODO: This is pretty awkward, unify the CSS between Diffusion and // TODO: This is pretty awkward, unify the CSS between Diffusion and
// Differential better. // Differential better.
require_celerity_resource('differential-core-view-css'); require_celerity_resource('differential-core-view-css');
$content[] = $changeset_view->render();
$crumbs = $this->buildCrumbs( $crumbs = $this->buildCrumbs(
array( array(
@ -80,19 +80,18 @@ final class DiffusionChangeController extends DiffusionController {
'path' => true, 'path' => true,
'view' => 'change', 'view' => 'change',
)); ));
$crumbs->setBorder(true);
$links = $this->renderPathLinks($drequest, $mode = 'browse'); $links = $this->renderPathLinks($drequest, $mode = 'browse');
$header = $this->buildHeader($drequest, $links);
$header = id(new PHUIHeaderView()) $view = id(new PHUITwoColumnView())
->setHeader($links)
->setUser($viewer)
->setPolicyObject($drequest->getRepository());
$actions = $this->buildActionView($drequest);
$properties = $this->buildPropertyView($drequest, $actions);
$object_box = id(new PHUIObjectBoxView())
->setHeader($header) ->setHeader($header)
->addPropertyList($properties); ->setMainColumn(array(
))
->setFooter(array(
$changeset_view,
));
return $this->newPage() return $this->newPage()
->setTitle( ->setTitle(
@ -103,25 +102,41 @@ final class DiffusionChangeController extends DiffusionController {
->setCrumbs($crumbs) ->setCrumbs($crumbs)
->appendChild( ->appendChild(
array( array(
$object_box, $view,
$content,
)); ));
} }
private function buildActionView(DiffusionRequest $drequest) { private function buildHeader(
$viewer = $this->getRequest()->getUser(); DiffusionRequest $drequest,
$links) {
$viewer = $this->getViewer();
$view = id(new PhabricatorActionListView()) $tag = $this->renderCommitHashTag($drequest);
->setUser($viewer);
$header = id(new PHUIHeaderView())
->setHeader($links)
->setUser($viewer)
->setPolicyObject($drequest->getRepository())
->addTag($tag);
return $header;
}
private function buildChangesetHeader(DiffusionRequest $drequest) {
$viewer = $this->getViewer();
$header = id(new PHUIHeaderView())
->setHeader(pht('Changes'));
$history_uri = $drequest->generateURI( $history_uri = $drequest->generateURI(
array( array(
'action' => 'history', 'action' => 'history',
)); ));
$view->addAction( $header->addActionLink(
id(new PhabricatorActionView()) id(new PHUIButtonView())
->setName(pht('View History')) ->setTag('a')
->setText(pht('View History'))
->setHref($history_uri) ->setHref($history_uri)
->setIcon('fa-clock-o')); ->setIcon('fa-clock-o'));
@ -130,13 +145,14 @@ final class DiffusionChangeController extends DiffusionController {
'action' => 'browse', 'action' => 'browse',
)); ));
$view->addAction( $header->addActionLink(
id(new PhabricatorActionView()) id(new PHUIButtonView())
->setName(pht('Browse Content')) ->setTag('a')
->setText(pht('Browse Content'))
->setHref($browse_uri) ->setHref($browse_uri)
->setIcon('fa-files-o')); ->setIcon('fa-files-o'));
return $view; return $header;
} }
protected function buildPropertyView( protected function buildPropertyView(

View file

@ -24,8 +24,7 @@ final class DiffusionCommitController extends DiffusionController {
} }
$drequest = $this->getDiffusionRequest(); $drequest = $this->getDiffusionRequest();
$viewer = $request->getUser();
$user = $request->getUser();
if ($request->getStr('diff')) { if ($request->getStr('diff')) {
return $this->buildRawDiffResponse($drequest); return $this->buildRawDiffResponse($drequest);
@ -33,9 +32,8 @@ final class DiffusionCommitController extends DiffusionController {
$repository = $drequest->getRepository(); $repository = $drequest->getRepository();
$content = array();
$commit = id(new DiffusionCommitQuery()) $commit = id(new DiffusionCommitQuery())
->setViewer($request->getUser()) ->setViewer($viewer)
->withRepository($repository) ->withRepository($repository)
->withIdentifiers(array($drequest->getCommit())) ->withIdentifiers(array($drequest->getCommit()))
->needCommitData(true) ->needCommitData(true)
@ -45,6 +43,7 @@ final class DiffusionCommitController extends DiffusionController {
$crumbs = $this->buildCrumbs(array( $crumbs = $this->buildCrumbs(array(
'commit' => true, 'commit' => true,
)); ));
$crumbs->setBorder(true);
if (!$commit) { if (!$commit) {
if (!$this->getCommitExists()) { if (!$this->getCommitExists()) {
@ -70,10 +69,11 @@ final class DiffusionCommitController extends DiffusionController {
$audit_requests = $commit->getAudits(); $audit_requests = $commit->getAudits();
$this->auditAuthorityPHIDs = $this->auditAuthorityPHIDs =
PhabricatorAuditCommentEditor::loadAuditPHIDsForUser($user); PhabricatorAuditCommentEditor::loadAuditPHIDsForUser($viewer);
$commit_data = $commit->getCommitData(); $commit_data = $commit->getCommitData();
$is_foreign = $commit_data->getCommitDetail('foreign-svn-stub'); $is_foreign = $commit_data->getCommitDetail('foreign-svn-stub');
$error_panel = null;
if ($is_foreign) { if ($is_foreign) {
$subpath = $commit_data->getCommitDetail('svn-subpath'); $subpath = $commit_data->getCommitDetail('svn-subpath');
@ -87,43 +87,41 @@ final class DiffusionCommitController extends DiffusionController {
"didn't affect the tracked subdirectory ('%s'), so no ". "didn't affect the tracked subdirectory ('%s'), so no ".
"information is available.", "information is available.",
$subpath)); $subpath));
$content[] = $error_panel;
} else { } else {
$engine = PhabricatorMarkupEngine::newDifferentialMarkupEngine(); $engine = PhabricatorMarkupEngine::newDifferentialMarkupEngine();
$engine->setConfig('viewer', $user); $engine->setConfig('viewer', $viewer);
$headsup_view = id(new PHUIHeaderView()) $commit_tag = $this->renderCommitHashTag($drequest);
$header = id(new PHUIHeaderView())
->setHeader(nonempty($commit->getSummary(), pht('Commit Detail'))) ->setHeader(nonempty($commit->getSummary(), pht('Commit Detail')))
->setSubheader(pht('Commit: %s', $commit->getCommitIdentifier())); ->setHeaderIcon('fa-code-fork')
->addTag($commit_tag);
$headsup_actions = $this->renderHeadsupActionList($commit, $repository); if ($commit->getAuditStatus()) {
$icon = PhabricatorAuditCommitStatusConstants::getStatusIcon(
$commit->getAuditStatus());
$color = PhabricatorAuditCommitStatusConstants::getStatusColor(
$commit->getAuditStatus());
$status = PhabricatorAuditCommitStatusConstants::getStatusName(
$commit->getAuditStatus());
$commit_properties = $this->loadCommitProperties( $header->setStatus($icon, $color, $status);
}
$curtain = $this->buildCurtain($commit, $repository);
$subheader = $this->buildSubheaderView($commit, $commit_data);
$details = $this->buildPropertyListView(
$commit, $commit,
$commit_data, $commit_data,
$audit_requests); $audit_requests);
$property_list = id(new PHUIPropertyListView())
->setHasKeyboardShortcuts(true)
->setUser($user)
->setObject($commit);
foreach ($commit_properties as $key => $value) {
$property_list->addProperty($key, $value);
}
$message = $commit_data->getCommitMessage(); $message = $commit_data->getCommitMessage();
$revision = $commit->getCommitIdentifier(); $revision = $commit->getCommitIdentifier();
$message = $this->linkBugtraq($message); $message = $this->linkBugtraq($message);
$message = $engine->markupText($message); $message = $engine->markupText($message);
$property_list->invokeWillRenderEvent();
$property_list->setActionList($headsup_actions);
$detail_list = new PHUIPropertyListView(); $detail_list = new PHUIPropertyListView();
$detail_list->addSectionHeader(
pht('Description'),
PHUIPropertyListView::ICON_SUMMARY);
$detail_list->addTextContent( $detail_list->addTextContent(
phutil_tag( phutil_tag(
'div', 'div',
@ -132,19 +130,14 @@ final class DiffusionCommitController extends DiffusionController {
), ),
$message)); $message));
$headsup_view->setTall(true); if ($this->getCommitErrors()) {
$error_panel = id(new PHUIInfoView())
$object_box = id(new PHUIObjectBoxView()) ->appendChild($this->getCommitErrors())
->setHeader($headsup_view) ->setSeverity(PHUIInfoView::SEVERITY_WARNING);
->setFormErrors($this->getCommitErrors()) }
->addPropertyList($property_list)
->addPropertyList($detail_list);
$content[] = $object_box;
} }
$content[] = $this->buildComments($commit); $timeline = $this->buildComments($commit);
$hard_limit = 1000; $hard_limit = 1000;
if ($commit->isImported()) { if ($commit->isImported()) {
@ -161,10 +154,10 @@ final class DiffusionCommitController extends DiffusionController {
$changes = array_slice($changes, 0, $hard_limit); $changes = array_slice($changes, 0, $hard_limit);
} }
$content[] = $this->buildMergesTable($commit); $merge_table = $this->buildMergesTable($commit);
$highlighted_audits = $commit->getAuthorityAudits( $highlighted_audits = $commit->getAuthorityAudits(
$user, $viewer,
$this->auditAuthorityPHIDs); $this->auditAuthorityPHIDs);
$count = count($changes); $count = count($changes);
@ -179,32 +172,35 @@ final class DiffusionCommitController extends DiffusionController {
} }
$show_changesets = false; $show_changesets = false;
$info_panel = null;
$change_list = null;
$change_table = null;
if ($bad_commit) { if ($bad_commit) {
$content[] = $this->renderStatusMessage( $info_panel = $this->renderStatusMessage(
pht('Bad Commit'), pht('Bad Commit'),
$bad_commit['description']); $bad_commit['description']);
} else if ($is_foreign) { } else if ($is_foreign) {
// Don't render anything else. // Don't render anything else.
} else if (!$commit->isImported()) { } else if (!$commit->isImported()) {
$content[] = $this->renderStatusMessage( $info_panel = $this->renderStatusMessage(
pht('Still Importing...'), pht('Still Importing...'),
pht( pht(
'This commit is still importing. Changes will be visible once '. 'This commit is still importing. Changes will be visible once '.
'the import finishes.')); 'the import finishes.'));
} else if (!count($changes)) { } else if (!count($changes)) {
$content[] = $this->renderStatusMessage( $info_panel = $this->renderStatusMessage(
pht('Empty Commit'), pht('Empty Commit'),
pht( pht(
'This commit is empty and does not affect any paths.')); 'This commit is empty and does not affect any paths.'));
} else if ($was_limited) { } else if ($was_limited) {
$content[] = $this->renderStatusMessage( $info_panel = $this->renderStatusMessage(
pht('Enormous Commit'), pht('Enormous Commit'),
pht( pht(
'This commit is enormous, and affects more than %d files. '. 'This commit is enormous, and affects more than %d files. '.
'Changes are not shown.', 'Changes are not shown.',
$hard_limit)); $hard_limit));
} else if (!$this->getCommitExists()) { } else if (!$this->getCommitExists()) {
$content[] = $this->renderStatusMessage( $info_panel = $this->renderStatusMessage(
pht('Commit No Longer Exists'), pht('Commit No Longer Exists'),
pht('This commit no longer exists in the repository.')); pht('This commit no longer exists in the repository.'));
} else { } else {
@ -214,13 +210,11 @@ final class DiffusionCommitController extends DiffusionController {
// changes inline even if there are more than the soft limit. // changes inline even if there are more than the soft limit.
$show_all_details = $request->getBool('show_all'); $show_all_details = $request->getBool('show_all');
$change_panel = new PHUIObjectBoxView(); $change_header = id(new PHUIHeaderView())
$header = new PHUIHeaderView(); ->setHeader(pht('Changes (%s)', new PhutilNumber($count)));
$header->setHeader(pht('Changes (%s)', new PhutilNumber($count)));
$change_panel->setID('toc');
$warning_view = null;
if ($count > self::CHANGES_LIMIT && !$show_all_details) { if ($count > self::CHANGES_LIMIT && !$show_all_details) {
$button = id(new PHUIButtonView()) $button = id(new PHUIButtonView())
->setText(pht('Show All Changes')) ->setText(pht('Show All Changes'))
->setHref('?show_all=true') ->setHref('?show_all=true')
@ -233,23 +227,19 @@ final class DiffusionCommitController extends DiffusionController {
->appendChild( ->appendChild(
pht('This commit is very large. Load each file individually.')); pht('This commit is very large. Load each file individually.'));
$change_panel->setInfoView($warning_view); $change_header->addActionLink($button);
$header->addActionLink($button);
} }
$changesets = DiffusionPathChange::convertToDifferentialChangesets( $changesets = DiffusionPathChange::convertToDifferentialChangesets(
$user, $viewer,
$changes); $changes);
// TODO: This table and panel shouldn't really be separate, but we need // TODO: This table and panel shouldn't really be separate, but we need
// to clean up the "Load All Files" interaction first. // to clean up the "Load All Files" interaction first.
$change_table = $this->buildTableOfContents( $change_table = $this->buildTableOfContents(
$changesets); $changesets,
$change_header,
$change_panel->setTable($change_table); $warning_view);
$change_panel->setHeader($header);
$content[] = $change_panel;
$vcs = $repository->getVersionControlSystem(); $vcs = $repository->getVersionControlSystem();
switch ($vcs) { switch ($vcs) {
@ -296,7 +286,7 @@ final class DiffusionCommitController extends DiffusionController {
} else { } else {
$visible_changesets = array(); $visible_changesets = array();
$inlines = PhabricatorAuditInlineComment::loadDraftAndPublishedComments( $inlines = PhabricatorAuditInlineComment::loadDraftAndPublishedComments(
$user, $viewer,
$commit->getPHID()); $commit->getPHID());
$path_ids = mpull($inlines, null, 'getPathID'); $path_ids = mpull($inlines, null, 'getPathID');
foreach ($changesets as $key => $changeset) { foreach ($changesets as $key => $changeset) {
@ -313,10 +303,10 @@ final class DiffusionCommitController extends DiffusionController {
$change_list->setChangesets($changesets); $change_list->setChangesets($changesets);
$change_list->setVisibleChangesets($visible_changesets); $change_list->setVisibleChangesets($visible_changesets);
$change_list->setRenderingReferences($references); $change_list->setRenderingReferences($references);
$change_list->setRenderURI( $change_list->setRenderURI($repository->getPathURI('diff/'));
$repository->getPathURI('diff/'));
$change_list->setRepository($repository); $change_list->setRepository($repository);
$change_list->setUser($user); $change_list->setUser($viewer);
$change_list->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);
// TODO: Try to setBranch() to something reasonable here? // TODO: Try to setBranch() to something reasonable here?
@ -332,48 +322,74 @@ final class DiffusionCommitController extends DiffusionController {
$change_list->setInlineCommentControllerURI( $change_list->setInlineCommentControllerURI(
'/diffusion/inline/edit/'.phutil_escape_uri($commit->getPHID()).'/'); '/diffusion/inline/edit/'.phutil_escape_uri($commit->getPHID()).'/');
$content[] = $change_list->render();
} }
$content[] = $this->renderAddCommentPanel($commit, $audit_requests); $add_comment = $this->renderAddCommentPanel($commit, $audit_requests);
$prefs = $user->loadPreferences(); $prefs = $viewer->loadPreferences();
$pref_filetree = PhabricatorUserPreferences::PREFERENCE_DIFF_FILETREE; $pref_filetree = PhabricatorUserPreferences::PREFERENCE_DIFF_FILETREE;
$pref_collapse = PhabricatorUserPreferences::PREFERENCE_NAV_COLLAPSED; $pref_collapse = PhabricatorUserPreferences::PREFERENCE_NAV_COLLAPSED;
$show_filetree = $prefs->getPreference($pref_filetree); $show_filetree = $prefs->getPreference($pref_filetree);
$collapsed = $prefs->getPreference($pref_collapse); $collapsed = $prefs->getPreference($pref_collapse);
$nav = null;
if ($show_changesets && $show_filetree) { if ($show_changesets && $show_filetree) {
$nav = id(new DifferentialChangesetFileTreeSideNavBuilder()) $nav = id(new DifferentialChangesetFileTreeSideNavBuilder())
->setTitle($commit->getDisplayName()) ->setTitle($commit->getDisplayName())
->setBaseURI(new PhutilURI($commit->getURI())) ->setBaseURI(new PhutilURI($commit->getURI()))
->build($changesets) ->build($changesets)
->setCrumbs($crumbs) ->setCrumbs($crumbs)
->setCollapsed((bool)$collapsed) ->setCollapsed((bool)$collapsed);
->appendChild($content);
$content = $nav;
} else {
$content = array($crumbs, $content);
} }
return $this->buildApplicationPage( $view = id(new PHUITwoColumnView())
$content, ->setHeader($header)
->setSubheader($subheader)
->setMainColumn(array(
$error_panel,
$timeline,
$merge_table,
$info_panel,
))
->setFooter(array(
$change_table,
$change_list,
$add_comment,
))
->addPropertySection(pht('DESCRIPTION'), $detail_list)
->addPropertySection(pht('DETAILS'), $details)
->setCurtain($curtain);
$page = $this->newPage()
->setTitle($commit->getDisplayName())
->setCrumbs($crumbs)
->setPageObjectPHIDS(array($commit->getPHID()))
->appendChild(
array( array(
'title' => $commit->getDisplayName(), $view,
'pageObjects' => array($commit->getPHID()),
)); ));
if ($nav) {
$page->setNavigation($nav);
} }
private function loadCommitProperties( return $page;
}
private function buildPropertyListView(
PhabricatorRepositoryCommit $commit, PhabricatorRepositoryCommit $commit,
PhabricatorRepositoryCommitData $data, PhabricatorRepositoryCommitData $data,
array $audit_requests) { array $audit_requests) {
$viewer = $this->getRequest()->getUser(); $viewer = $this->getViewer();
$commit_phid = $commit->getPHID(); $commit_phid = $commit->getPHID();
$drequest = $this->getDiffusionRequest(); $drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository(); $repository = $drequest->getRepository();
$view = id(new PHUIPropertyListView())
->setUser($this->getRequest()->getUser());
$edge_query = id(new PhabricatorEdgeQuery()) $edge_query = id(new PhabricatorEdgeQuery())
->withSourcePHIDs(array($commit_phid)) ->withSourcePHIDs(array($commit_phid))
->withEdgeTypes(array( ->withEdgeTypes(array(
@ -437,31 +453,6 @@ final class DiffusionCommitController extends DiffusionController {
$props = array(); $props = array();
if ($commit->getAuditStatus()) {
$status = PhabricatorAuditCommitStatusConstants::getStatusName(
$commit->getAuditStatus());
$tag = id(new PHUITagView())
->setType(PHUITagView::TYPE_STATE)
->setName($status);
switch ($commit->getAuditStatus()) {
case PhabricatorAuditCommitStatusConstants::NEEDS_AUDIT:
$tag->setBackgroundColor(PHUITagView::COLOR_ORANGE);
break;
case PhabricatorAuditCommitStatusConstants::CONCERN_RAISED:
$tag->setBackgroundColor(PHUITagView::COLOR_RED);
break;
case PhabricatorAuditCommitStatusConstants::PARTIALLY_AUDITED:
$tag->setBackgroundColor(PHUITagView::COLOR_BLUE);
break;
case PhabricatorAuditCommitStatusConstants::FULLY_AUDITED:
$tag->setBackgroundColor(PHUITagView::COLOR_GREEN);
break;
}
$props['Status'] = $tag;
}
if ($audit_requests) { if ($audit_requests) {
$user_requests = array(); $user_requests = array();
$other_requests = array(); $other_requests = array();
@ -474,37 +465,21 @@ final class DiffusionCommitController extends DiffusionController {
} }
if ($user_requests) { if ($user_requests) {
$props['Auditors'] = $this->renderAuditStatusView( $view->addProperty(
$user_requests); pht('Auditors'),
$this->renderAuditStatusView($user_requests));
} }
if ($other_requests) { if ($other_requests) {
$props['Project/Package Auditors'] = $this->renderAuditStatusView( $view->addProperty(
$other_requests); pht('Project/Package Auditors'),
$this->renderAuditStatusView($other_requests));
} }
} }
$author_phid = $data->getCommitDetail('authorPHID'); $author_phid = $data->getCommitDetail('authorPHID');
$author_name = $data->getAuthorName(); $author_name = $data->getAuthorName();
if (!$repository->isSVN()) {
$authored_info = id(new PHUIStatusItemView());
$author_epoch = $data->getCommitDetail('authorEpoch'); $author_epoch = $data->getCommitDetail('authorEpoch');
if ($author_epoch !== null) {
$authored_info->setNote(
phabricator_datetime($author_epoch, $viewer));
}
if ($author_phid) {
$authored_info->setTarget($handles[$author_phid]->renderLink());
} else if (strlen($author_name)) {
$authored_info->setTarget($author_name);
}
$props['Authored'] = id(new PHUIStatusListView())
->addItem($authored_info);
}
$committed_info = id(new PHUIStatusItemView()) $committed_info = id(new PHUIStatusItemView())
->setNote(phabricator_datetime($commit->getEpoch(), $viewer)); ->setNote(phabricator_datetime($commit->getEpoch(), $viewer));
@ -521,8 +496,9 @@ final class DiffusionCommitController extends DiffusionController {
$committed_info->setTarget($author_name); $committed_info->setTarget($author_name);
} }
$props['Committed'] = id(new PHUIStatusListView()) $view->addProperty(
->addItem($committed_info); pht('Committed'),
$committed_info);
if ($push_logs) { if ($push_logs) {
$pushed_list = new PHUIStatusListView(); $pushed_list = new PHUIStatusListView();
@ -534,36 +510,49 @@ final class DiffusionCommitController extends DiffusionController {
$pushed_list->addItem($pushed_item); $pushed_list->addItem($pushed_item);
} }
$props['Pushed'] = $pushed_list; $view->addProperty(
pht('Pushed'),
$pushed_list);
} }
$reviewer_phid = $data->getCommitDetail('reviewerPHID'); $reviewer_phid = $data->getCommitDetail('reviewerPHID');
if ($reviewer_phid) { if ($reviewer_phid) {
$props['Reviewer'] = $handles[$reviewer_phid]->renderLink(); $view->addProperty(
pht('Reviewer'),
$handles[$reviewer_phid]->renderLink());
} }
if ($revision_phid) { if ($revision_phid) {
$props['Differential Revision'] = $handles[$revision_phid]->renderLink(); $view->addProperty(
pht('Differential Revision'),
$handles[$revision_phid]->renderLink());
} }
$parents = $this->getCommitParents(); $parents = $this->getCommitParents();
if ($parents) { if ($parents) {
$props['Parents'] = $viewer->renderHandleList(mpull($parents, 'getPHID')); $view->addProperty(
pht('Parents'),
$viewer->renderHandleList(mpull($parents, 'getPHID')));
} }
if ($this->getCommitExists()) { if ($this->getCommitExists()) {
$props['Branches'] = phutil_tag( $view->addProperty(
pht('Branches'),
phutil_tag(
'span', 'span',
array( array(
'id' => 'commit-branches', 'id' => 'commit-branches',
), ),
pht('Unknown')); pht('Unknown')));
$props['Tags'] = phutil_tag(
$view->addProperty(
pht('Tags'),
phutil_tag(
'span', 'span',
array( array(
'id' => 'commit-tags', 'id' => 'commit-tags',
), ),
pht('Unknown')); pht('Unknown')));
$identifier = $commit->getCommitIdentifier(); $identifier = $commit->getCommitIdentifier();
$root = $repository->getPathURI("commit/{$identifier}"); $root = $repository->getPathURI("commit/{$identifier}");
@ -586,16 +575,21 @@ final class DiffusionCommitController extends DiffusionController {
), ),
$ref_data['ref']); $ref_data['ref']);
} }
$props['References'] = phutil_implode_html(', ', $ref_links); $view->addProperty(
pht('References'),
phutil_implode_html(', ', $ref_links));
} }
if ($reverts_phids) { if ($reverts_phids) {
$props[pht('Reverts')] = $viewer->renderHandleList($reverts_phids); $view->addProperty(
pht('Reverts'),
$viewer->renderHandleList($reverts_phids));
} }
if ($reverted_by_phids) { if ($reverted_by_phids) {
$props[pht('Reverted By')] = $viewer->renderHandleList( $view->addProperty(
$reverted_by_phids); pht('Reverted By'),
$viewer->renderHandleList($reverted_by_phids));
} }
if ($task_phids) { if ($task_phids) {
@ -604,12 +598,62 @@ final class DiffusionCommitController extends DiffusionController {
$task_list[] = $handles[$phid]->renderLink(); $task_list[] = $handles[$phid]->renderLink();
} }
$task_list = phutil_implode_html(phutil_tag('br'), $task_list); $task_list = phutil_implode_html(phutil_tag('br'), $task_list);
$props['Tasks'] = $task_list; $view->addProperty(
pht('Tasks'),
$task_list);
} }
return $props; return $view;
} }
private function buildSubheaderView(
PhabricatorRepositoryCommit $commit,
PhabricatorRepositoryCommitData $data) {
$viewer = $this->getViewer();
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
if ($repository->isSVN()) {
return null;
}
$author_phid = $data->getCommitDetail('authorPHID');
$author_name = $data->getAuthorName();
$author_epoch = $data->getCommitDetail('authorEpoch');
$date = null;
if ($author_epoch !== null) {
$date = phabricator_datetime($author_epoch, $viewer);
}
if ($author_phid) {
$handles = $viewer->loadHandles(array($author_phid));
$image_uri = $handles[$author_phid]->getImageURI();
$image_href = $handles[$author_phid]->getURI();
$author = $handles[$author_phid]->renderLink();
} else if (strlen($author_name)) {
$author = $author_name;
$image_uri = null;
$image_href = null;
} else {
return null;
}
$author = phutil_tag('strong', array(), $author);
if ($date) {
$content = pht('Authored by %s on %s.', $author, $date);
} else {
$content = pht('Authored by %s.', $author);
}
return id(new PHUIHeadThingView())
->setImage($image_uri)
->setImageHref($image_href)
->setContent($content);
}
private function buildComments(PhabricatorRepositoryCommit $commit) { private function buildComments(PhabricatorRepositoryCommit $commit) {
$timeline = $this->buildTransactionTimeline( $timeline = $this->buildTransactionTimeline(
$commit, $commit,
@ -624,11 +668,11 @@ final class DiffusionCommitController extends DiffusionController {
assert_instances_of($audit_requests, 'PhabricatorRepositoryAuditRequest'); assert_instances_of($audit_requests, 'PhabricatorRepositoryAuditRequest');
$request = $this->getRequest(); $request = $this->getRequest();
$user = $request->getUser(); $viewer = $request->getUser();
if (!$user->isLoggedIn()) { if (!$viewer->isLoggedIn()) {
return id(new PhabricatorApplicationTransactionCommentView()) return id(new PhabricatorApplicationTransactionCommentView())
->setUser($user) ->setUser($viewer)
->setRequestURI($request->getRequestURI()); ->setRequestURI($request->getRequestURI());
} }
@ -643,7 +687,7 @@ final class DiffusionCommitController extends DiffusionController {
$draft = id(new PhabricatorDraft())->loadOneWhere( $draft = id(new PhabricatorDraft())->loadOneWhere(
'authorPHID = %s AND draftKey = %s', 'authorPHID = %s AND draftKey = %s',
$user->getPHID(), $viewer->getPHID(),
'diffusion-audit-'.$commit->getID()); 'diffusion-audit-'.$commit->getID());
if ($draft) { if ($draft) {
$draft = $draft->getDraft(); $draft = $draft->getDraft();
@ -657,7 +701,7 @@ final class DiffusionCommitController extends DiffusionController {
$auditor_source = new DiffusionAuditorDatasource(); $auditor_source = new DiffusionAuditorDatasource();
$form = id(new AphrontFormView()) $form = id(new AphrontFormView())
->setUser($user) ->setUser($viewer)
->setAction('/audit/addcomment/') ->setAction('/audit/addcomment/')
->addHiddenInput('commit', $commit->getPHID()) ->addHiddenInput('commit', $commit->getPHID())
->appendChild( ->appendChild(
@ -690,7 +734,7 @@ final class DiffusionCommitController extends DiffusionController {
->setName('content') ->setName('content')
->setValue($draft) ->setValue($draft)
->setID('audit-content') ->setID('audit-content')
->setUser($user)) ->setUser($viewer))
->appendChild( ->appendChild(
id(new AphrontFormSubmitControl()) id(new AphrontFormSubmitControl())
->setValue(pht('Submit'))); ->setValue(pht('Submit')));
@ -776,13 +820,13 @@ final class DiffusionCommitController extends DiffusionController {
PhabricatorRepositoryCommit $commit, PhabricatorRepositoryCommit $commit,
array $audit_requests) { array $audit_requests) {
assert_instances_of($audit_requests, 'PhabricatorRepositoryAuditRequest'); assert_instances_of($audit_requests, 'PhabricatorRepositoryAuditRequest');
$user = $this->getRequest()->getUser(); $viewer = $this->getViewer();
$user_is_author = ($commit->getAuthorPHID() == $user->getPHID()); $user_is_author = ($commit->getAuthorPHID() == $viewer->getPHID());
$user_request = null; $user_request = null;
foreach ($audit_requests as $audit_request) { foreach ($audit_requests as $audit_request) {
if ($audit_request->getAuditorPHID() == $user->getPHID()) { if ($audit_request->getAuditorPHID() == $viewer->getPHID()) {
$user_request = $audit_request; $user_request = $audit_request;
break; break;
} }
@ -876,9 +920,10 @@ final class DiffusionCommitController extends DiffusionController {
$history_table->loadRevisions(); $history_table->loadRevisions();
$panel = new PHUIObjectBoxView(); $panel = id(new PHUIObjectBoxView())
$panel->setHeaderText(pht('Merged Changes')); ->setHeaderText(pht('Merged Changes'))
$panel->setTable($history_table); ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($history_table);
if ($caption) { if ($caption) {
$panel->setInfoView($caption); $panel->setInfoView($caption);
} }
@ -886,19 +931,16 @@ final class DiffusionCommitController extends DiffusionController {
return $panel; return $panel;
} }
private function renderHeadsupActionList( private function buildCurtain(
PhabricatorRepositoryCommit $commit, PhabricatorRepositoryCommit $commit,
PhabricatorRepository $repository) { PhabricatorRepository $repository) {
$request = $this->getRequest(); $request = $this->getRequest();
$user = $request->getUser(); $viewer = $this->getViewer();
$curtain = $this->newCurtainView($commit);
$actions = id(new PhabricatorActionListView())
->setUser($user)
->setObject($commit);
$can_edit = PhabricatorPolicyFilter::hasCapability( $can_edit = PhabricatorPolicyFilter::hasCapability(
$user, $viewer,
$commit, $commit,
PhabricatorPolicyCapability::CAN_EDIT); PhabricatorPolicyCapability::CAN_EDIT);
@ -911,7 +953,7 @@ final class DiffusionCommitController extends DiffusionController {
->setIcon('fa-pencil') ->setIcon('fa-pencil')
->setDisabled(!$can_edit) ->setDisabled(!$can_edit)
->setWorkflow(!$can_edit); ->setWorkflow(!$can_edit);
$actions->addAction($action); $curtain->addAction($action);
require_celerity_resource('phabricator-object-selector-css'); require_celerity_resource('phabricator-object-selector-css');
require_celerity_resource('javelin-behavior-phabricator-object-selector'); require_celerity_resource('javelin-behavior-phabricator-object-selector');
@ -924,16 +966,16 @@ final class DiffusionCommitController extends DiffusionController {
->setHref('/search/attach/'.$commit->getPHID().'/TASK/edge/') ->setHref('/search/attach/'.$commit->getPHID().'/TASK/edge/')
->setWorkflow(true) ->setWorkflow(true)
->setDisabled(!$can_edit); ->setDisabled(!$can_edit);
$actions->addAction($action); $curtain->addAction($action);
} }
$action = id(new PhabricatorActionView()) $action = id(new PhabricatorActionView())
->setName(pht('Download Raw Diff')) ->setName(pht('Download Raw Diff'))
->setHref($request->getRequestURI()->alter('diff', true)) ->setHref($request->getRequestURI()->alter('diff', true))
->setIcon('fa-download'); ->setIcon('fa-download');
$actions->addAction($action); $curtain->addAction($action);
return $actions; return $curtain;
} }
private function buildRawDiffResponse(DiffusionRequest $drequest) { private function buildRawDiffResponse(DiffusionRequest $drequest) {
@ -1017,12 +1059,22 @@ final class DiffusionCommitController extends DiffusionController {
return $parser->processCorpus($corpus); return $parser->processCorpus($corpus);
} }
private function buildTableOfContents(array $changesets) { private function buildTableOfContents(
array $changesets,
$header,
$info_view) {
$drequest = $this->getDiffusionRequest(); $drequest = $this->getDiffusionRequest();
$viewer = $this->getViewer(); $viewer = $this->getViewer();
$toc_view = id(new PHUIDiffTableOfContentsListView()) $toc_view = id(new PHUIDiffTableOfContentsListView())
->setUser($viewer); ->setUser($viewer)
->setHeader($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);
if ($info_view) {
$toc_view->setInfoView($info_view);
}
// TODO: This is hacky, we just want access to the linkX() methods on // TODO: This is hacky, we just want access to the linkX() methods on
// DiffusionView. // DiffusionView.

View file

@ -291,6 +291,7 @@ abstract class DiffusionController extends PhabricatorController {
return id(new PHUIInfoView()) return id(new PHUIInfoView())
->setSeverity(PHUIInfoView::SEVERITY_WARNING) ->setSeverity(PHUIInfoView::SEVERITY_WARNING)
->setTitle($title) ->setTitle($title)
->setFlush(true)
->appendChild($body); ->appendChild($body);
} }
@ -300,6 +301,27 @@ abstract class DiffusionController extends PhabricatorController {
->appendChild($pager); ->appendChild($pager);
} }
protected function renderCommitHashTag(DiffusionRequest $drequest) {
$stable_commit = $drequest->getStableCommit();
$commit = phutil_tag(
'a',
array(
'href' => $drequest->generateURI(
array(
'action' => 'commit',
'commit' => $stable_commit,
)),
),
$drequest->getRepository()->formatCommitName($stable_commit, true));
$tag = id(new PHUITagView())
->setName($commit)
->setShade('indigo')
->setType(PHUITagView::TYPE_SHADE);
return $tag;
}
protected function renderDirectoryReadme(DiffusionBrowseResultSet $browse) { protected function renderDirectoryReadme(DiffusionBrowseResultSet $browse) {
$readme_path = $browse->getReadmePath(); $readme_path = $browse->getReadmePath();
if ($readme_path === null) { if ($readme_path === null) {

View file

@ -40,8 +40,6 @@ final class DiffusionHistoryController extends DiffusionController {
$history = $pager->sliceResults($history); $history = $pager->sliceResults($history);
$show_graph = !strlen($drequest->getPath()); $show_graph = !strlen($drequest->getPath());
$content = array();
$history_table = id(new DiffusionHistoryTableView()) $history_table = id(new DiffusionHistoryTableView())
->setUser($request->getUser()) ->setUser($request->getUser())
->setDiffusionRequest($drequest) ->setDiffusionRequest($drequest)
@ -55,23 +53,13 @@ final class DiffusionHistoryController extends DiffusionController {
$history_table->setIsTail(!$pager->getHasMorePages()); $history_table->setIsTail(!$pager->getHasMorePages());
} }
$history_panel = new PHUIObjectBoxView(); $history_header = $this->buildHistoryHeader($drequest);
$history_panel->setHeaderText(pht('History')); $history_panel = id(new PHUIObjectBoxView())
$history_panel->setTable($history_table); ->setHeader($history_header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($history_table);
$content[] = $history_panel; $header = $this->buildHeader($drequest, $repository);
$header = id(new PHUIHeaderView())
->setUser($viewer)
->setPolicyObject($repository)
->setHeader($this->renderPathLinks($drequest, $mode = 'history'));
$actions = $this->buildActionView($drequest);
$properties = $this->buildPropertyView($drequest, $actions);
$object_box = id(new PHUIObjectBoxView())
->setHeader($header)
->addPropertyList($properties);
$crumbs = $this->buildCrumbs( $crumbs = $this->buildCrumbs(
array( array(
@ -79,9 +67,17 @@ final class DiffusionHistoryController extends DiffusionController {
'path' => true, 'path' => true,
'view' => 'history', 'view' => 'history',
)); ));
$crumbs->setBorder(true);
$pager_box = $this->renderTablePagerBox($pager); $pager_box = $this->renderTablePagerBox($pager);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter(array(
$history_panel,
$pager_box,
));
return $this->newPage() return $this->newPage()
->setTitle( ->setTitle(
array( array(
@ -91,28 +87,39 @@ final class DiffusionHistoryController extends DiffusionController {
->setCrumbs($crumbs) ->setCrumbs($crumbs)
->appendChild( ->appendChild(
array( array(
$object_box, $view,
$content,
$pager_box,
)); ));
} }
private function buildActionView(DiffusionRequest $drequest) { private function buildHeader(DiffusionRequest $drequest) {
$viewer = $this->getRequest()->getUser(); $viewer = $this->getViewer();
$view = id(new PhabricatorActionListView()) $tag = $this->renderCommitHashTag($drequest);
->setUser($viewer);
$header = id(new PHUIHeaderView())
->setUser($viewer)
->setPolicyObject($drequest->getRepository())
->addTag($tag)
->setHeader($this->renderPathLinks($drequest, $mode = 'history'))
->setHeaderIcon('fa-clock-o');
return $header;
}
private function buildHistoryHeader(DiffusionRequest $drequest) {
$viewer = $this->getViewer();
$browse_uri = $drequest->generateURI( $browse_uri = $drequest->generateURI(
array( array(
'action' => 'browse', 'action' => 'browse',
)); ));
$view->addAction( $browse_button = id(new PHUIButtonView())
id(new PhabricatorActionView()) ->setTag('a')
->setName(pht('Browse Content')) ->setText(pht('Browse'))
->setHref($browse_uri) ->setHref($browse_uri)
->setIcon('fa-files-o')); ->setIcon('fa-files-o');
// TODO: Sometimes we do have a change view, we need to look at the most // TODO: Sometimes we do have a change view, we need to look at the most
// recent history entry to figure it out. // recent history entry to figure it out.
@ -130,41 +137,18 @@ final class DiffusionHistoryController extends DiffusionController {
->alter('copies', true); ->alter('copies', true);
} }
$view->addAction( $branch_button = id(new PHUIButtonView())
id(new PhabricatorActionView()) ->setTag('a')
->setName($branch_name) ->setText($branch_name)
->setIcon('fa-code-fork') ->setIcon('fa-code-fork')
->setHref($branch_uri)); ->setHref($branch_uri);
return $view; $header = id(new PHUIHeaderView())
} ->setHeader(pht('History'))
->addActionLink($browse_button)
->addActionLink($branch_button);
protected function buildPropertyView( return $header;
DiffusionRequest $drequest,
PhabricatorActionListView $actions) {
$viewer = $this->getRequest()->getUser();
$view = id(new PHUIPropertyListView())
->setUser($viewer)
->setActionList($actions);
$stable_commit = $drequest->getStableCommit();
$view->addProperty(
pht('Commit'),
phutil_tag(
'a',
array(
'href' => $drequest->generateURI(
array(
'action' => 'commit',
'commit' => $stable_commit,
)),
),
$drequest->getRepository()->formatCommitName($stable_commit)));
return $view;
} }
} }

View file

@ -103,7 +103,7 @@ final class DiffusionLastModifiedController extends DiffusionController {
$modified = DiffusionView::linkCommit( $modified = DiffusionView::linkCommit(
$drequest->getRepository(), $drequest->getRepository(),
$commit->getCommitIdentifier()); $commit->getCommitIdentifier());
$date = phabricator_datetime($epoch, $viewer); $date = $viewer->formatShortDateTime($epoch);
} else { } else {
$modified = ''; $modified = '';
$date = ''; $date = '';

View file

@ -157,6 +157,7 @@ final class DiffusionLintController extends DiffusionController {
$content[] = id(new PHUIObjectBoxView()) $content[] = id(new PHUIObjectBoxView())
->setHeaderText(pht('Lint')) ->setHeaderText(pht('Lint'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($table); ->setTable($table);
$title = array('Lint'); $title = array('Lint');
@ -179,7 +180,7 @@ final class DiffusionLintController extends DiffusionController {
$header = id(new PHUIHeaderView()) $header = id(new PHUIHeaderView())
->setHeader($this->renderPathLinks($drequest, 'lint')) ->setHeader($this->renderPathLinks($drequest, 'lint'))
->setUser($viewer) ->setUser($viewer)
->setPolicyObject($drequest->getRepository()); ->setHeaderIcon('fa-code');
$actions = $this->buildActionView($drequest); $actions = $this->buildActionView($drequest);
$properties = $this->buildPropertyView( $properties = $this->buildPropertyView(
$drequest, $drequest,
@ -189,18 +190,28 @@ final class DiffusionLintController extends DiffusionController {
$object_box = id(new PHUIObjectBoxView()) $object_box = id(new PHUIObjectBoxView())
->setHeader($header) ->setHeader($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($properties); ->addPropertyList($properties);
} else { } else {
$object_box = null; $object_box = null;
$header = id(new PHUIHeaderView())
->setHeader(pht('All Lint'))
->setHeaderIcon('fa-code');
} }
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter(array(
$object_box,
$content,
));
return $this->newPage() return $this->newPage()
->setTitle($title) ->setTitle($title)
->setCrumbs($crumbs) ->setCrumbs($crumbs)
->appendChild( ->appendChild(
array( array(
$object_box, $view,
$content,
)); ));
} }
@ -444,6 +455,7 @@ final class DiffusionLintController extends DiffusionController {
$content[] = id(new PHUIObjectBoxView()) $content[] = id(new PHUIObjectBoxView())
->setHeaderText(pht('Lint Details')) ->setHeaderText(pht('Lint Details'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($table); ->setTable($table);
$crumbs = $this->buildCrumbs( $crumbs = $this->buildCrumbs(
@ -454,6 +466,16 @@ final class DiffusionLintController extends DiffusionController {
)); ));
$pager_box = $this->renderTablePagerBox($pager); $pager_box = $this->renderTablePagerBox($pager);
$header = id(new PHUIHeaderView())
->setHeader(pht('Lint: %s', $drequest->getRepository()->getDisplayName()))
->setHeaderIcon('fa-code');
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter(array(
$content,
$pager_box,
));
return $this->newPage() return $this->newPage()
->setTitle( ->setTitle(
@ -464,8 +486,7 @@ final class DiffusionLintController extends DiffusionController {
->setCrumbs($crumbs) ->setCrumbs($crumbs)
->appendChild( ->appendChild(
array( array(
$content, $view,
$pager_box,
)); ));
} }

View file

@ -16,11 +16,14 @@ final class DiffusionRepositoryController extends DiffusionController {
$drequest = $this->getDiffusionRequest(); $drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository(); $repository = $drequest->getRepository();
$content = array();
$crumbs = $this->buildCrumbs(); $crumbs = $this->buildCrumbs();
$crumbs->setBorder(true);
$content[] = $this->buildPropertiesTable($drequest->getRepository()); $header = $this->buildHeaderView($repository);
$curtain = $this->buildCurtain($repository);
$property_table = $this->buildPropertiesTable($repository);
$description = $this->buildDescriptionView($repository);
$locate_file = $this->buildLocateFile();
// Before we do any work, make sure we're looking at a some content: we're // Before we do any work, make sure we're looking at a some content: we're
// on a valid branch, and the repository is not empty. // on a valid branch, and the repository is not empty.
@ -68,14 +71,24 @@ final class DiffusionRepositoryController extends DiffusionController {
} }
if ($page_has_content) { if ($page_has_content) {
$content[] = $this->buildNormalContent($drequest); $content = $this->buildNormalContent($drequest);
} else { } else {
$content[] = id(new PHUIInfoView()) $content = id(new PHUIInfoView())
->setTitle($empty_title) ->setTitle($empty_title)
->setSeverity(PHUIInfoView::SEVERITY_WARNING) ->setSeverity(PHUIInfoView::SEVERITY_WARNING)
->setErrors(array($empty_message)); ->setErrors(array($empty_message));
} }
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setCurtain($curtain)
->setMainColumn(array(
$property_table,
$description,
$locate_file,
))
->setFooter($content);
return $this->newPage() return $this->newPage()
->setTitle( ->setTitle(
array( array(
@ -83,7 +96,9 @@ final class DiffusionRepositoryController extends DiffusionController {
$repository->getDisplayName(), $repository->getDisplayName(),
)) ))
->setCrumbs($crumbs) ->setCrumbs($crumbs)
->appendChild($content); ->appendChild(array(
$view,
));
} }
@ -206,13 +221,13 @@ final class DiffusionRepositoryController extends DiffusionController {
return $content; return $content;
} }
private function buildPropertiesTable(PhabricatorRepository $repository) { private function buildHeaderView(PhabricatorRepository $repository) {
$user = $this->getRequest()->getUser(); $viewer = $this->getViewer();
$header = id(new PHUIHeaderView()) $header = id(new PHUIHeaderView())
->setHeader($repository->getName()) ->setHeader($repository->getName())
->setUser($user) ->setUser($viewer)
->setPolicyObject($repository); ->setPolicyObject($repository)
->setHeaderIcon('fa-code');
if (!$repository->isTracked()) { if (!$repository->isTracked()) {
$header->setStatus('fa-ban', 'dark', pht('Inactive')); $header->setStatus('fa-ban', 'dark', pht('Inactive'));
@ -227,12 +242,64 @@ final class DiffusionRepositoryController extends DiffusionController {
$header->setStatus('fa-check', 'bluegrey', pht('Active')); $header->setStatus('fa-check', 'bluegrey', pht('Active'));
} }
return $header;
}
$actions = $this->buildActionList($repository); private function buildCurtain(PhabricatorRepository $repository) {
$viewer = $this->getViewer();
$edit_uri = $repository->getPathURI('edit/');
$curtain = $this->newCurtainView($repository);
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$repository,
PhabricatorPolicyCapability::CAN_EDIT);
$curtain->addAction(
id(new PhabricatorActionView())
->setName(pht('Edit Repository'))
->setIcon('fa-pencil')
->setHref($edit_uri)
->setWorkflow(!$can_edit)
->setDisabled(!$can_edit));
if ($repository->isHosted()) {
$push_uri = $this->getApplicationURI(
'pushlog/?repositories='.$repository->getMonogram());
$curtain->addAction(
id(new PhabricatorActionView())
->setName(pht('View Push Logs'))
->setIcon('fa-list-alt')
->setHref($push_uri));
}
return $curtain;
}
private function buildDescriptionView(PhabricatorRepository $repository) {
$viewer = $this->getViewer();
$view = id(new PHUIPropertyListView())
->setUser($viewer);
$description = $repository->getDetail('description');
if (strlen($description)) {
$description = new PHUIRemarkupView($viewer, $description);
$view->addTextContent($description);
return id(new PHUIObjectBoxView())
->setHeaderText(pht('DESCRIPTION'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->appendChild($view);
}
return null;
}
private function buildPropertiesTable(PhabricatorRepository $repository) {
$viewer = $this->getViewer();
$view = id(new PHUIPropertyListView()) $view = id(new PHUIPropertyListView())
->setObject($repository) ->setUser($viewer);
->setUser($user);
if ($repository->isHosted()) { if ($repository->isHosted()) {
$ssh_uri = $repository->getSSHCloneURIObject(); $ssh_uri = $repository->getSSHCloneURIObject();
@ -286,21 +353,10 @@ final class DiffusionRepositoryController extends DiffusionController {
} }
} }
$view->invokeWillRenderEvent();
$description = $repository->getDetail('description');
if (strlen($description)) {
$description = new PHUIRemarkupView($user, $description);
$view->addSectionHeader(
pht('Description'), PHUIPropertyListView::ICON_SUMMARY);
$view->addTextContent($description);
}
$view->setActionList($actions);
$box = id(new PHUIObjectBoxView()) $box = id(new PHUIObjectBoxView())
->setHeader($header) ->setHeaderText(pht('DETAILS'))
->addPropertyList($view); ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->appendChild($view);
$info = null; $info = null;
$drequest = $this->getDiffusionRequest(); $drequest = $this->getDiffusionRequest();
@ -344,7 +400,7 @@ final class DiffusionRepositoryController extends DiffusionController {
} }
private function buildBranchListTable(DiffusionRequest $drequest) { private function buildBranchListTable(DiffusionRequest $drequest) {
$viewer = $this->getRequest()->getUser(); $viewer = $this->getViewer();
if ($drequest->getBranch() === null) { if ($drequest->getBranch() === null) {
return null; return null;
@ -379,7 +435,8 @@ final class DiffusionRepositoryController extends DiffusionController {
->setBranches($branches) ->setBranches($branches)
->setCommits($commits); ->setCommits($commits);
$panel = new PHUIObjectBoxView(); $panel = id(new PHUIObjectBoxView())
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);
$header = new PHUIHeaderView(); $header = new PHUIHeaderView();
$header->setHeader(pht('Branches')); $header->setHeader(pht('Branches'));
@ -388,7 +445,7 @@ final class DiffusionRepositoryController extends DiffusionController {
} }
$button = new PHUIButtonView(); $button = new PHUIButtonView();
$button->setText(pht('Show All Branches')); $button->setText(pht('Show All'));
$button->setTag('a'); $button->setTag('a');
$button->setIcon('fa-code-fork'); $button->setIcon('fa-code-fork');
$button->setHref($drequest->generateURI( $button->setHref($drequest->generateURI(
@ -404,7 +461,7 @@ final class DiffusionRepositoryController extends DiffusionController {
} }
private function buildTagListTable(DiffusionRequest $drequest) { private function buildTagListTable(DiffusionRequest $drequest) {
$viewer = $this->getRequest()->getUser(); $viewer = $this->getViewer();
$repository = $drequest->getRepository(); $repository = $drequest->getRepository();
switch ($repository->getVersionControlSystem()) { switch ($repository->getVersionControlSystem()) {
@ -469,46 +526,11 @@ final class DiffusionRepositoryController extends DiffusionController {
$panel->setHeader($header); $panel->setHeader($header);
$panel->setTable($view); $panel->setTable($view);
$panel->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);
return $panel; return $panel;
} }
private function buildActionList(PhabricatorRepository $repository) {
$viewer = $this->getRequest()->getUser();
$edit_uri = $repository->getPathURI('edit/');
$view = id(new PhabricatorActionListView())
->setUser($viewer)
->setObject($repository);
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$repository,
PhabricatorPolicyCapability::CAN_EDIT);
$view->addAction(
id(new PhabricatorActionView())
->setName(pht('Edit Repository'))
->setIcon('fa-pencil')
->setHref($edit_uri)
->setWorkflow(!$can_edit)
->setDisabled(!$can_edit));
if ($repository->isHosted()) {
$push_uri = $this->getApplicationURI(
'pushlog/?repositories='.$repository->getMonogram());
$view->addAction(
id(new PhabricatorActionView())
->setName(pht('View Push Logs'))
->setIcon('fa-list-alt')
->setHref($push_uri));
}
return $view;
}
private function buildHistoryTable( private function buildHistoryTable(
$history_results, $history_results,
$history, $history,
@ -551,7 +573,7 @@ final class DiffusionRepositoryController extends DiffusionController {
->setIcon('fa-list-alt'); ->setIcon('fa-list-alt');
$button = id(new PHUIButtonView()) $button = id(new PHUIButtonView())
->setText(pht('View Full History')) ->setText(pht('View History'))
->setHref($drequest->generateURI( ->setHref($drequest->generateURI(
array( array(
'action' => 'history', 'action' => 'history',
@ -559,7 +581,8 @@ final class DiffusionRepositoryController extends DiffusionController {
->setTag('a') ->setTag('a')
->setIcon($icon); ->setIcon($icon);
$panel = new PHUIObjectBoxView(); $panel = id(new PHUIObjectBoxView())
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);
$header = id(new PHUIHeaderView()) $header = id(new PHUIHeaderView())
->setHeader(pht('Recent Commits')) ->setHeader(pht('Recent Commits'))
->addActionLink($button); ->addActionLink($button);
@ -569,6 +592,46 @@ final class DiffusionRepositoryController extends DiffusionController {
return $panel; return $panel;
} }
private function buildLocateFile() {
$request = $this->getRequest();
$viewer = $request->getUser();
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$locate_panel = null;
if ($repository->canUsePathTree()) {
Javelin::initBehavior(
'diffusion-locate-file',
array(
'controlID' => 'locate-control',
'inputID' => 'locate-input',
'browseBaseURI' => (string)$drequest->generateURI(
array(
'action' => 'browse',
)),
'uri' => (string)$drequest->generateURI(
array(
'action' => 'pathtree',
)),
));
$form = id(new AphrontFormView())
->setUser($viewer)
->appendChild(
id(new AphrontFormTypeaheadControl())
->setHardpointID('locate-control')
->setID('locate-input')
->setLabel(pht('Locate File')));
$form_box = id(new PHUIBoxView())
->appendChild($form->buildLayoutView());
$locate_panel = id(new PHUIObjectBoxView())
->setHeaderText(pht('Locate File'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->appendChild($form_box);
}
return $locate_panel;
}
private function buildBrowseTable( private function buildBrowseTable(
$browse_results, $browse_results,
$browse_paths, $browse_paths,
@ -606,9 +669,10 @@ final class DiffusionRepositoryController extends DiffusionController {
$browse_uri = $drequest->generateURI(array('action' => 'browse')); $browse_uri = $drequest->generateURI(array('action' => 'browse'));
$browse_panel = new PHUIObjectBoxView(); $browse_panel = id(new PHUIObjectBoxView())
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);
$header = id(new PHUIHeaderView()) $header = id(new PHUIHeaderView())
->setHeader(pht('Repository')); ->setHeader($repository->getName());
$icon = id(new PHUIIconView()) $icon = id(new PHUIIconView())
->setIcon('fa-folder-open'); ->setIcon('fa-folder-open');
@ -621,38 +685,6 @@ final class DiffusionRepositoryController extends DiffusionController {
$header->addActionLink($button); $header->addActionLink($button);
$browse_panel->setHeader($header); $browse_panel->setHeader($header);
$locate_panel = null;
if ($repository->canUsePathTree()) {
Javelin::initBehavior(
'diffusion-locate-file',
array(
'controlID' => 'locate-control',
'inputID' => 'locate-input',
'browseBaseURI' => (string)$drequest->generateURI(
array(
'action' => 'browse',
)),
'uri' => (string)$drequest->generateURI(
array(
'action' => 'pathtree',
)),
));
$form = id(new AphrontFormView())
->setUser($viewer)
->appendChild(
id(new AphrontFormTypeaheadControl())
->setHardpointID('locate-control')
->setID('locate-input')
->setLabel(pht('Locate File')));
$form_box = id(new PHUIBoxView())
->appendChild($form->buildLayoutView());
$locate_panel = id(new PHUIObjectBoxView())
->setHeaderText('Locate File')
->appendChild($form_box);
}
$browse_panel->setTable($browse_table); $browse_panel->setTable($browse_table);
$pager->setURI($browse_uri, 'offset'); $pager->setURI($browse_uri, 'offset');
@ -664,7 +696,6 @@ final class DiffusionRepositoryController extends DiffusionController {
} }
return array( return array(
$locate_panel,
$browse_panel, $browse_panel,
$pager_box, $pager_box,
); );

View file

@ -262,10 +262,26 @@ final class DiffusionRepositoryCreateController
$crumbs = $this->buildApplicationCrumbs(); $crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb($title); $crumbs->addTextCrumb($title);
$header = id(new PHUIHeaderView())
->setHeader($title)
->setHeaderIcon('fa-pencil');
$form_box = id(new PHUIObjectBoxView())
->setHeaderText($title)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setForm($form);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter(array(
$form,
));
return $this->newPage() return $this->newPage()
->setTitle($title) ->setTitle($title)
->setCrumbs($crumbs) ->setCrumbs($crumbs)
->appendChild($form); ->appendChild($view);
} }

View file

@ -53,6 +53,10 @@ final class DiffusionRepositoryEditActionsController
$title = pht('Edit Actions (%s)', $repository->getName()); $title = pht('Edit Actions (%s)', $repository->getName());
$header = id(new PHUIHeaderView())
->setHeader($title)
->setHeaderIcon('fa-pencil');
$policies = id(new PhabricatorPolicyQuery()) $policies = id(new PhabricatorPolicyQuery())
->setViewer($viewer) ->setViewer($viewer)
->setObject($repository) ->setObject($repository)
@ -97,13 +101,21 @@ final class DiffusionRepositoryEditActionsController
->addCancelButton($edit_uri)); ->addCancelButton($edit_uri));
$form_box = id(new PHUIObjectBoxView()) $form_box = id(new PHUIObjectBoxView())
->setHeaderText($title) ->setHeaderText(pht('Actions'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setForm($form); ->setForm($form);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter(array(
$form_box,
));
return $this->newPage() return $this->newPage()
->setTitle($title) ->setTitle($title)
->setCrumbs($crumbs) ->setCrumbs($crumbs)
->appendChild($form_box); ->appendChild($view);
} }
} }

View file

@ -49,6 +49,10 @@ final class DiffusionRepositoryEditAutomationController
$title = pht('Edit %s', $repository->getName()); $title = pht('Edit %s', $repository->getName());
$header = id(new PHUIHeaderView())
->setHeader($title)
->setHeaderIcon('fa-pencil');
$form = id(new AphrontFormView()) $form = id(new AphrontFormView())
->setUser($viewer) ->setUser($viewer)
->appendRemarkupInstructions( ->appendRemarkupInstructions(
@ -69,14 +73,21 @@ final class DiffusionRepositoryEditAutomationController
->setValue(pht('Save')) ->setValue(pht('Save'))
->addCancelButton($edit_uri)); ->addCancelButton($edit_uri));
$object_box = id(new PHUIObjectBoxView()) $form_box = id(new PHUIObjectBoxView())
->setHeaderText($title) ->setHeaderText(pht('Automation'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setForm($form); ->setForm($form);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter(array(
$form_box,
));
return $this->newPage() return $this->newPage()
->setTitle($title) ->setTitle($title)
->setCrumbs($crumbs) ->setCrumbs($crumbs)
->appendChild($object_box); ->appendChild($view);
} }
} }

View file

@ -105,6 +105,10 @@ final class DiffusionRepositoryEditBasicController
$title = pht('Edit %s', $repository->getName()); $title = pht('Edit %s', $repository->getName());
$header = id(new PHUIHeaderView())
->setHeader($title)
->setHeaderIcon('fa-pencil');
$form = id(new AphrontFormView()) $form = id(new AphrontFormView())
->setUser($viewer) ->setUser($viewer)
->appendChild( ->appendChild(
@ -144,16 +148,23 @@ final class DiffusionRepositoryEditBasicController
->appendChild(id(new PHUIFormDividerControl())) ->appendChild(id(new PHUIFormDividerControl()))
->appendRemarkupInstructions($this->getReadmeInstructions()); ->appendRemarkupInstructions($this->getReadmeInstructions());
$object_box = id(new PHUIObjectBoxView()) $form_box = id(new PHUIObjectBoxView())
->setHeaderText($title) ->setHeaderText(pht('Basic Information'))
->setValidationException($validation_exception) ->setValidationException($validation_exception)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setForm($form) ->setForm($form)
->setFormErrors($errors); ->setFormErrors($errors);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter(array(
$form_box,
));
return $this->newPage() return $this->newPage()
->setTitle($title) ->setTitle($title)
->setCrumbs($crumbs) ->setCrumbs($crumbs)
->appendChild($object_box); ->appendChild($view);
} }
private function getReadmeInstructions() { private function getReadmeInstructions() {

View file

@ -98,6 +98,9 @@ final class DiffusionRepositoryEditBranchesController
$crumbs->addTextCrumb(pht('Edit Branches')); $crumbs->addTextCrumb(pht('Edit Branches'));
$title = pht('Edit Branches (%s)', $repository->getName()); $title = pht('Edit Branches (%s)', $repository->getName());
$header = id(new PHUIHeaderView())
->setHeader($title)
->setHeaderIcon('fa-pencil');
$policies = id(new PhabricatorPolicyQuery()) $policies = id(new PhabricatorPolicyQuery())
->setViewer($viewer) ->setViewer($viewer)
@ -213,14 +216,21 @@ final class DiffusionRepositoryEditBranchesController
->addCancelButton($edit_uri)); ->addCancelButton($edit_uri));
$form_box = id(new PHUIObjectBoxView()) $form_box = id(new PHUIObjectBoxView())
->setHeaderText(pht('Branches'))
->setValidationException($validation_exception) ->setValidationException($validation_exception)
->setHeaderText($title) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setForm($form); ->setForm($form);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter(array(
$form_box,
));
return $this->newPage() return $this->newPage()
->setTitle($title) ->setTitle($title)
->setCrumbs($crumbs) ->setCrumbs($crumbs)
->appendChild($form_box); ->appendChild($view);
} }
private function processBranches($string) { private function processBranches($string) {

View file

@ -20,6 +20,7 @@ abstract class DiffusionRepositoryEditController
$crumbs->addTextCrumb(pht('Edit'), $edit_uri); $crumbs->addTextCrumb(pht('Edit'), $edit_uri);
} }
} }
$crumbs->setBorder(true);
return $crumbs; return $crumbs;
} }

View file

@ -50,6 +50,9 @@ final class DiffusionRepositoryEditEncodingController
$crumbs->addTextCrumb(pht('Edit Encoding')); $crumbs->addTextCrumb(pht('Edit Encoding'));
$title = pht('Edit %s', $repository->getName()); $title = pht('Edit %s', $repository->getName());
$header = id(new PHUIHeaderView())
->setHeader($title)
->setHeaderIcon('fa-pencil');
$form = id(new AphrontFormView()) $form = id(new AphrontFormView())
->setUser($user) ->setUser($user)
@ -65,15 +68,22 @@ final class DiffusionRepositoryEditEncodingController
->setValue(pht('Save Encoding')) ->setValue(pht('Save Encoding'))
->addCancelButton($edit_uri)); ->addCancelButton($edit_uri));
$object_box = id(new PHUIObjectBoxView()) $form_box = id(new PHUIObjectBoxView())
->setHeaderText($title) ->setHeaderText(pht('Encoding'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setForm($form) ->setForm($form)
->setFormErrors($errors); ->setFormErrors($errors);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter(array(
$form_box,
));
return $this->newPage() return $this->newPage()
->setTitle($title) ->setTitle($title)
->setCrumbs($crumbs) ->setCrumbs($crumbs)
->appendChild($object_box); ->appendChild($view);
} }
private function getEncodingInstructions() { private function getEncodingInstructions() {

View file

@ -57,6 +57,9 @@ final class DiffusionRepositoryEditHostingController
$crumbs->addTextCrumb(pht('Edit Hosting')); $crumbs->addTextCrumb(pht('Edit Hosting'));
$title = pht('Edit Hosting (%s)', $repository->getName()); $title = pht('Edit Hosting (%s)', $repository->getName());
$header = id(new PHUIHeaderView())
->setHeader($title)
->setHeaderIcon('fa-pencil');
$hosted_control = id(new AphrontFormRadioButtonControl()) $hosted_control = id(new AphrontFormRadioButtonControl())
->setName('hosting') ->setName('hosting')
@ -95,14 +98,21 @@ final class DiffusionRepositoryEditHostingController
->setValue(pht('Save and Continue')) ->setValue(pht('Save and Continue'))
->addCancelButton($edit_uri)); ->addCancelButton($edit_uri));
$object_box = id(new PHUIObjectBoxView()) $form_box = id(new PHUIObjectBoxView())
->setHeaderText($title) ->setHeaderText(pht('Hosting'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setForm($form); ->setForm($form);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter(array(
$form_box,
));
return $this->newPage() return $this->newPage()
->setTitle($title) ->setTitle($title)
->setCrumbs($crumbs) ->setCrumbs($crumbs)
->appendChild($object_box); ->appendChild($view);
} }
public function handleProtocols(PhabricatorRepository $repository) { public function handleProtocols(PhabricatorRepository $repository) {
@ -155,7 +165,9 @@ final class DiffusionRepositoryEditHostingController
$crumbs->addTextCrumb(pht('Edit Protocols')); $crumbs->addTextCrumb(pht('Edit Protocols'));
$title = pht('Edit Protocols (%s)', $repository->getName()); $title = pht('Edit Protocols (%s)', $repository->getName());
$header = id(new PHUIHeaderView())
->setHeader($title)
->setHeaderIcon('fa-pencil');
$rw_message = pht( $rw_message = pht(
'Phabricator will serve a read-write copy of this repository.'); 'Phabricator will serve a read-write copy of this repository.');
@ -256,14 +268,21 @@ final class DiffusionRepositoryEditHostingController
->setValue(pht('Save Changes')) ->setValue(pht('Save Changes'))
->addCancelButton($prev_uri, pht('Back'))); ->addCancelButton($prev_uri, pht('Back')));
$object_box = id(new PHUIObjectBoxView()) $form_box = id(new PHUIObjectBoxView())
->setHeaderText($title) ->setHeaderText(pht('Protocols'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setForm($form); ->setForm($form);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter(array(
$form_box,
));
return $this->newPage() return $this->newPage()
->setTitle($title) ->setTitle($title)
->setCrumbs($crumbs) ->setCrumbs($crumbs)
->appendChild($object_box); ->appendChild($view);
} }
} }

View file

@ -38,16 +38,16 @@ final class DiffusionRepositoryEditMainController
$title = pht('Edit %s', $repository->getName()); $title = pht('Edit %s', $repository->getName());
$header = id(new PHUIHeaderView()) $header = id(new PHUIHeaderView())
->setHeader($title); ->setHeader($title)
->setHeaderIcon('fa-pencil');
if ($repository->isTracked()) { if ($repository->isTracked()) {
$header->setStatus('fa-check', 'bluegrey', pht('Active')); $header->setStatus('fa-check', 'bluegrey', pht('Active'));
} else { } else {
$header->setStatus('fa-ban', 'dark', pht('Inactive')); $header->setStatus('fa-ban', 'dark', pht('Inactive'));
} }
$basic_actions = $this->buildBasicActions($repository); $curtain = $this->buildCurtain($repository);
$basic_properties = $basic_properties = $this->buildBasicProperties($repository);
$this->buildBasicProperties($repository, $basic_actions);
$policy_actions = $this->buildPolicyActions($repository); $policy_actions = $this->buildPolicyActions($repository);
$policy_properties = $policy_properties =
@ -119,16 +119,14 @@ final class DiffusionRepositoryEditMainController
$boxes = array(); $boxes = array();
$boxes[] = id(new PHUIObjectBoxView())
->setHeader($header)
->addPropertyList($basic_properties);
$boxes[] = id(new PHUIObjectBoxView()) $boxes[] = id(new PHUIObjectBoxView())
->setHeaderText(pht('Policies')) ->setHeaderText(pht('Policies'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($policy_properties); ->addPropertyList($policy_properties);
$boxes[] = id(new PHUIObjectBoxView()) $boxes[] = id(new PHUIObjectBoxView())
->setHeaderText(pht('Hosting')) ->setHeaderText(pht('Hosting'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($hosting_properties); ->addPropertyList($hosting_properties);
if ($repository->canMirror()) { if ($repository->canMirror()) {
@ -156,6 +154,7 @@ final class DiffusionRepositoryEditMainController
$boxes[] = id(new PHUIObjectBoxView()) $boxes[] = id(new PHUIObjectBoxView())
->setFormErrors($mirror_info) ->setFormErrors($mirror_info)
->setHeaderText(pht('Mirrors')) ->setHeaderText(pht('Mirrors'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($mirror_properties); ->addPropertyList($mirror_properties);
$boxes[] = $mirror_list; $boxes[] = $mirror_list;
@ -164,73 +163,88 @@ final class DiffusionRepositoryEditMainController
if ($remote_properties) { if ($remote_properties) {
$boxes[] = id(new PHUIObjectBoxView()) $boxes[] = id(new PHUIObjectBoxView())
->setHeaderText(pht('Remote')) ->setHeaderText(pht('Remote'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($remote_properties); ->addPropertyList($remote_properties);
} }
if ($storage_properties) { if ($storage_properties) {
$boxes[] = id(new PHUIObjectBoxView()) $boxes[] = id(new PHUIObjectBoxView())
->setHeaderText(pht('Storage')) ->setHeaderText(pht('Storage'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($storage_properties); ->addPropertyList($storage_properties);
} }
if ($staging_properties) { if ($staging_properties) {
$boxes[] = id(new PHUIObjectBoxView()) $boxes[] = id(new PHUIObjectBoxView())
->setHeaderText(pht('Staging')) ->setHeaderText(pht('Staging'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($staging_properties); ->addPropertyList($staging_properties);
} }
if ($automation_properties) { if ($automation_properties) {
$boxes[] = id(new PHUIObjectBoxView()) $boxes[] = id(new PHUIObjectBoxView())
->setHeaderText(pht('Automation')) ->setHeaderText(pht('Automation'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($automation_properties); ->addPropertyList($automation_properties);
} }
$boxes[] = id(new PHUIObjectBoxView()) $boxes[] = id(new PHUIObjectBoxView())
->setHeaderText(pht('Text Encoding')) ->setHeaderText(pht('Text Encoding'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($encoding_properties); ->addPropertyList($encoding_properties);
$boxes[] = id(new PHUIObjectBoxView()) $boxes[] = id(new PHUIObjectBoxView())
->setHeaderText(pht('Symbols')) ->setHeaderText(pht('Symbols'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($symbols_properties); ->addPropertyList($symbols_properties);
if ($branches_properties) { if ($branches_properties) {
$boxes[] = id(new PHUIObjectBoxView()) $boxes[] = id(new PHUIObjectBoxView())
->setHeaderText(pht('Branches')) ->setHeaderText(pht('Branches'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($branches_properties); ->addPropertyList($branches_properties);
} }
if ($subversion_properties) { if ($subversion_properties) {
$boxes[] = id(new PHUIObjectBoxView()) $boxes[] = id(new PHUIObjectBoxView())
->setHeaderText(pht('Subversion')) ->setHeaderText(pht('Subversion'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($subversion_properties); ->addPropertyList($subversion_properties);
} }
$boxes[] = id(new PHUIObjectBoxView()) $boxes[] = id(new PHUIObjectBoxView())
->setHeaderText(pht('Actions')) ->setHeaderText(pht('Actions'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($actions_properties); ->addPropertyList($actions_properties);
return $this->buildApplicationPage( $crumbs->setBorder(true);
array(
$crumbs, $view = id(new PHUITwoColumnView())
->setHeader($header)
->setCurtain($curtain)
->addPropertySection(pht('Properties'), $basic_properties)
->setMainColumn(array(
$boxes, $boxes,
$timeline, $timeline,
),
array(
'title' => $title,
)); ));
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
->appendChild($view);
} }
private function buildBasicActions(PhabricatorRepository $repository) { private function buildCurtain(PhabricatorRepository $repository) {
$viewer = $this->getRequest()->getUser(); $viewer = $this->getViewer();
$view = id(new PhabricatorActionListView()) $curtain = $this->newCurtainView($repository);
->setUser($viewer);
$edit = id(new PhabricatorActionView()) $edit = id(new PhabricatorActionView())
->setIcon('fa-pencil') ->setIcon('fa-pencil')
->setName(pht('Edit Basic Information')) ->setName(pht('Edit Basic Information'))
->setHref($this->getRepositoryControllerURI($repository, 'edit/basic/')); ->setHref($this->getRepositoryControllerURI($repository, 'edit/basic/'));
$view->addAction($edit); $curtain->addAction($edit);
$edit = id(new PhabricatorActionView()) $edit = id(new PhabricatorActionView())
->setIcon('fa-refresh') ->setIcon('fa-refresh')
@ -238,7 +252,7 @@ final class DiffusionRepositoryEditMainController
->setWorkflow(true) ->setWorkflow(true)
->setHref( ->setHref(
$this->getRepositoryControllerURI($repository, 'edit/update/')); $this->getRepositoryControllerURI($repository, 'edit/update/'));
$view->addAction($edit); $curtain->addAction($edit);
$activate = id(new PhabricatorActionView()) $activate = id(new PhabricatorActionView())
->setHref( ->setHref(
@ -255,9 +269,9 @@ final class DiffusionRepositoryEditMainController
->setName(pht('Activate Repository')); ->setName(pht('Activate Repository'));
} }
$view->addAction($activate); $curtain->addAction($activate);
$view->addAction( $curtain->addAction(
id(new PhabricatorActionView()) id(new PhabricatorActionView())
->setName(pht('Delete Repository')) ->setName(pht('Delete Repository'))
->setIcon('fa-times') ->setIcon('fa-times')
@ -266,19 +280,16 @@ final class DiffusionRepositoryEditMainController
->setDisabled(true) ->setDisabled(true)
->setWorkflow(true)); ->setWorkflow(true));
return $view; return $curtain;
} }
private function buildBasicProperties( private function buildBasicProperties(
PhabricatorRepository $repository, PhabricatorRepository $repository) {
PhabricatorActionListView $actions) {
$viewer = $this->getRequest()->getUser(); $viewer = $this->getViewer();
$view = id(new PHUIPropertyListView()) $view = id(new PHUIPropertyListView())
->setUser($viewer) ->setUser($viewer);
->setObject($repository)
->setActionList($actions);
$type = PhabricatorRepositoryType::getNameForRepositoryType( $type = PhabricatorRepositoryType::getNameForRepositoryType(
$repository->getVersionControlSystem()); $repository->getVersionControlSystem());
@ -322,7 +333,7 @@ final class DiffusionRepositoryEditMainController
} }
private function buildEncodingActions(PhabricatorRepository $repository) { private function buildEncodingActions(PhabricatorRepository $repository) {
$viewer = $this->getRequest()->getUser(); $viewer = $this->getViewer();
$view = id(new PhabricatorActionListView()) $view = id(new PhabricatorActionListView())
->setUser($viewer); ->setUser($viewer);
@ -341,7 +352,7 @@ final class DiffusionRepositoryEditMainController
PhabricatorRepository $repository, PhabricatorRepository $repository,
PhabricatorActionListView $actions) { PhabricatorActionListView $actions) {
$viewer = $this->getRequest()->getUser(); $viewer = $this->getViewer();
$view = id(new PHUIPropertyListView()) $view = id(new PHUIPropertyListView())
->setUser($viewer) ->setUser($viewer)
@ -358,7 +369,7 @@ final class DiffusionRepositoryEditMainController
} }
private function buildPolicyActions(PhabricatorRepository $repository) { private function buildPolicyActions(PhabricatorRepository $repository) {
$viewer = $this->getRequest()->getUser(); $viewer = $this->getViewer();
$view = id(new PhabricatorActionListView()) $view = id(new PhabricatorActionListView())
->setUser($viewer); ->setUser($viewer);
@ -377,7 +388,7 @@ final class DiffusionRepositoryEditMainController
PhabricatorRepository $repository, PhabricatorRepository $repository,
PhabricatorActionListView $actions) { PhabricatorActionListView $actions) {
$viewer = $this->getRequest()->getUser(); $viewer = $this->getViewer();
$view = id(new PHUIPropertyListView()) $view = id(new PHUIPropertyListView())
->setUser($viewer) ->setUser($viewer)
@ -412,7 +423,7 @@ final class DiffusionRepositoryEditMainController
} }
private function buildBranchesActions(PhabricatorRepository $repository) { private function buildBranchesActions(PhabricatorRepository $repository) {
$viewer = $this->getRequest()->getUser(); $viewer = $this->getViewer();
$view = id(new PhabricatorActionListView()) $view = id(new PhabricatorActionListView())
->setUser($viewer); ->setUser($viewer);
@ -431,7 +442,7 @@ final class DiffusionRepositoryEditMainController
PhabricatorRepository $repository, PhabricatorRepository $repository,
PhabricatorActionListView $actions) { PhabricatorActionListView $actions) {
$viewer = $this->getRequest()->getUser(); $viewer = $this->getViewer();
$view = id(new PHUIPropertyListView()) $view = id(new PHUIPropertyListView())
->setUser($viewer) ->setUser($viewer)
@ -461,7 +472,7 @@ final class DiffusionRepositoryEditMainController
} }
private function buildSubversionActions(PhabricatorRepository $repository) { private function buildSubversionActions(PhabricatorRepository $repository) {
$viewer = $this->getRequest()->getUser(); $viewer = $this->getViewer();
$view = id(new PhabricatorActionListView()) $view = id(new PhabricatorActionListView())
->setUser($viewer); ->setUser($viewer);
@ -480,7 +491,7 @@ final class DiffusionRepositoryEditMainController
PhabricatorRepository $repository, PhabricatorRepository $repository,
PhabricatorActionListView $actions) { PhabricatorActionListView $actions) {
$viewer = $this->getRequest()->getUser(); $viewer = $this->getViewer();
$view = id(new PHUIPropertyListView()) $view = id(new PHUIPropertyListView())
->setUser($viewer) ->setUser($viewer)
@ -500,7 +511,7 @@ final class DiffusionRepositoryEditMainController
} }
private function buildActionsActions(PhabricatorRepository $repository) { private function buildActionsActions(PhabricatorRepository $repository) {
$viewer = $this->getRequest()->getUser(); $viewer = $this->getViewer();
$view = id(new PhabricatorActionListView()) $view = id(new PhabricatorActionListView())
->setUser($viewer); ->setUser($viewer);
@ -519,7 +530,7 @@ final class DiffusionRepositoryEditMainController
PhabricatorRepository $repository, PhabricatorRepository $repository,
PhabricatorActionListView $actions) { PhabricatorActionListView $actions) {
$viewer = $this->getRequest()->getUser(); $viewer = $this->getViewer();
$view = id(new PHUIPropertyListView()) $view = id(new PHUIPropertyListView())
->setUser($viewer) ->setUser($viewer)
@ -541,7 +552,7 @@ final class DiffusionRepositoryEditMainController
} }
private function buildRemoteActions(PhabricatorRepository $repository) { private function buildRemoteActions(PhabricatorRepository $repository) {
$viewer = $this->getRequest()->getUser(); $viewer = $this->getViewer();
$view = id(new PhabricatorActionListView()) $view = id(new PhabricatorActionListView())
->setUser($viewer); ->setUser($viewer);
@ -560,7 +571,7 @@ final class DiffusionRepositoryEditMainController
PhabricatorRepository $repository, PhabricatorRepository $repository,
PhabricatorActionListView $actions) { PhabricatorActionListView $actions) {
$viewer = $this->getRequest()->getUser(); $viewer = $this->getViewer();
$view = id(new PHUIPropertyListView()) $view = id(new PHUIPropertyListView())
->setUser($viewer) ->setUser($viewer)
@ -581,7 +592,7 @@ final class DiffusionRepositoryEditMainController
} }
private function buildStorageActions(PhabricatorRepository $repository) { private function buildStorageActions(PhabricatorRepository $repository) {
$viewer = $this->getRequest()->getUser(); $viewer = $this->getViewer();
$view = id(new PhabricatorActionListView()) $view = id(new PhabricatorActionListView())
->setUser($viewer); ->setUser($viewer);
@ -600,7 +611,7 @@ final class DiffusionRepositoryEditMainController
PhabricatorRepository $repository, PhabricatorRepository $repository,
PhabricatorActionListView $actions) { PhabricatorActionListView $actions) {
$viewer = $this->getRequest()->getUser(); $viewer = $this->getViewer();
$view = id(new PHUIPropertyListView()) $view = id(new PHUIPropertyListView())
->setUser($viewer) ->setUser($viewer)
@ -801,7 +812,7 @@ final class DiffusionRepositoryEditMainController
private function buildRepositoryStatus( private function buildRepositoryStatus(
PhabricatorRepository $repository) { PhabricatorRepository $repository) {
$viewer = $this->getRequest()->getUser(); $viewer = $this->getViewer();
$is_cluster = $repository->getAlmanacServicePHID(); $is_cluster = $repository->getAlmanacServicePHID();
$view = new PHUIStatusListView(); $view = new PHUIStatusListView();
@ -1188,7 +1199,7 @@ final class DiffusionRepositoryEditMainController
private function buildMirrorActions( private function buildMirrorActions(
PhabricatorRepository $repository) { PhabricatorRepository $repository) {
$viewer = $this->getRequest()->getUser(); $viewer = $this->getViewer();
$mirror_actions = id(new PhabricatorActionListView()) $mirror_actions = id(new PhabricatorActionListView())
->setUser($viewer); ->setUser($viewer);
@ -1211,7 +1222,7 @@ final class DiffusionRepositoryEditMainController
PhabricatorRepository $repository, PhabricatorRepository $repository,
PhabricatorActionListView $actions) { PhabricatorActionListView $actions) {
$viewer = $this->getRequest()->getUser(); $viewer = $this->getViewer();
$mirror_properties = id(new PHUIPropertyListView()) $mirror_properties = id(new PHUIPropertyListView())
->setUser($viewer) ->setUser($viewer)
@ -1262,11 +1273,14 @@ final class DiffusionRepositoryEditMainController
$mirror_list->addItem($item); $mirror_list->addItem($item);
} }
return $mirror_list; return id(new PHUIObjectBoxView())
->setHeaderText(pht('Configured Mirrors'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setObjectList($mirror_list);
} }
private function buildSymbolsActions(PhabricatorRepository $repository) { private function buildSymbolsActions(PhabricatorRepository $repository) {
$viewer = $this->getRequest()->getUser(); $viewer = $this->getViewer();
$view = id(new PhabricatorActionListView()) $view = id(new PhabricatorActionListView())
->setUser($viewer); ->setUser($viewer);
@ -1285,7 +1299,7 @@ final class DiffusionRepositoryEditMainController
PhabricatorRepository $repository, PhabricatorRepository $repository,
PhabricatorActionListView $actions) { PhabricatorActionListView $actions) {
$viewer = $this->getRequest()->getUser(); $viewer = $this->getViewer();
$view = id(new PHUIPropertyListView()) $view = id(new PHUIPropertyListView())
->setUser($viewer) ->setUser($viewer)

View file

@ -45,7 +45,10 @@ final class DiffusionRepositoryEditStagingController
$crumbs = $this->buildApplicationCrumbs(); $crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Edit Staging')); $crumbs->addTextCrumb(pht('Edit Staging'));
$title = pht('Edit %s', $repository->getName()); $title = pht('Edit Staging (%s)', $repository->getName());
$header = id(new PHUIHeaderView())
->setHeader($title)
->setHeaderIcon('fa-pencil');
$form = id(new AphrontFormView()) $form = id(new AphrontFormView())
->setUser($viewer) ->setUser($viewer)
@ -68,14 +71,21 @@ final class DiffusionRepositoryEditStagingController
->setValue(pht('Save')) ->setValue(pht('Save'))
->addCancelButton($edit_uri)); ->addCancelButton($edit_uri));
$object_box = id(new PHUIObjectBoxView()) $form_box = id(new PHUIObjectBoxView())
->setHeaderText($title) ->setHeaderText(pht('Staging'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setForm($form); ->setForm($form);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter(array(
$form_box,
));
return $this->newPage() return $this->newPage()
->setTitle($title) ->setTitle($title)
->setCrumbs($crumbs) ->setCrumbs($crumbs)
->appendChild($object_box); ->appendChild($view);
} }
} }

View file

@ -22,6 +22,9 @@ final class DiffusionRepositoryEditStorageController
$crumbs->addTextCrumb(pht('Edit Storage')); $crumbs->addTextCrumb(pht('Edit Storage'));
$title = pht('Edit %s', $repository->getName()); $title = pht('Edit %s', $repository->getName());
$header = id(new PHUIHeaderView())
->setHeader($title)
->setHeaderIcon('fa-pencil');
$service_phid = $repository->getAlmanacServicePHID(); $service_phid = $repository->getAlmanacServicePHID();
if ($service_phid) { if ($service_phid) {
@ -57,15 +60,21 @@ final class DiffusionRepositoryEditStorageController
id(new AphrontFormSubmitControl()) id(new AphrontFormSubmitControl())
->addCancelButton($edit_uri, pht('Done'))); ->addCancelButton($edit_uri, pht('Done')));
$object_box = id(new PHUIObjectBoxView()) $form_box = id(new PHUIObjectBoxView())
->setHeaderText($title) ->setHeaderText(pht('Storage'))
->setForm($form) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setFormErrors($errors); ->setForm($form);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter(array(
$form_box,
));
return $this->newPage() return $this->newPage()
->setTitle($title) ->setTitle($title)
->setCrumbs($crumbs) ->setCrumbs($crumbs)
->appendChild($object_box); ->appendChild($view);
} }
} }

View file

@ -63,6 +63,9 @@ final class DiffusionRepositoryEditSubversionController
$crumbs->addTextCrumb(pht('Edit Subversion Info')); $crumbs->addTextCrumb(pht('Edit Subversion Info'));
$title = pht('Edit Subversion Info (%s)', $repository->getName()); $title = pht('Edit Subversion Info (%s)', $repository->getName());
$header = id(new PHUIHeaderView())
->setHeader($title)
->setHeaderIcon('fa-pencil');
$policies = id(new PhabricatorPolicyQuery()) $policies = id(new PhabricatorPolicyQuery())
->setViewer($viewer) ->setViewer($viewer)
@ -96,13 +99,20 @@ final class DiffusionRepositoryEditSubversionController
->addCancelButton($edit_uri)); ->addCancelButton($edit_uri));
$form_box = id(new PHUIObjectBoxView()) $form_box = id(new PHUIObjectBoxView())
->setHeaderText($title) ->setHeaderText(pht('Subversion'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setForm($form); ->setForm($form);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter(array(
$form_box,
));
return $this->newPage() return $this->newPage()
->setTitle($title) ->setTitle($title)
->setCrumbs($crumbs) ->setCrumbs($crumbs)
->appendChild($form_box); ->appendChild($view);
} }
} }

View file

@ -59,7 +59,10 @@ final class DiffusionRepositorySymbolsController
$crumbs = $this->buildApplicationCrumbs(); $crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Edit Symbols')); $crumbs->addTextCrumb(pht('Edit Symbols'));
$title = pht('Edit %s', $repository->getName()); $title = pht('Edit Symbols (%s)', $repository->getName());
$header = id(new PHUIHeaderView())
->setHeader($title)
->setHeaderIcon('fa-pencil');
$form = id(new AphrontFormView()) $form = id(new AphrontFormView())
->setUser($viewer) ->setUser($viewer)
@ -85,15 +88,22 @@ final class DiffusionRepositorySymbolsController
->setValue(pht('Save')) ->setValue(pht('Save'))
->addCancelButton($edit_uri)); ->addCancelButton($edit_uri));
$object_box = id(new PHUIObjectBoxView()) $form_box = id(new PHUIObjectBoxView())
->setHeaderText($title) ->setHeaderText(pht('Symbols'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setForm($form) ->setForm($form)
->setFormErrors($errors); ->setFormErrors($errors);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter(array(
$form_box,
));
return $this->newPage() return $this->newPage()
->setTitle($title) ->setTitle($title)
->setCrumbs($crumbs) ->setCrumbs($crumbs)
->appendChild($object_box); ->appendChild($view);
} }
private function getInstructions() { private function getInstructions() {

View file

@ -5,7 +5,12 @@ final class DiffusionServeController extends DiffusionController {
private $serviceViewer; private $serviceViewer;
private $serviceRepository; private $serviceRepository;
private $isGitLFSRequest;
private $gitLFSToken;
public function setServiceViewer(PhabricatorUser $viewer) { public function setServiceViewer(PhabricatorUser $viewer) {
$this->getRequest()->setUser($viewer);
$this->serviceViewer = $viewer; $this->serviceViewer = $viewer;
return $this; return $this;
} }
@ -23,6 +28,14 @@ final class DiffusionServeController extends DiffusionController {
return $this->serviceRepository; return $this->serviceRepository;
} }
public function getIsGitLFSRequest() {
return $this->isGitLFSRequest;
}
public function getGitLFSToken() {
return $this->gitLFSToken;
}
public function isVCSRequest(AphrontRequest $request) { public function isVCSRequest(AphrontRequest $request) {
$identifier = $this->getRepositoryIdentifierFromRequest($request); $identifier = $this->getRepositoryIdentifierFromRequest($request);
if ($identifier === null) { if ($identifier === null) {
@ -31,6 +44,10 @@ final class DiffusionServeController extends DiffusionController {
$content_type = $request->getHTTPHeader('Content-Type'); $content_type = $request->getHTTPHeader('Content-Type');
$user_agent = idx($_SERVER, 'HTTP_USER_AGENT'); $user_agent = idx($_SERVER, 'HTTP_USER_AGENT');
$request_type = $request->getHTTPHeader('X-Phabricator-Request-Type');
// This may have a "charset" suffix, so only match the prefix.
$lfs_pattern = '(^application/vnd\\.git-lfs\\+json(;|\z))';
$vcs = null; $vcs = null;
if ($request->getExists('service')) { if ($request->getExists('service')) {
@ -46,6 +63,14 @@ final class DiffusionServeController extends DiffusionController {
} else if ($content_type == 'application/x-git-receive-pack-request') { } else if ($content_type == 'application/x-git-receive-pack-request') {
// We get this for `git-receive-pack`. // We get this for `git-receive-pack`.
$vcs = PhabricatorRepositoryType::REPOSITORY_TYPE_GIT; $vcs = PhabricatorRepositoryType::REPOSITORY_TYPE_GIT;
} else if (preg_match($lfs_pattern, $content_type)) {
// This is a Git LFS HTTP API request.
$vcs = PhabricatorRepositoryType::REPOSITORY_TYPE_GIT;
$this->isGitLFSRequest = true;
} else if ($request_type == 'git-lfs') {
// This is a Git LFS object content request.
$vcs = PhabricatorRepositoryType::REPOSITORY_TYPE_GIT;
$this->isGitLFSRequest = true;
} else if ($request->getExists('cmd')) { } else if ($request->getExists('cmd')) {
// Mercurial also sends an Accept header like // Mercurial also sends an Accept header like
// "application/mercurial-0.1", and a User-Agent like // "application/mercurial-0.1", and a User-Agent like
@ -142,7 +167,17 @@ final class DiffusionServeController extends DiffusionController {
$username = $_SERVER['PHP_AUTH_USER']; $username = $_SERVER['PHP_AUTH_USER'];
$password = new PhutilOpaqueEnvelope($_SERVER['PHP_AUTH_PW']); $password = new PhutilOpaqueEnvelope($_SERVER['PHP_AUTH_PW']);
// Try Git LFS auth first since we can usually reject it without doing
// any queries, since the username won't match the one we expect or the
// request won't be LFS.
$viewer = $this->authenticateGitLFSUser($username, $password);
// If that failed, try normal auth. Note that we can use normal auth on
// LFS requests, so this isn't strictly an alternative to LFS auth.
if (!$viewer) {
$viewer = $this->authenticateHTTPRepositoryUser($username, $password); $viewer = $this->authenticateHTTPRepositoryUser($username, $password);
}
if (!$viewer) { if (!$viewer) {
return new PhabricatorVCSResponse( return new PhabricatorVCSResponse(
403, 403,
@ -202,6 +237,11 @@ final class DiffusionServeController extends DiffusionController {
} }
} }
$response = $this->validateGitLFSRequest($repository, $viewer);
if ($response) {
return $response;
}
$this->setServiceRepository($repository); $this->setServiceRepository($repository);
if (!$repository->isTracked()) { if (!$repository->isTracked()) {
@ -212,6 +252,12 @@ final class DiffusionServeController extends DiffusionController {
$is_push = !$this->isReadOnlyRequest($repository); $is_push = !$this->isReadOnlyRequest($repository);
if ($this->getIsGitLFSRequest() && $this->getGitLFSToken()) {
// We allow git LFS requests over HTTP even if the repository does not
// otherwise support HTTP reads or writes, as long as the user is using a
// token from SSH. If they're using HTTP username + password auth, they
// have to obey the normal HTTP rules.
} else {
switch ($repository->getServeOverHTTP()) { switch ($repository->getServeOverHTTP()) {
case PhabricatorRepository::SERVE_READONLY: case PhabricatorRepository::SERVE_READONLY:
if ($is_push) { if ($is_push) {
@ -221,6 +267,16 @@ final class DiffusionServeController extends DiffusionController {
} }
break; break;
case PhabricatorRepository::SERVE_READWRITE: case PhabricatorRepository::SERVE_READWRITE:
// We'll check for push capability below.
break;
case PhabricatorRepository::SERVE_OFF:
default:
return new PhabricatorVCSResponse(
403,
pht('This repository is not available over HTTP.'));
}
}
if ($is_push) { if ($is_push) {
$can_push = PhabricatorPolicyFilter::hasCapability( $can_push = PhabricatorPolicyFilter::hasCapability(
$viewer, $viewer,
@ -230,7 +286,9 @@ final class DiffusionServeController extends DiffusionController {
if ($viewer->isLoggedIn()) { if ($viewer->isLoggedIn()) {
return new PhabricatorVCSResponse( return new PhabricatorVCSResponse(
403, 403,
pht('You do not have permission to push to this repository.')); pht(
'You do not have permission to push to this '.
'repository.'));
} else { } else {
if ($allow_auth) { if ($allow_auth) {
return new PhabricatorVCSResponse( return new PhabricatorVCSResponse(
@ -246,13 +304,6 @@ final class DiffusionServeController extends DiffusionController {
} }
} }
} }
break;
case PhabricatorRepository::SERVE_OFF:
default:
return new PhabricatorVCSResponse(
403,
pht('This repository is not available over HTTP.'));
}
$vcs_type = $repository->getVersionControlSystem(); $vcs_type = $repository->getVersionControlSystem();
$req_type = $this->isVCSRequest($request); $req_type = $this->isVCSRequest($request);
@ -324,6 +375,14 @@ final class DiffusionServeController extends DiffusionController {
PhabricatorRepository $repository, PhabricatorRepository $repository,
PhabricatorUser $viewer) { PhabricatorUser $viewer) {
// We can serve Git LFS requests first, since we don't need to proxy them.
// It's also important that LFS requests never fall through to standard
// service pathways, because that would let you use LFS tokens to read
// normal repository data.
if ($this->getIsGitLFSRequest()) {
return $this->serveGitLFSRequest($repository, $viewer);
}
// If this repository is hosted on a service, we need to proxy the request // If this repository is hosted on a service, we need to proxy the request
// to a host which can serve it. // to a host which can serve it.
$is_cluster_request = $this->getRequest()->isProxiedClusterRequest(); $is_cluster_request = $this->getRequest()->isProxiedClusterRequest();
@ -363,6 +422,8 @@ final class DiffusionServeController extends DiffusionController {
// TODO: This implementation is safe by default, but very incomplete. // TODO: This implementation is safe by default, but very incomplete.
// TODO: This doesn't get the right result for Git LFS yet.
switch ($repository->getVersionControlSystem()) { switch ($repository->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$service = $request->getStr('service'); $service = $request->getStr('service');
@ -514,6 +575,52 @@ final class DiffusionServeController extends DiffusionController {
return $base_path; return $base_path;
} }
private function authenticateGitLFSUser(
$username,
PhutilOpaqueEnvelope $password) {
// Never accept these credentials for requests which aren't LFS requests.
if (!$this->getIsGitLFSRequest()) {
return null;
}
// If we have the wrong username, don't bother checking if the token
// is right.
if ($username !== DiffusionGitLFSTemporaryTokenType::HTTP_USERNAME) {
return null;
}
$lfs_pass = $password->openEnvelope();
$lfs_hash = PhabricatorHash::digest($lfs_pass);
$token = id(new PhabricatorAuthTemporaryTokenQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withTokenTypes(array(DiffusionGitLFSTemporaryTokenType::TOKENTYPE))
->withTokenCodes(array($lfs_hash))
->withExpired(false)
->executeOne();
if (!$token) {
return null;
}
$user = id(new PhabricatorPeopleQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withPHIDs(array($token->getUserPHID()))
->executeOne();
if (!$user) {
return null;
}
if (!$user->isUserActivated()) {
return null;
}
$this->gitLFSToken = $token;
return $user;
}
private function authenticateHTTPRepositoryUser( private function authenticateHTTPRepositoryUser(
$username, $username,
PhutilOpaqueEnvelope $password) { PhutilOpaqueEnvelope $password) {
@ -739,4 +846,291 @@ final class DiffusionServeController extends DiffusionController {
); );
} }
private function validateGitLFSRequest(
PhabricatorRepository $repository,
PhabricatorUser $viewer) {
if (!$this->getIsGitLFSRequest()) {
return null;
}
if (!$repository->canUseGitLFS()) {
return new PhabricatorVCSResponse(
403,
pht(
'The requested repository ("%s") does not support Git LFS.',
$repository->getDisplayName()));
}
// If this is using an LFS token, sanity check that we're using it on the
// correct repository. This shouldn't really matter since the user could
// just request a proper token anyway, but it suspicious and should not
// be permitted.
$token = $this->getGitLFSToken();
if ($token) {
$resource = $token->getTokenResource();
if ($resource !== $repository->getPHID()) {
return new PhabricatorVCSResponse(
403,
pht(
'The authentication token provided in the request is bound to '.
'a different repository than the requested repository ("%s").',
$repository->getDisplayName()));
}
}
return null;
}
private function serveGitLFSRequest(
PhabricatorRepository $repository,
PhabricatorUser $viewer) {
if (!$this->getIsGitLFSRequest()) {
throw new Exception(pht('This is not a Git LFS request!'));
}
$path = $this->getGitLFSRequestPath($repository);
$matches = null;
if (preg_match('(^upload/(.*)\z)', $path, $matches)) {
$oid = $matches[1];
return $this->serveGitLFSUploadRequest($repository, $viewer, $oid);
} else if ($path == 'objects/batch') {
return $this->serveGitLFSBatchRequest($repository, $viewer);
} else {
return DiffusionGitLFSResponse::newErrorResponse(
404,
pht(
'Git LFS operation "%s" is not supported by this server.',
$path));
}
}
private function serveGitLFSBatchRequest(
PhabricatorRepository $repository,
PhabricatorUser $viewer) {
$input = PhabricatorStartup::getRawInput();
$input = phutil_json_decode($input);
$operation = idx($input, 'operation');
switch ($operation) {
case 'upload':
$want_upload = true;
break;
case 'download':
$want_upload = false;
break;
default:
return DiffusionGitLFSResponse::newErrorResponse(
404,
pht(
'Git LFS batch operation "%s" is not supported by this server.',
$operation));
}
$objects = idx($input, 'objects', array());
$hashes = array();
foreach ($objects as $object) {
$hashes[] = idx($object, 'oid');
}
if ($hashes) {
$refs = id(new PhabricatorRepositoryGitLFSRefQuery())
->setViewer($viewer)
->withRepositoryPHIDs(array($repository->getPHID()))
->withObjectHashes($hashes)
->execute();
$refs = mpull($refs, null, 'getObjectHash');
} else {
$refs = array();
}
$file_phids = mpull($refs, 'getFilePHID');
if ($file_phids) {
$files = id(new PhabricatorFileQuery())
->setViewer($viewer)
->withPHIDs($file_phids)
->execute();
$files = mpull($files, null, 'getPHID');
} else {
$files = array();
}
$authorization = null;
$output = array();
foreach ($objects as $object) {
$oid = idx($object, 'oid');
$size = idx($object, 'size');
$ref = idx($refs, $oid);
$error = null;
// NOTE: If we already have a ref for this object, we only emit a
// "download" action. The client should not upload the file again.
$actions = array();
if ($ref) {
$file = idx($files, $ref->getFilePHID());
if ($file) {
// Git LFS may prompt users for authentication if the action does
// not provide an "Authorization" header and does not have a query
// parameter named "token". See here for discussion:
// <https://github.com/github/git-lfs/issues/1088>
$no_authorization = 'Basic '.base64_encode('none');
$get_uri = $file->getCDNURIWithToken();
$actions['download'] = array(
'href' => $get_uri,
'header' => array(
'Authorization' => $no_authorization,
),
);
} else {
$error = array(
'code' => 404,
'message' => pht(
'Object "%s" was previously uploaded, but no longer exists '.
'on this server.',
$oid),
);
}
} else if ($want_upload) {
if (!$authorization) {
// Here, we could reuse the existing authorization if we have one,
// but it's a little simpler to just generate a new one
// unconditionally.
$authorization = $this->newGitLFSHTTPAuthorization(
$repository,
$viewer,
$operation);
}
$put_uri = $repository->getGitLFSURI("info/lfs/upload/{$oid}");
$actions['upload'] = array(
'href' => $put_uri,
'header' => array(
'Authorization' => $authorization,
'X-Phabricator-Request-Type' => 'git-lfs',
),
);
}
$object = array(
'oid' => $oid,
'size' => $size,
);
if ($actions) {
$object['actions'] = $actions;
}
if ($error) {
$object['error'] = $error;
}
$output[] = $object;
}
$output = array(
'objects' => $output,
);
return id(new DiffusionGitLFSResponse())
->setContent($output);
}
private function serveGitLFSUploadRequest(
PhabricatorRepository $repository,
PhabricatorUser $viewer,
$oid) {
$ref = id(new PhabricatorRepositoryGitLFSRefQuery())
->setViewer($viewer)
->withRepositoryPHIDs(array($repository->getPHID()))
->withObjectHashes(array($oid))
->executeOne();
if ($ref) {
return DiffusionGitLFSResponse::newErrorResponse(
405,
pht(
'Content for object "%s" is already known to this server. It can '.
'not be uploaded again.',
$oid));
}
$request_stream = new AphrontRequestStream();
$request_iterator = $request_stream->getIterator();
$hashing_iterator = id(new PhutilHashingIterator($request_iterator))
->setAlgorithm('sha256');
$source = id(new PhabricatorIteratorFileUploadSource())
->setName('lfs-'.$oid)
->setViewPolicy(PhabricatorPolicies::POLICY_NOONE)
->setIterator($hashing_iterator);
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
$file = $source->uploadFile();
unset($unguarded);
$hash = $hashing_iterator->getHash();
if ($hash !== $oid) {
return DiffusionGitLFSResponse::newErrorResponse(
400,
pht(
'Uploaded data is corrupt or invalid. Expected hash "%s", actual '.
'hash "%s".',
$oid,
$hash));
}
$ref = id(new PhabricatorRepositoryGitLFSRef())
->setRepositoryPHID($repository->getPHID())
->setObjectHash($hash)
->setByteSize($file->getByteSize())
->setAuthorPHID($viewer->getPHID())
->setFilePHID($file->getPHID());
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
// Attach the file to the repository to give users permission
// to access it.
$file->attachToObject($repository->getPHID());
$ref->save();
unset($unguarded);
// This is just a plain HTTP 200 with no content, which is what `git lfs`
// expects.
return new DiffusionGitLFSResponse();
}
private function newGitLFSHTTPAuthorization(
PhabricatorRepository $repository,
PhabricatorUser $viewer,
$operation) {
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
$authorization = DiffusionGitLFSTemporaryTokenType::newHTTPAuthorization(
$repository,
$viewer,
$operation);
unset($unguarded);
return $authorization;
}
private function getGitLFSRequestPath(PhabricatorRepository $repository) {
$request_path = $this->getRequestDirectoryPath($repository);
$matches = null;
if (preg_match('(^/info/lfs(?:\z|/)(.*))', $request_path, $matches)) {
return $matches[1];
}
return null;
}
} }

View file

@ -134,17 +134,24 @@ final class DiffusionSymbolController extends DiffusionController {
$table->setNoDataString( $table->setNoDataString(
pht('No matching symbol could be found in any indexed repository.')); pht('No matching symbol could be found in any indexed repository.'));
$panel = id(new PHUIObjectBoxView()) $header = id(new PHUIHeaderView())
->setHeaderText(pht('Similar Symbols')) ->setHeader(pht('Similar Symbols'))
->setTable($table); ->setHeaderIcon('fa-bullseye');
$crumbs = $this->buildApplicationCrumbs(); $crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Find Symbol')); $crumbs->addTextCrumb(pht('Find Symbol'));
$crumbs->setBorder(true);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter(array(
$table,
));
return $this->newPage() return $this->newPage()
->setTitle(pht('Find Symbol')) ->setTitle(pht('Find Symbol'))
->setCrumbs($crumbs) ->setCrumbs($crumbs)
->appendChild($panel); ->appendChild($view);
} }
} }

View file

@ -45,6 +45,11 @@ final class DiffusionTagListController extends DiffusionController {
$tags = $pager->sliceResults($tags); $tags = $pager->sliceResults($tags);
$content = null; $content = null;
$header = id(new PHUIHeaderView())
->setHeader(pht('Tags'))
->setHeaderIcon('fa-tags');
if (!$tags) { if (!$tags) {
$content = $this->renderStatusMessage( $content = $this->renderStatusMessage(
pht('No Tags'), pht('No Tags'),
@ -69,11 +74,7 @@ final class DiffusionTagListController extends DiffusionController {
$handles = $this->loadViewerHandles($phids); $handles = $this->loadViewerHandles($phids);
$view->setHandles($handles); $view->setHandles($handles);
$panel = id(new PHUIObjectBoxView()) $content = $view;
->setHeaderText(pht('Tags'))
->appendChild($view);
$content = $panel;
} }
$crumbs = $this->buildCrumbs( $crumbs = $this->buildCrumbs(
@ -81,9 +82,22 @@ final class DiffusionTagListController extends DiffusionController {
'tags' => true, 'tags' => true,
'commit' => $drequest->getSymbolicCommit(), 'commit' => $drequest->getSymbolicCommit(),
)); ));
$crumbs->setBorder(true);
$box = id(new PHUIObjectBoxView())
->setHeaderText($repository->getDisplayName())
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($view);
$pager_box = $this->renderTablePagerBox($pager); $pager_box = $this->renderTablePagerBox($pager);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter(array(
$box,
$pager_box,
));
return $this->newPage() return $this->newPage()
->setTitle( ->setTitle(
array( array(
@ -91,11 +105,7 @@ final class DiffusionTagListController extends DiffusionController {
$repository->getDisplayName(), $repository->getDisplayName(),
)) ))
->setCrumbs($crumbs) ->setCrumbs($crumbs)
->appendChild( ->appendChild($view);
array(
$content,
$pager_box,
));
} }
} }

View file

@ -0,0 +1,108 @@
<?php
final class DiffusionGitLFSAuthenticateWorkflow
extends DiffusionGitSSHWorkflow {
protected function didConstruct() {
$this->setName('git-lfs-authenticate');
$this->setArguments(
array(
array(
'name' => 'argv',
'wildcard' => true,
),
));
}
protected function identifyRepository() {
return $this->loadRepositoryWithPath($this->getLFSPathArgument());
}
private function getLFSPathArgument() {
return $this->getLFSArgument(0);
}
private function getLFSOperationArgument() {
return $this->getLFSArgument(1);
}
private function getLFSArgument($position) {
$args = $this->getArgs();
$argv = $args->getArg('argv');
if (!isset($argv[$position])) {
throw new Exception(
pht(
'Expected `git-lfs-authenticate <path> <operation>`, but received '.
'too few arguments.'));
}
return $argv[$position];
}
protected function executeRepositoryOperations() {
$operation = $this->getLFSOperationArgument();
// NOTE: We aren't checking write access here, even for "upload". The
// HTTP endpoint should be able to do that for us.
switch ($operation) {
case 'upload':
case 'download':
break;
default:
throw new Exception(
pht(
'Git LFS operation "%s" is not supported by this server.',
$operation));
}
$repository = $this->getRepository();
if (!$repository->isGit()) {
throw new Exception(
pht(
'Repository "%s" is not a Git repository. Git LFS is only '.
'supported for Git repositories.',
$repository->getDisplayName()));
}
if (!$repository->canUseGitLFS()) {
throw new Exception(
pht('Git LFS is not enabled for this repository.'));
}
// NOTE: This is usually the same as the default URI (which does not
// need to be specified in the response), but the protocol or domain may
// differ in some situations.
$lfs_uri = $repository->getGitLFSURI('info/lfs');
// Generate a temporary token to allow the user to acces LFS over HTTP.
// This works even if normal HTTP repository operations are not available
// on this host, and does not require the user to have a VCS password.
$user = $this->getUser();
$authorization = DiffusionGitLFSTemporaryTokenType::newHTTPAuthorization(
$repository,
$user,
$operation);
$headers = array(
'authorization' => $authorization,
);
$result = array(
'header' => $headers,
'href' => $lfs_uri,
);
$result = phutil_json_encode($result);
$this->writeIO($result);
$this->waitForGitClient();
return 0;
}
}

View file

@ -0,0 +1,42 @@
<?php
final class DiffusionGitLFSTemporaryTokenType
extends PhabricatorAuthTemporaryTokenType {
const TOKENTYPE = 'diffusion.git.lfs';
const HTTP_USERNAME = '@git-lfs';
public function getTokenTypeDisplayName() {
return pht('Git Large File Storage');
}
public function getTokenReadableTypeName(
PhabricatorAuthTemporaryToken $token) {
return pht('Git LFS Token');
}
public static function newHTTPAuthorization(
PhabricatorRepository $repository,
PhabricatorUser $viewer,
$operation) {
$lfs_user = self::HTTP_USERNAME;
$lfs_pass = Filesystem::readRandomCharacters(32);
$lfs_hash = PhabricatorHash::digest($lfs_pass);
$ttl = PhabricatorTime::getNow() + phutil_units('1 day in seconds');
$token = id(new PhabricatorAuthTemporaryToken())
->setTokenResource($repository->getPHID())
->setTokenType(self::TOKENTYPE)
->setTokenCode($lfs_hash)
->setUserPHID($viewer->getPHID())
->setTemporaryTokenProperty('lfs.operation', $operation)
->setTokenExpires($ttl)
->save();
$authorization_header = base64_encode($lfs_user.':'.$lfs_pass);
return 'Basic '.$authorization_header;
}
}

View file

@ -0,0 +1,37 @@
<?php
final class DiffusionGitLFSResponse extends AphrontResponse {
private $content;
public static function newErrorResponse($code, $message) {
// We can optionally include "request_id" and "documentation_url" in
// this response.
return id(new self())
->setHTTPResponseCode($code)
->setContent(
array(
'message' => $message,
));
}
public function setContent(array $content) {
$this->content = phutil_json_encode($content);
return $this;
}
public function buildResponseString() {
return $this->content;
}
public function getHeaders() {
$headers = array(
array('Content-Type', 'application/vnd.git-lfs+json'),
);
return array_merge(parent::getHeaders(), $headers);
}
}

View file

@ -39,7 +39,7 @@ final class DiffusionBranchTableView extends DiffusionView {
$commit = idx($commits, $branch->getCommitIdentifier()); $commit = idx($commits, $branch->getCommitIdentifier());
if ($commit) { if ($commit) {
$details = $commit->getSummary(); $details = $commit->getSummary();
$datetime = phabricator_datetime($commit->getEpoch(), $viewer); $datetime = $viewer->formatShortDateTime($commit->getEpoch());
$buildable = idx($buildables, $commit->getPHID()); $buildable = idx($buildables, $commit->getPHID());
if ($buildable) { if ($buildable) {
$build_status = $this->renderBuildable($buildable); $build_status = $this->renderBuildable($buildable);
@ -147,7 +147,7 @@ final class DiffusionBranchTableView extends DiffusionView {
'', '',
'wide', 'wide',
'', '',
'', 'right',
)); ));
$view->setColumnVisibility( $view->setColumnVisibility(
array( array(

View file

@ -90,7 +90,6 @@ final class DiffusionBrowseTableView extends DiffusionView {
$browse_link, $browse_link,
idx($dict, 'lint'), idx($dict, 'lint'),
$dict['commit'], $dict['commit'],
$dict['author'],
$dict['details'], $dict['details'],
$dict['date'], $dict['date'],
); );
@ -120,7 +119,6 @@ final class DiffusionBrowseTableView extends DiffusionView {
pht('Path'), pht('Path'),
($lint ? $lint : pht('Lint')), ($lint ? $lint : pht('Lint')),
pht('Modified'), pht('Modified'),
pht('Author/Committer'),
pht('Details'), pht('Details'),
pht('Committed'), pht('Committed'),
)); ));
@ -130,9 +128,8 @@ final class DiffusionBrowseTableView extends DiffusionView {
'', '',
'', '',
'', '',
'',
'wide', 'wide',
'', 'right',
)); ));
$view->setColumnVisibility( $view->setColumnVisibility(
array( array(
@ -142,7 +139,6 @@ final class DiffusionBrowseTableView extends DiffusionView {
true, true,
true, true,
true, true,
true,
)); ));
$view->setDeviceVisibility( $view->setDeviceVisibility(
@ -150,7 +146,6 @@ final class DiffusionBrowseTableView extends DiffusionView {
true, true,
true, true,
false, false,
true,
false, false,
true, true,
false, false,

View file

@ -95,7 +95,7 @@ final class DiffusionHistoryTableView extends DiffusionView {
$epoch = $history->getEpoch(); $epoch = $history->getEpoch();
if ($epoch) { if ($epoch) {
$committed = phabricator_datetime($epoch, $viewer); $committed = $viewer->formatShortDateTime($epoch);
} else { } else {
$committed = null; $committed = null;
} }
@ -195,7 +195,7 @@ final class DiffusionHistoryTableView extends DiffusionView {
'', '',
'', '',
'wide', 'wide',
'', 'right',
)); ));
$view->setColumnVisibility( $view->setColumnVisibility(
array( array(

View file

@ -88,7 +88,7 @@ final class DiffusionPushLogListView extends AphrontView {
// TODO: Make these human-readable. // TODO: Make these human-readable.
$log->getChangeFlags(), $log->getChangeFlags(),
$log->getPushEvent()->getRejectCode(), $log->getPushEvent()->getRejectCode(),
phabricator_datetime($log->getEpoch(), $viewer), $viewer->formatShortDateTime($log->getEpoch()),
); );
} }
@ -119,7 +119,7 @@ final class DiffusionPushLogListView extends AphrontView {
'wide', 'wide',
'n', 'n',
'n', 'n',
'date', 'right',
)); ));
return $table; return $table;

View file

@ -28,6 +28,7 @@ final class DiffusionTagListView extends DiffusionView {
public function render() { public function render() {
$drequest = $this->getDiffusionRequest(); $drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository(); $repository = $drequest->getRepository();
$viewer = $this->getViewer();
$buildables = $this->loadBuildables($this->commits); $buildables = $this->loadBuildables($this->commits);
$has_builds = false; $has_builds = false;
@ -100,7 +101,7 @@ final class DiffusionTagListView extends DiffusionView {
$build, $build,
$author, $author,
$description, $description,
phabricator_datetime($tag->getEpoch(), $this->getViewer()), $viewer->formatShortDateTime($tag->getEpoch()),
); );
} }
@ -123,6 +124,7 @@ final class DiffusionTagListView extends DiffusionView {
'', '',
'', '',
'wide', 'wide',
'right',
)) ))
->setColumnVisibility( ->setColumnVisibility(
array( array(

View file

@ -95,7 +95,9 @@ abstract class DiffusionView extends AphrontView {
} }
$icon = DifferentialChangeType::getIconForFileType($file_type); $icon = DifferentialChangeType::getIconForFileType($file_type);
$icon_view = id(new PHUIIconView())->setIcon($icon); $color = DifferentialChangeType::getIconColorForFileType($file_type);
$icon_view = id(new PHUIIconView())
->setIcon($icon.' '.$color);
// If we're rendering a file or directory name, don't show the tooltip. // If we're rendering a file or directory name, don't show the tooltip.
if ($display_name !== null) { if ($display_name !== null) {

View file

@ -26,16 +26,14 @@ final class DrydockAuthorizationViewController
->setUser($viewer) ->setUser($viewer)
->setPolicyObject($authorization); ->setPolicyObject($authorization);
$state = $authorization->getBlueprintAuthorizationState(); $state = $authorization->getBlueprintAuthorizationState();
$icon = DrydockAuthorization::getBlueprintStateIcon($state); $icon = DrydockAuthorization::getBlueprintStateIcon($state);
$name = DrydockAuthorization::getBlueprintStateName($state); $name = DrydockAuthorization::getBlueprintStateName($state);
$header->setStatus($icon, null, $name); $header->setStatus($icon, null, $name);
$actions = $this->buildActionListView($authorization); $curtain = $this->buildCurtain($authorization);
$properties = $this->buildPropertyListView($authorization); $properties = $this->buildPropertyListView($authorization);
$properties->setActionList($actions);
$crumbs = $this->buildApplicationCrumbs(); $crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb( $crumbs->addTextCrumb(
@ -45,29 +43,32 @@ final class DrydockAuthorizationViewController
$blueprint->getBlueprintName(), $blueprint->getBlueprintName(),
$this->getApplicationURI("blueprint/{$blueprint_id}/")); $this->getApplicationURI("blueprint/{$blueprint_id}/"));
$crumbs->addTextCrumb($title); $crumbs->addTextCrumb($title);
$crumbs->setBorder(true);
$object_box = id(new PHUIObjectBoxView()) $object_box = id(new PHUIObjectBoxView())
->setHeader($header) ->setHeader($header)
->addPropertyList($properties); ->addPropertyList($properties);
return $this->buildApplicationPage( $view = id(new PHUITwoColumnView())
->setHeader($header)
->setCurtain($curtain)
->addPropertySection(pht('Properties'), $properties);
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
->appendChild(
array( array(
$crumbs, $view,
$object_box,
),
array(
'title' => $title,
)); ));
} }
private function buildActionListView(DrydockAuthorization $authorization) { private function buildCurtain(DrydockAuthorization $authorization) {
$viewer = $this->getViewer(); $viewer = $this->getViewer();
$id = $authorization->getID(); $id = $authorization->getID();
$view = id(new PhabricatorActionListView()) $curtain = $this->newCurtainView($authorization);
->setUser($viewer)
->setObject($authorization);
$can_edit = PhabricatorPolicyFilter::hasCapability( $can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer, $viewer,
@ -84,7 +85,7 @@ final class DrydockAuthorizationViewController
$can_authorize = $can_edit && ($state != $state_authorized); $can_authorize = $can_edit && ($state != $state_authorized);
$can_decline = $can_edit && ($state != $state_declined); $can_decline = $can_edit && ($state != $state_declined);
$view->addAction( $curtain->addAction(
id(new PhabricatorActionView()) id(new PhabricatorActionView())
->setHref($authorize_uri) ->setHref($authorize_uri)
->setName(pht('Approve Authorization')) ->setName(pht('Approve Authorization'))
@ -92,7 +93,7 @@ final class DrydockAuthorizationViewController
->setWorkflow(true) ->setWorkflow(true)
->setDisabled(!$can_authorize)); ->setDisabled(!$can_authorize));
$view->addAction( $curtain->addAction(
id(new PhabricatorActionView()) id(new PhabricatorActionView())
->setHref($decline_uri) ->setHref($decline_uri)
->setName(pht('Decline Authorization')) ->setName(pht('Decline Authorization'))
@ -100,7 +101,7 @@ final class DrydockAuthorizationViewController
->setWorkflow(true) ->setWorkflow(true)
->setDisabled(!$can_decline)); ->setDisabled(!$can_decline));
return $view; return $curtain;
} }
private function buildPropertyListView(DrydockAuthorization $authorization) { private function buildPropertyListView(DrydockAuthorization $authorization) {

View file

@ -19,7 +19,8 @@ final class DrydockBlueprintViewController extends DrydockBlueprintController {
$header = id(new PHUIHeaderView()) $header = id(new PHUIHeaderView())
->setHeader($title) ->setHeader($title)
->setUser($viewer) ->setUser($viewer)
->setPolicyObject($blueprint); ->setPolicyObject($blueprint)
->setHeaderIcon('fa-map-o');
if ($blueprint->getIsDisabled()) { if ($blueprint->getIsDisabled()) {
$header->setStatus('fa-ban', 'red', pht('Disabled')); $header->setStatus('fa-ban', 'red', pht('Disabled'));
@ -27,15 +28,12 @@ final class DrydockBlueprintViewController extends DrydockBlueprintController {
$header->setStatus('fa-check', 'bluegrey', pht('Active')); $header->setStatus('fa-check', 'bluegrey', pht('Active'));
} }
$actions = $this->buildActionListView($blueprint); $curtain = $this->buildCurtain($blueprint);
$properties = $this->buildPropertyListView($blueprint, $actions); $properties = $this->buildPropertyListView($blueprint);
$crumbs = $this->buildApplicationCrumbs(); $crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Blueprint %d', $blueprint->getID())); $crumbs->addTextCrumb(pht('Blueprint %d', $blueprint->getID()));
$crumbs->setBorder(true);
$object_box = id(new PHUIObjectBoxView())
->setHeader($header)
->addPropertyList($properties);
$field_list = PhabricatorCustomField::getObjectFields( $field_list = PhabricatorCustomField::getObjectFields(
$blueprint, $blueprint,
@ -49,9 +47,8 @@ final class DrydockBlueprintViewController extends DrydockBlueprintController {
$viewer, $viewer,
$properties); $properties);
$resource_box = $this->buildResourceBox($blueprint); $resources = $this->buildResourceBox($blueprint);
$authorizations = $this->buildAuthorizationsBox($blueprint);
$authorizations_box = $this->buildAuthorizationsBox($blueprint);
$timeline = $this->buildTransactionTimeline( $timeline = $this->buildTransactionTimeline(
$blueprint, $blueprint,
@ -61,33 +58,36 @@ final class DrydockBlueprintViewController extends DrydockBlueprintController {
$log_query = id(new DrydockLogQuery()) $log_query = id(new DrydockLogQuery())
->withBlueprintPHIDs(array($blueprint->getPHID())); ->withBlueprintPHIDs(array($blueprint->getPHID()));
$log_box = $this->buildLogBox( $logs = $this->buildLogBox(
$log_query, $log_query,
$this->getApplicationURI("blueprint/{$id}/logs/query/all/")); $this->getApplicationURI("blueprint/{$id}/logs/query/all/"));
return $this->buildApplicationPage( $view = id(new PHUITwoColumnView())
array( ->setHeader($header)
$crumbs, ->setCurtain($curtain)
$object_box, ->addPropertySection(pht('Properties'), $properties)
$resource_box, ->setMainColumn(array(
$authorizations_box, $resources,
$log_box, $authorizations,
$logs,
$timeline, $timeline,
), ));
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
->appendChild(
array( array(
'title' => $title, $view,
)); ));
} }
private function buildActionListView(DrydockBlueprint $blueprint) { private function buildCurtain(DrydockBlueprint $blueprint) {
$viewer = $this->getViewer(); $viewer = $this->getViewer();
$id = $blueprint->getID(); $id = $blueprint->getID();
$view = id(new PhabricatorActionListView()) $curtain = $this->newCurtainView($blueprint);
->setUser($viewer)
->setObject($blueprint);
$edit_uri = $this->getApplicationURI("blueprint/edit/{$id}/"); $edit_uri = $this->getApplicationURI("blueprint/edit/{$id}/");
$can_edit = PhabricatorPolicyFilter::hasCapability( $can_edit = PhabricatorPolicyFilter::hasCapability(
@ -95,7 +95,7 @@ final class DrydockBlueprintViewController extends DrydockBlueprintController {
$blueprint, $blueprint,
PhabricatorPolicyCapability::CAN_EDIT); PhabricatorPolicyCapability::CAN_EDIT);
$view->addAction( $curtain->addAction(
id(new PhabricatorActionView()) id(new PhabricatorActionView())
->setHref($edit_uri) ->setHref($edit_uri)
->setName(pht('Edit Blueprint')) ->setName(pht('Edit Blueprint'))
@ -113,7 +113,7 @@ final class DrydockBlueprintViewController extends DrydockBlueprintController {
$disable_uri = $this->getApplicationURI("blueprint/{$id}/enable/"); $disable_uri = $this->getApplicationURI("blueprint/{$id}/enable/");
} }
$view->addAction( $curtain->addAction(
id(new PhabricatorActionView()) id(new PhabricatorActionView())
->setHref($disable_uri) ->setHref($disable_uri)
->setName($disable_name) ->setName($disable_name)
@ -121,19 +121,15 @@ final class DrydockBlueprintViewController extends DrydockBlueprintController {
->setWorkflow(true) ->setWorkflow(true)
->setDisabled(!$can_edit)); ->setDisabled(!$can_edit));
return $view; return $curtain;
} }
private function buildPropertyListView( private function buildPropertyListView(
DrydockBlueprint $blueprint, DrydockBlueprint $blueprint) {
PhabricatorActionListView $actions) {
$viewer = $this->getViewer(); $viewer = $this->getViewer();
$view = id(new PHUIPropertyListView()) $view = id(new PHUIPropertyListView())
->setUser($viewer) ->setUser($viewer);
->setObject($blueprint);
$view->setActionList($actions);
$view->addProperty( $view->addProperty(
pht('Type'), pht('Type'),
@ -177,6 +173,7 @@ final class DrydockBlueprintViewController extends DrydockBlueprintController {
return id(new PHUIObjectBoxView()) return id(new PHUIObjectBoxView())
->setHeader($resource_header) ->setHeader($resource_header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setObjectList($resource_list); ->setObjectList($resource_list);
} }
@ -242,6 +239,7 @@ final class DrydockBlueprintViewController extends DrydockBlueprintController {
return id(new PHUIObjectBoxView()) return id(new PHUIObjectBoxView())
->setHeader($authorizations_header) ->setHeader($authorizations_header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setObjectList($authorization_list); ->setObjectList($authorization_list);
} }

View file

@ -102,6 +102,7 @@ abstract class DrydockController extends PhabricatorController {
->setText(pht('View All'))); ->setText(pht('View All')));
return id(new PHUIObjectBoxView()) return id(new PHUIObjectBoxView())
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setHeader($log_header) ->setHeader($log_header)
->setTable($log_table); ->setTable($log_table);
} }

View file

@ -21,53 +21,59 @@ final class DrydockLeaseViewController extends DrydockLeaseController {
$title = pht('Lease %d', $lease->getID()); $title = pht('Lease %d', $lease->getID());
$header = id(new PHUIHeaderView()) $header = id(new PHUIHeaderView())
->setHeader($title); ->setHeader($title)
->setHeaderIcon('fa-link');
if ($lease->isReleasing()) { if ($lease->isReleasing()) {
$header->setStatus('fa-exclamation-triangle', 'red', pht('Releasing')); $header->setStatus('fa-exclamation-triangle', 'red', pht('Releasing'));
} }
$actions = $this->buildActionListView($lease); $curtain = $this->buildCurtain($lease);
$properties = $this->buildPropertyListView($lease, $actions); $properties = $this->buildPropertyListView($lease);
$log_query = id(new DrydockLogQuery()) $log_query = id(new DrydockLogQuery())
->withLeasePHIDs(array($lease->getPHID())); ->withLeasePHIDs(array($lease->getPHID()));
$log_box = $this->buildLogBox( $logs = $this->buildLogBox(
$log_query, $log_query,
$this->getApplicationURI("lease/{$id}/logs/query/all/")); $this->getApplicationURI("lease/{$id}/logs/query/all/"));
$crumbs = $this->buildApplicationCrumbs(); $crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb($title, $lease_uri); $crumbs->addTextCrumb($title, $lease_uri);
$crumbs->setBorder(true);
$locks = $this->buildLocksTab($lease->getPHID()); $locks = $this->buildLocksTab($lease->getPHID());
$commands = $this->buildCommandsTab($lease->getPHID()); $commands = $this->buildCommandsTab($lease->getPHID());
$object_box = id(new PHUIObjectBoxView()) $object_box = id(new PHUIObjectBoxView())
->setHeader($header) ->setHeaderText(pht('Properties'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($properties, pht('Properties')) ->addPropertyList($properties, pht('Properties'))
->addPropertyList($locks, pht('Slot Locks')) ->addPropertyList($locks, pht('Slot Locks'))
->addPropertyList($commands, pht('Commands')); ->addPropertyList($commands, pht('Commands'));
return $this->buildApplicationPage( $view = id(new PHUITwoColumnView())
array( ->setHeader($header)
$crumbs, ->setCurtain($curtain)
->setMainColumn(array(
$object_box, $object_box,
$log_box, $logs,
), ));
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
->appendChild(
array( array(
'title' => $title, $view,
)); ));
} }
private function buildActionListView(DrydockLease $lease) { private function buildCurtain(DrydockLease $lease) {
$viewer = $this->getViewer(); $viewer = $this->getViewer();
$view = id(new PhabricatorActionListView()) $curtain = $this->newCurtainView($lease);
->setUser($viewer)
->setObject($lease);
$id = $lease->getID(); $id = $lease->getID();
$can_release = $lease->canRelease(); $can_release = $lease->canRelease();
@ -80,7 +86,7 @@ final class DrydockLeaseViewController extends DrydockLeaseController {
$lease, $lease,
PhabricatorPolicyCapability::CAN_EDIT); PhabricatorPolicyCapability::CAN_EDIT);
$view->addAction( $curtain->addAction(
id(new PhabricatorActionView()) id(new PhabricatorActionView())
->setName(pht('Release Lease')) ->setName(pht('Release Lease'))
->setIcon('fa-times') ->setIcon('fa-times')
@ -88,16 +94,14 @@ final class DrydockLeaseViewController extends DrydockLeaseController {
->setWorkflow(true) ->setWorkflow(true)
->setDisabled(!$can_release || !$can_edit)); ->setDisabled(!$can_release || !$can_edit));
return $view; return $curtain;
} }
private function buildPropertyListView( private function buildPropertyListView(
DrydockLease $lease, DrydockLease $lease) {
PhabricatorActionListView $actions) {
$viewer = $this->getViewer(); $viewer = $this->getViewer();
$view = new PHUIPropertyListView(); $view = new PHUIPropertyListView();
$view->setActionList($actions);
$view->addProperty( $view->addProperty(
pht('Status'), pht('Status'),

View file

@ -25,50 +25,52 @@ final class DrydockRepositoryOperationViewController
$header = id(new PHUIHeaderView()) $header = id(new PHUIHeaderView())
->setHeader($title) ->setHeader($title)
->setUser($viewer) ->setUser($viewer)
->setPolicyObject($operation); ->setPolicyObject($operation)
->setHeaderIcon('fa-fighter-jet');
$state = $operation->getOperationState(); $state = $operation->getOperationState();
$icon = DrydockRepositoryOperation::getOperationStateIcon($state); $icon = DrydockRepositoryOperation::getOperationStateIcon($state);
$name = DrydockRepositoryOperation::getOperationStateName($state); $name = DrydockRepositoryOperation::getOperationStateName($state);
$header->setStatus($icon, null, $name); $header->setStatus($icon, null, $name);
$actions = $this->buildActionListView($operation); $curtain = $this->buildCurtain($operation);
$properties = $this->buildPropertyListView($operation); $properties = $this->buildPropertyListView($operation);
$properties->setActionList($actions);
$crumbs = $this->buildApplicationCrumbs(); $crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb( $crumbs->addTextCrumb(
pht('Operations'), pht('Operations'),
$this->getApplicationURI('operation/')); $this->getApplicationURI('operation/'));
$crumbs->addTextCrumb($title); $crumbs->addTextCrumb($title);
$crumbs->setBorder(true);
$object_box = id(new PHUIObjectBoxView())
->setHeader($header)
->addPropertyList($properties);
$status_view = id(new DrydockRepositoryOperationStatusView()) $status_view = id(new DrydockRepositoryOperationStatusView())
->setUser($viewer) ->setUser($viewer)
->setOperation($operation); ->setOperation($operation);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setCurtain($curtain)
->addPropertySection(pht('Properties'), $properties)
->setMainColumn(array(
$status_view,
));
return $this->newPage() return $this->newPage()
->setTitle($title) ->setTitle($title)
->setCrumbs($crumbs) ->setCrumbs($crumbs)
->appendChild( ->appendChild(
array( array(
$object_box, $view,
$status_view,
)); ));
} }
private function buildActionListView(DrydockRepositoryOperation $operation) { private function buildCurtain(DrydockRepositoryOperation $operation) {
$viewer = $this->getViewer(); $viewer = $this->getViewer();
$id = $operation->getID(); $id = $operation->getID();
$view = id(new PhabricatorActionListView()) $curtain = $this->newCurtainView($operation);
->setUser($viewer)
->setObject($operation);
return $view; return $curtain;
} }
private function buildPropertyListView( private function buildPropertyListView(

View file

@ -23,14 +23,15 @@ final class DrydockResourceViewController extends DrydockResourceController {
$header = id(new PHUIHeaderView()) $header = id(new PHUIHeaderView())
->setUser($viewer) ->setUser($viewer)
->setPolicyObject($resource) ->setPolicyObject($resource)
->setHeader($title); ->setHeader($title)
->setHeaderIcon('fa-map');
if ($resource->isReleasing()) { if ($resource->isReleasing()) {
$header->setStatus('fa-exclamation-triangle', 'red', pht('Releasing')); $header->setStatus('fa-exclamation-triangle', 'red', pht('Releasing'));
} }
$actions = $this->buildActionListView($resource); $curtain = $this->buildCurtain($resource);
$properties = $this->buildPropertyListView($resource, $actions); $properties = $this->buildPropertyListView($resource);
$id = $resource->getID(); $id = $resource->getID();
$resource_uri = $this->getApplicationURI("resource/{$id}/"); $resource_uri = $this->getApplicationURI("resource/{$id}/");
@ -44,37 +45,42 @@ final class DrydockResourceViewController extends DrydockResourceController {
$crumbs = $this->buildApplicationCrumbs(); $crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Resource %d', $resource->getID())); $crumbs->addTextCrumb(pht('Resource %d', $resource->getID()));
$crumbs->setBorder(true);
$locks = $this->buildLocksTab($resource->getPHID()); $locks = $this->buildLocksTab($resource->getPHID());
$commands = $this->buildCommandsTab($resource->getPHID()); $commands = $this->buildCommandsTab($resource->getPHID());
$lease_box = $this->buildLeaseBox($resource);
$object_box = id(new PHUIObjectBoxView()) $object_box = id(new PHUIObjectBoxView())
->setHeader($header) ->setHeaderText(pht('Properties'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($properties, pht('Properties')) ->addPropertyList($properties, pht('Properties'))
->addPropertyList($locks, pht('Slot Locks')) ->addPropertyList($locks, pht('Slot Locks'))
->addPropertyList($commands, pht('Commands')); ->addPropertyList($commands, pht('Commands'));
$lease_box = $this->buildLeaseBox($resource); $view = id(new PHUITwoColumnView())
->setHeader($header)
return $this->buildApplicationPage( ->setCurtain($curtain)
array( ->setMainColumn(array(
$crumbs,
$object_box, $object_box,
$lease_box, $lease_box,
$log_box, $log_box,
), ));
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
->appendChild(
array( array(
'title' => $title, $view,
)); ));
} }
private function buildActionListView(DrydockResource $resource) { private function buildCurtain(DrydockResource $resource) {
$viewer = $this->getViewer(); $viewer = $this->getViewer();
$view = id(new PhabricatorActionListView()) $curtain = $this->newCurtainView($resource);
->setUser($viewer)
->setObject($resource);
$can_release = $resource->canRelease(); $can_release = $resource->canRelease();
if ($resource->isReleasing()) { if ($resource->isReleasing()) {
@ -89,7 +95,7 @@ final class DrydockResourceViewController extends DrydockResourceController {
$uri = '/resource/'.$resource->getID().'/release/'; $uri = '/resource/'.$resource->getID().'/release/';
$uri = $this->getApplicationURI($uri); $uri = $this->getApplicationURI($uri);
$view->addAction( $curtain->addAction(
id(new PhabricatorActionView()) id(new PhabricatorActionView())
->setHref($uri) ->setHref($uri)
->setName(pht('Release Resource')) ->setName(pht('Release Resource'))
@ -97,17 +103,14 @@ final class DrydockResourceViewController extends DrydockResourceController {
->setWorkflow(true) ->setWorkflow(true)
->setDisabled(!$can_release || !$can_edit)); ->setDisabled(!$can_release || !$can_edit));
return $view; return $curtain;
} }
private function buildPropertyListView( private function buildPropertyListView(
DrydockResource $resource, DrydockResource $resource) {
PhabricatorActionListView $actions) {
$viewer = $this->getViewer(); $viewer = $this->getViewer();
$view = id(new PHUIPropertyListView()) $view = new PHUIPropertyListView();
->setActionList($actions);
$status = $resource->getStatus(); $status = $resource->getStatus();
$status = DrydockResourceStatus::getNameForStatus($status); $status = DrydockResourceStatus::getNameForStatus($status);
@ -179,6 +182,7 @@ final class DrydockResourceViewController extends DrydockResourceController {
return id(new PHUIObjectBoxView()) return id(new PHUIObjectBoxView())
->setHeader($lease_header) ->setHeader($lease_header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setObjectList($lease_list); ->setObjectList($lease_list);
} }

View file

@ -48,6 +48,7 @@ final class DrydockRepositoryOperationStatusView
$box_view = $this->getBoxView(); $box_view = $this->getBoxView();
if (!$box_view) { if (!$box_view) {
$box_view = id(new PHUIObjectBoxView()) $box_view = id(new PHUIObjectBoxView())
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setHeaderText(pht('Operation Status')); ->setHeaderText(pht('Operation Status'));
} }
$box_view->setObjectList($list); $box_view->setObjectList($list);

View file

@ -26,7 +26,6 @@ final class PhabricatorFile extends PhabricatorFileDAO
PhabricatorPolicyInterface, PhabricatorPolicyInterface,
PhabricatorDestructibleInterface { PhabricatorDestructibleInterface {
const ONETIME_TEMPORARY_TOKEN_TYPE = 'file:onetime';
const STORAGE_FORMAT_RAW = 'raw'; const STORAGE_FORMAT_RAW = 'raw';
const METADATA_IMAGE_WIDTH = 'width'; const METADATA_IMAGE_WIDTH = 'width';
@ -1119,12 +1118,13 @@ final class PhabricatorFile extends PhabricatorFileDAO
protected function generateOneTimeToken() { protected function generateOneTimeToken() {
$key = Filesystem::readRandomCharacters(16); $key = Filesystem::readRandomCharacters(16);
$token_type = PhabricatorFileAccessTemporaryTokenType::TOKENTYPE;
// Save the new secret. // Save the new secret.
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
$token = id(new PhabricatorAuthTemporaryToken()) $token = id(new PhabricatorAuthTemporaryToken())
->setObjectPHID($this->getPHID()) ->setTokenResource($this->getPHID())
->setTokenType(self::ONETIME_TEMPORARY_TOKEN_TYPE) ->setTokenType($token_type)
->setTokenExpires(time() + phutil_units('1 hour in seconds')) ->setTokenExpires(time() + phutil_units('1 hour in seconds'))
->setTokenCode(PhabricatorHash::digest($key)) ->setTokenCode(PhabricatorHash::digest($key))
->save(); ->save();
@ -1134,10 +1134,12 @@ final class PhabricatorFile extends PhabricatorFileDAO
} }
public function validateOneTimeToken($token_code) { public function validateOneTimeToken($token_code) {
$token_type = PhabricatorFileAccessTemporaryTokenType::TOKENTYPE;
$token = id(new PhabricatorAuthTemporaryTokenQuery()) $token = id(new PhabricatorAuthTemporaryTokenQuery())
->setViewer(PhabricatorUser::getOmnipotentUser()) ->setViewer(PhabricatorUser::getOmnipotentUser())
->withObjectPHIDs(array($this->getPHID())) ->withTokenResources(array($this->getPHID()))
->withTokenTypes(array(self::ONETIME_TEMPORARY_TOKEN_TYPE)) ->withTokenTypes(array($token_type))
->withExpired(false) ->withExpired(false)
->withTokenCodes(array(PhabricatorHash::digest($token_code))) ->withTokenCodes(array(PhabricatorHash::digest($token_code)))
->executeOne(); ->executeOne();

View file

@ -0,0 +1,17 @@
<?php
final class PhabricatorFileAccessTemporaryTokenType
extends PhabricatorAuthTemporaryTokenType {
const TOKENTYPE = 'file:onetime';
public function getTokenTypeDisplayName() {
return pht('File Access');
}
public function getTokenReadableTypeName(
PhabricatorAuthTemporaryToken $token) {
return pht('File Access Token');
}
}

View file

@ -72,8 +72,10 @@ abstract class PhabricatorFileUploadSource
$data->rewind(); $data->rewind();
$this->didRewind = true; $this->didRewind = true;
} else { } else {
if ($data->valid()) {
$data->next(); $data->next();
} }
}
if (!$data->valid()) { if (!$data->valid()) {
return false; return false;

View file

@ -0,0 +1,25 @@
<?php
final class PhabricatorIteratorFileUploadSource
extends PhabricatorFileUploadSource {
private $iterator;
public function setIterator(Iterator $iterator) {
$this->iterator = $iterator;
return $this;
}
public function getIterator() {
return $this->iterator;
}
protected function newDataIterator() {
return $this->getIterator();
}
protected function getDataLength() {
return null;
}
}

View file

@ -7,6 +7,7 @@ final class HarbormasterUnitSummaryView extends AphrontView {
private $limit; private $limit;
private $excuse; private $excuse;
private $showViewAll; private $showViewAll;
private $background;
public function setBuildable(HarbormasterBuildable $buildable) { public function setBuildable(HarbormasterBuildable $buildable) {
$this->buildable = $buildable; $this->buildable = $buildable;
@ -33,6 +34,11 @@ final class HarbormasterUnitSummaryView extends AphrontView {
return $this; return $this;
} }
public function setBackground($background) {
$this->background = $background;
return $this;
}
public function render() { public function render() {
$messages = $this->messages; $messages = $this->messages;
$buildable = $this->buildable; $buildable = $this->buildable;
@ -54,9 +60,14 @@ final class HarbormasterUnitSummaryView extends AphrontView {
$tag_icon = 'fa-ban'; $tag_icon = 'fa-ban';
} }
$tag = id(new PHUITagView())
->setType(PHUITagView::TYPE_SHADE)
->setShade($tag_color)
->setIcon($tag_icon)
->setName($tag_text);
$header = id(new PHUIHeaderView()) $header = id(new PHUIHeaderView())
->setHeader(pht('Unit Tests')) ->setHeader(array(pht('Unit Tests'), $tag));
->setStatus($tag_icon, $tag_color, $tag_text);
if ($this->showViewAll) { if ($this->showViewAll) {
$view_all = id(new PHUIButtonView()) $view_all = id(new PHUIButtonView())
@ -98,6 +109,10 @@ final class HarbormasterUnitSummaryView extends AphrontView {
$box->setTable($table); $box->setTable($table);
if ($this->background) {
$box->setBackground($this->background);
}
return $box; return $box;
} }

View file

@ -700,7 +700,7 @@ final class PhabricatorUserEditor extends PhabricatorEditor {
} }
} }
private function revokePasswordResetLinks(PhabricatorUser $user) { public function revokePasswordResetLinks(PhabricatorUser $user) {
// Revoke any outstanding password reset links. If an attacker compromises // Revoke any outstanding password reset links. If an attacker compromises
// an account, changes the email address, and sends themselves a password // an account, changes the email address, and sends themselves a password
// reset link, it could otherwise remain live for a short period of time // reset link, it could otherwise remain live for a short period of time
@ -710,8 +710,8 @@ final class PhabricatorUserEditor extends PhabricatorEditor {
$user, $user,
array($user->getPHID()), array($user->getPHID()),
array( array(
PhabricatorAuthSessionEngine::ONETIME_TEMPORARY_TOKEN_TYPE, PhabricatorAuthOneTimeLoginTemporaryTokenType::TOKENTYPE,
PhabricatorAuthSessionEngine::PASSWORD_TEMPORARY_TOKEN_TYPE, PhabricatorAuthPasswordResetTemporaryTokenType::TOKENTYPE,
)); ));
} }

View file

@ -742,6 +742,38 @@ final class PhabricatorUser
return new DateTimeZone($this->getTimezoneIdentifier()); return new DateTimeZone($this->getTimezoneIdentifier());
} }
public function formatShortDateTime($when, $now = null) {
if ($now === null) {
$now = PhabricatorTime::getNow();
}
try {
$when = new DateTime('@'.$when);
$now = new DateTime('@'.$now);
} catch (Exception $ex) {
return null;
}
$zone = $this->getTimeZone();
$when->setTimeZone($zone);
$now->setTimeZone($zone);
if ($when->format('Y') !== $now->format('Y')) {
// Different year, so show "Feb 31 2075".
$format = 'M j Y';
} else if ($when->format('Ymd') !== $now->format('Ymd')) {
// Same year but different month and day, so show "Feb 31".
$format = 'M j';
} else {
// Same year, month and day so show a time of day.
$pref_time = PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT;
$format = $this->getPreference($pref_time);
}
return $when->format($format);
}
public function getPreference($key) { public function getPreference($key) {
$preferences = $this->loadPreferences(); $preferences = $this->loadPreferences();

View file

@ -0,0 +1,109 @@
<?php
final class PhabricatorHandleRemarkupRule extends PhutilRemarkupRule {
const KEY_RULE_HANDLE = 'rule.handle';
const KEY_RULE_HANDLE_ORIGINAL = 'rule.handle.original';
public function apply($text) {
return preg_replace_callback(
'/{(PHID-[a-zA-Z0-9-]*)}/',
array($this, 'markupHandle'),
$text);
}
public function markupHandle(array $matches) {
$engine = $this->getEngine();
$viewer = $engine->getConfig('viewer');
if (!$this->isFlatText($matches[0])) {
return $matches[0];
}
$phid_type = phid_get_type($matches[1]);
if ($phid_type == PhabricatorPHIDConstants::PHID_TYPE_UNKNOWN) {
return $matches[0];
}
$token = $engine->storeText($matches[0]);
if ($engine->isTextMode()) {
return $token;
}
$original_key = self::KEY_RULE_HANDLE_ORIGINAL;
$original = $engine->getTextMetadata($original_key, array());
$original[$token] = $matches[0];
$engine->setTextMetadata($original_key, $original);
$metadata_key = self::KEY_RULE_HANDLE;
$metadata = $engine->getTextMetadata($metadata_key, array());
$phid = $matches[1];
if (empty($metadata[$phid])) {
$metadata[$phid] = array();
}
$metadata[$phid][] = $token;
$engine->setTextMetadata($metadata_key, $metadata);
return $token;
}
public function didMarkupText() {
$engine = $this->getEngine();
$metadata_key = self::KEY_RULE_HANDLE;
$metadata = $engine->getTextMetadata($metadata_key, array());
if (empty($metadata)) {
// No mentions, or we already processed them.
return;
}
$original_key = self::KEY_RULE_HANDLE_ORIGINAL;
$original = $engine->getTextMetadata($original_key, array());
$phids = array_keys($metadata);
$handles = id(new PhabricatorHandleQuery())
->setViewer($this->getEngine()->getConfig('viewer'))
->withPHIDs($phids)
->execute();
foreach ($metadata as $phid => $tokens) {
$handle = idx($handles, $phid);
if ($handle->isComplete()) {
if ($engine->isHTMLMailMode()) {
$href = $handle->getURI();
$href = PhabricatorEnv::getProductionURI($href);
$link = phutil_tag(
'a',
array(
'href' => $href,
'style' => '
border-color: #f1f7ff;
color: #19558d;
background-color: #f1f7ff;
border: 1px solid transparent;
border-radius: 3px;
font-weight: bold;
padding: 0 4px;',
),
$handle->getLinkName());
} else {
$link = $handle->renderTag();
$link->setPHID($phid);
}
foreach ($tokens as $token) {
$engine->overwriteStoredText($token, $link);
}
} else {
foreach ($tokens as $token) {
$engine->overwriteStoredText($token, idx($original, $token));
}
}
}
$engine->setTextMetadata($metadata_key, array());
}
}

View file

@ -18,7 +18,9 @@ final class PhabricatorPhurlLinkRemarkupRule extends PhutilRemarkupRule {
public function markupLink(array $matches) { public function markupLink(array $matches) {
$engine = $this->getEngine(); $engine = $this->getEngine();
$viewer = $engine->getConfig('viewer'); $viewer = $engine->getConfig('viewer');
$text_mode = $engine->isTextMode(); $text_mode = $engine->isTextMode();
$html_mode = $engine->isHTMLMailMode();
if (!$this->isFlatText($matches[0])) { if (!$this->isFlatText($matches[0])) {
return $matches[0]; return $matches[0];
@ -28,46 +30,45 @@ final class PhabricatorPhurlLinkRemarkupRule extends PhutilRemarkupRule {
$monogram = null; $monogram = null;
$is_monogram = '/^U(?P<id>[1-9]\d*)/'; $is_monogram = '/^U(?P<id>[1-9]\d*)/';
$query = id(new PhabricatorPhurlURLQuery())
->setViewer($viewer);
if (preg_match($is_monogram, $ref, $monogram)) { if (preg_match($is_monogram, $ref, $monogram)) {
$phurls = id(new PhabricatorPhurlURLQuery()) $query->withIDs(array($monogram[1]));
->setViewer($viewer)
->withIDs(array($monogram[1]))
->execute();
} else if (ctype_digit($ref)) { } else if (ctype_digit($ref)) {
$phurls = id(new PhabricatorPhurlURLQuery()) $query->withIDs(array($ref));
->setViewer($viewer)
->withIDs(array($ref))
->execute();
} else { } else {
$phurls = id(new PhabricatorPhurlURLQuery()) $query->withAliases(array($ref));
->setViewer($viewer)
->withAliases(array($ref))
->execute();
} }
$phurl = head($phurls); $phurl = $query->executeOne();
if (!$phurl) {
return $matches[0];
}
$uri = $phurl->getRedirectURI();
$name = $phurl->getDisplayName();
if ($text_mode || $html_mode) {
$uri = PhabricatorEnv::getProductionURI($uri);
}
if ($phurl) {
if ($text_mode) { if ($text_mode) {
return $phurl->getDisplayName(). return pht(
' <'. '%s <%s>',
$phurl->getRedirectURI(). $name,
'>'; $uri);
} } else {
$link = phutil_tag( $link = phutil_tag(
'a', 'a',
array( array(
'href' => $phurl->getRedirectURI(), 'href' => $uri,
'target' => '_blank', 'target' => '_blank',
), ),
$phurl->getDisplayName()); $name);
}
return $this->getEngine()->storeText($link); return $this->getEngine()->storeText($link);
} else {
return $matches[0];
}
} }
} }

View file

@ -0,0 +1,64 @@
<?php
final class PhabricatorRepositoryGitLFSRefQuery
extends PhabricatorCursorPagedPolicyAwareQuery {
private $ids;
private $repositoryPHIDs;
private $objectHashes;
public function withIDs(array $ids) {
$this->ids = $ids;
return $this;
}
public function withRepositoryPHIDs(array $phids) {
$this->repositoryPHIDs = $phids;
return $this;
}
public function withObjectHashes(array $hashes) {
$this->objectHashes = $hashes;
return $this;
}
public function newResultObject() {
return new PhabricatorRepositoryGitLFSRef();
}
protected function loadPage() {
return $this->loadStandardPage($this->newResultObject());
}
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
$where = parent::buildWhereClauseParts($conn);
if ($this->ids !== null) {
$where[] = qsprintf(
$conn,
'id IN (%Ld)',
$this->ids);
}
if ($this->repositoryPHIDs !== null) {
$where[] = qsprintf(
$conn,
'repositoryPHID IN (%Ls)',
$this->repositoryPHIDs);
}
if ($this->objectHashes !== null) {
$where[] = qsprintf(
$conn,
'objectHash IN (%Ls)',
$this->objectHashes);
}
return $where;
}
public function getQueryApplicationClass() {
return 'PhabricatorDiffusionApplication';
}
}

View file

@ -1518,6 +1518,10 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
return null; return null;
} }
return $this->getRawHTTPCloneURIObject();
}
private function getRawHTTPCloneURIObject() {
$uri = PhabricatorEnv::getProductionURI($this->getURI()); $uri = PhabricatorEnv::getProductionURI($this->getURI());
$uri = new PhutilURI($uri); $uri = new PhutilURI($uri);
@ -1819,6 +1823,38 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
return !$this->isSVN(); return !$this->isSVN();
} }
public function canUseGitLFS() {
if (!$this->isGit()) {
return false;
}
if (!$this->isHosted()) {
return false;
}
// TODO: Unprototype this feature.
if (!PhabricatorEnv::getEnvConfig('phabricator.show-prototypes')) {
return false;
}
return true;
}
public function getGitLFSURI($path = null) {
if (!$this->canUseGitLFS()) {
throw new Exception(
pht(
'This repository does not support Git LFS, so Git LFS URIs can '.
'not be generated for it.'));
}
$uri = $this->getRawHTTPCloneURIObject();
$uri = (string)$uri;
$uri = $uri.'/'.$path;
return $uri;
}
public function canMirror() { public function canMirror() {
if ($this->isGit() || $this->isHg()) { if ($this->isGit() || $this->isHg()) {
return true; return true;
@ -2399,6 +2435,14 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
$engine->destroyObject($atom); $engine->destroyObject($atom);
} }
$lfs_refs = id(new PhabricatorRepositoryGitLFSRefQuery())
->setViewer($engine->getViewer())
->withRepositoryPHIDs(array($phid))
->execute();
foreach ($lfs_refs as $ref) {
$engine->destroyObject($ref);
}
$this->saveTransaction(); $this->saveTransaction();
} }

View file

@ -0,0 +1,72 @@
<?php
final class PhabricatorRepositoryGitLFSRef
extends PhabricatorRepositoryDAO
implements
PhabricatorPolicyInterface,
PhabricatorDestructibleInterface {
protected $repositoryPHID;
protected $objectHash;
protected $byteSize;
protected $authorPHID;
protected $filePHID;
protected function getConfiguration() {
return array(
self::CONFIG_COLUMN_SCHEMA => array(
'objectHash' => 'bytes64',
'byteSize' => 'uint64',
),
self::CONFIG_KEY_SCHEMA => array(
'key_hash' => array(
'columns' => array('repositoryPHID', 'objectHash'),
'unique' => true,
),
),
) + parent::getConfiguration();
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */
public function getCapabilities() {
return array(
PhabricatorPolicyCapability::CAN_VIEW,
);
}
public function getPolicy($capability) {
return PhabricatorPolicies::getMostOpenPolicy();
}
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
return false;
}
public function describeAutomaticCapability($capability) {
return null;
}
/* -( PhabricatorDestructibleInterface )----------------------------------- */
public function destroyObjectPermanently(
PhabricatorDestructionEngine $engine) {
$file_phid = $this->getFilePHID();
$file = id(new PhabricatorFileQuery())
->setViewer($engine->getViewer())
->withPHIDs(array($file_phid))
->executeOne();
if ($file) {
$engine->destroyObject($file);
}
$this->delete();
}
}

View file

@ -155,9 +155,6 @@ final class PhabricatorRepositorySchemaSpec
'repositoryID' => array( 'repositoryID' => array(
'columns' => array('repositoryID', 'pathID', 'commitSequence'), 'columns' => array('repositoryID', 'pathID', 'commitSequence'),
), ),
'key_history' => array(
'columns' => array('commitID', 'isDirect', 'changeType'),
),
)); ));
$this->buildRawSchema( $this->buildRawSchema(

View file

@ -40,13 +40,14 @@ final class PhabricatorPasswordSettingsPanel extends PhabricatorSettingsPanel {
// the workflow from a password reset email. // the workflow from a password reset email.
$key = $request->getStr('key'); $key = $request->getStr('key');
$password_type = PhabricatorAuthPasswordResetTemporaryTokenType::TOKENTYPE;
$token = null; $token = null;
if ($key) { if ($key) {
$token = id(new PhabricatorAuthTemporaryTokenQuery()) $token = id(new PhabricatorAuthTemporaryTokenQuery())
->setViewer($user) ->setViewer($user)
->withObjectPHIDs(array($user->getPHID())) ->withTokenResources(array($user->getPHID()))
->withTokenTypes( ->withTokenTypes(array($password_type))
array(PhabricatorAuthSessionEngine::PASSWORD_TEMPORARY_TOKEN_TYPE))
->withTokenCodes(array(PhabricatorHash::digest($key))) ->withTokenCodes(array(PhabricatorHash::digest($key)))
->withExpired(false) ->withExpired(false)
->executeOne(); ->executeOne();

View file

@ -23,7 +23,7 @@ final class PhabricatorTokensSettingsPanel extends PhabricatorSettingsPanel {
$tokens = id(new PhabricatorAuthTemporaryTokenQuery()) $tokens = id(new PhabricatorAuthTemporaryTokenQuery())
->setViewer($viewer) ->setViewer($viewer)
->withObjectPHIDs(array($viewer->getPHID())) ->withTokenResources(array($viewer->getPHID()))
->execute(); ->execute();
$rows = array(); $rows = array();

View file

@ -4,6 +4,9 @@ final class PHUIDiffTableOfContentsListView extends AphrontView {
private $items = array(); private $items = array();
private $authorityPackages; private $authorityPackages;
private $header;
private $infoView;
private $background;
public function addItem(PHUIDiffTableOfContentsItemView $item) { public function addItem(PHUIDiffTableOfContentsItemView $item) {
$this->items[] = $item; $this->items[] = $item;
@ -20,6 +23,21 @@ final class PHUIDiffTableOfContentsListView extends AphrontView {
return $this->authorityPackages; return $this->authorityPackages;
} }
public function setBackground($background) {
$this->background = $background;
return $this;
}
public function setHeader(PHUIHeaderView $header) {
$this->header = $header;
return $this;
}
public function setInfoView(PHUIInfoView $infoview) {
$this->infoView = $infoview;
return $this;
}
public function render() { public function render() {
$this->requireResource('differential-core-view-css'); $this->requireResource('differential-core-view-css');
$this->requireResource('differential-table-of-contents-css'); $this->requireResource('differential-table-of-contents-css');
@ -142,11 +160,24 @@ final class PHUIDiffTableOfContentsListView extends AphrontView {
->setAnchorName('toc') ->setAnchorName('toc')
->setNavigationMarker(true); ->setNavigationMarker(true);
return id(new PHUIObjectBoxView()) $header = id(new PHUIHeaderView())
->setHeaderText(pht('Table of Contents')) ->setHeader(pht('Table of Contents'));
if ($this->header) {
$header = $this->header;
}
$box = id(new PHUIObjectBoxView())
->setHeader($header)
->setBackground($this->background)
->setTable($table) ->setTable($table)
->appendChild($anchor) ->appendChild($anchor)
->appendChild($buttons); ->appendChild($buttons);
if ($this->infoView) {
$box->setInfoView($this->infoView);
}
return $box;
} }
} }

View file

@ -494,6 +494,7 @@ final class PhabricatorMarkupEngine extends Phobject {
$rules[] = new PhabricatorIconRemarkupRule(); $rules[] = new PhabricatorIconRemarkupRule();
$rules[] = new PhabricatorEmojiRemarkupRule(); $rules[] = new PhabricatorEmojiRemarkupRule();
$rules[] = new PhabricatorHandleRemarkupRule();
$applications = PhabricatorApplication::getAllInstalledApplications(); $applications = PhabricatorApplication::getAllInstalledApplications();
foreach ($applications as $application) { foreach ($applications as $application) {

View file

@ -14,6 +14,7 @@ final class PHUIInfoView extends AphrontView {
private $id; private $id;
private $buttons = array(); private $buttons = array();
private $isHidden; private $isHidden;
private $flush;
public function setTitle($title) { public function setTitle($title) {
$this->title = $title; $this->title = $title;
@ -40,6 +41,11 @@ final class PHUIInfoView extends AphrontView {
return $this; return $this;
} }
public function setFlush($flush) {
$this->flush = $flush;
return $this;
}
public function addButton(PHUIButtonView $button) { public function addButton(PHUIButtonView $button) {
$this->buttons[] = $button; $this->buttons[] = $button;
return $this; return $this;
@ -87,6 +93,9 @@ final class PHUIInfoView extends AphrontView {
$classes[] = 'phui-info-view'; $classes[] = 'phui-info-view';
$classes[] = 'phui-info-severity-'.$this->severity; $classes[] = 'phui-info-severity-'.$this->severity;
$classes[] = 'grouped'; $classes[] = 'grouped';
if ($this->flush) {
$classes[] = 'phui-info-view-flush';
}
$classes = implode(' ', $classes); $classes = implode(' ', $classes);
$children = $this->renderChildren(); $children = $this->renderChildren();

View file

@ -263,6 +263,7 @@ final class PHUIPagedFormView extends AphrontView {
$form->appendChild($submit); $form->appendChild($submit);
$box = id(new PHUIObjectBoxView()) $box = id(new PHUIObjectBoxView())
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setFormErrors($errors) ->setFormErrors($errors)
->setForm($form); ->setForm($form);

View file

@ -35,6 +35,9 @@ final class PHUIHeadThingView extends AphrontTagView {
$classes = array(); $classes = array();
$classes[] = 'phui-head-thing-view'; $classes[] = 'phui-head-thing-view';
if ($this->image) {
$classes[] = 'phui-head-has-image';
}
if ($this->size) { if ($this->size) {
$classes[] = $this->size; $classes[] = $this->size;
@ -57,8 +60,11 @@ final class PHUIHeadThingView extends AphrontTagView {
'href' => $this->imageHref, 'href' => $this->imageHref,
)); ));
if ($this->image) {
return array($image, $this->content); return array($image, $this->content);
} else {
return $this->content;
}
} }

View file

@ -83,6 +83,26 @@ final class PhabricatorStartup {
* @task info * @task info
*/ */
public static function getRawInput() { public static function getRawInput() {
if (self::$rawInput === null) {
$stream = new AphrontRequestStream();
if (isset($_SERVER['HTTP_CONTENT_ENCODING'])) {
$encoding = trim($_SERVER['HTTP_CONTENT_ENCODING']);
$stream->setEncoding($encoding);
}
$input = '';
do {
$bytes = $stream->readData();
if ($bytes === null) {
break;
}
$input .= $bytes;
} while (true);
self::$rawInput = $input;
}
return self::$rawInput; return self::$rawInput;
} }
@ -128,47 +148,6 @@ final class PhabricatorStartup {
self::detectPostMaxSizeTriggered(); self::detectPostMaxSizeTriggered();
self::beginOutputCapture(); self::beginOutputCapture();
if (isset($_SERVER['HTTP_CONTENT_ENCODING'])) {
$encoding = trim($_SERVER['HTTP_CONTENT_ENCODING']);
} else {
$encoding = null;
}
$input_stream = fopen('php://input', 'rb');
if (!$input_stream) {
self::didFatal(
'Unable to open "php://input" to read HTTP request body.');
}
if ($encoding === 'gzip') {
$ok = stream_filter_append(
$input_stream,
'zlib.inflate',
STREAM_FILTER_READ,
array(
'window' => 30,
));
if (!$ok) {
self::didFatal(
'Failed to append gzip inflate filter to HTTP request body input '.
'stream.');
}
}
$input_data = '';
while (!feof($input_stream)) {
$read_bytes = fread($input_stream, 16 * 1024);
if ($read_bytes === false) {
self::didFatal(
'Failed to read input bytes from HTTP request body.');
}
$input_data .= $read_bytes;
}
fclose($input_stream);
self::$rawInput = $input_data;
} }

View file

@ -6,7 +6,7 @@
.differential-changeset { .differential-changeset {
position: relative; position: relative;
margin: 0; margin: 0;
padding-top: 32px; padding-top: 16px;
overflow-x: auto; overflow-x: auto;
/* Fixes what seems to be a layout bug in Firefox which causes scrollbars, /* Fixes what seems to be a layout bug in Firefox which causes scrollbars,
@ -265,7 +265,7 @@ td.cov-I {
.differential-changeset h1 { .differential-changeset h1 {
font-size: {$biggestfontsize}; font-size: {$biggestfontsize};
padding: 2px 0 12px 12px; padding: 2px 0 20px 12px;
line-height: 20px; line-height: 20px;
color: #000; color: #000;
} }
@ -322,7 +322,7 @@ td.cov-I {
.differential-changeset-buttons { .differential-changeset-buttons {
float: right; float: right;
margin-right: 8px; margin-right: 12px;
} }
.device-phone .differential-changeset-buttons { .device-phone .differential-changeset-buttons {
@ -362,3 +362,7 @@ tr.differential-inline-hidden {
tr.differential-inline-loading { tr.differential-inline-loading {
opacity: 0.5; opacity: 0.5;
} }
.differential-review-stage {
position: relative;
}

View file

@ -3,7 +3,7 @@
*/ */
.differential-primary-pane { .differential-primary-pane {
margin-bottom: 32px; margin-top: -20px;
} }
.differential-panel { .differential-panel {
@ -23,3 +23,7 @@
-ms-user-select: none; -ms-user-select: none;
user-select: none; user-select: none;
} }
.differential-content-hidden {
margin: 0 0 24px 0;
}

Some files were not shown because too many files have changed in this diff Show more