1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-29 02:02:41 +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(
'names' => array(
'core.pkg.css' => '9c8e888d',
'core.pkg.css' => 'a93de192',
'core.pkg.js' => '7d8faf57',
'darkconsole.pkg.js' => 'e7393ebb',
'differential.pkg.css' => '7d0a63a7',
'differential.pkg.css' => '7ba78475',
'differential.pkg.js' => 'd0cd0df6',
'diffusion.pkg.css' => 'f45955ed',
'diffusion.pkg.css' => 'dc8e0cc2',
'diffusion.pkg.js' => '3a9a8bfa',
'maniphest.pkg.css' => '4845691a',
'maniphest.pkg.js' => '949a7498',
@ -57,16 +57,16 @@ return array(
'rsrc/css/application/dashboard/dashboard.css' => 'eb458607',
'rsrc/css/application/diff/inline-comment-summary.css' => '51efda3a',
'rsrc/css/application/differential/add-comment.css' => 'c47f8c40',
'rsrc/css/application/differential/changeset-view.css' => 'b6b0d1bb',
'rsrc/css/application/differential/core.css' => '7ac3cabc',
'rsrc/css/application/differential/changeset-view.css' => '3e3b0b76',
'rsrc/css/application/differential/core.css' => '5b7b8ff4',
'rsrc/css/application/differential/phui-inline-comment.css' => '5953c28e',
'rsrc/css/application/differential/revision-comment.css' => '14b8565a',
'rsrc/css/application/differential/revision-history.css' => '0e8eb855',
'rsrc/css/application/differential/revision-list.css' => 'f3c47d33',
'rsrc/css/application/differential/table-of-contents.css' => 'ae4b7a55',
'rsrc/css/application/diffusion/diffusion-icons.css' => '2941baf1',
'rsrc/css/application/diffusion/diffusion-readme.css' => '356a4f3c',
'rsrc/css/application/diffusion/diffusion-source.css' => '075ba788',
'rsrc/css/application/diffusion/diffusion-icons.css' => '3311444d',
'rsrc/css/application/diffusion/diffusion-readme.css' => '297373eb',
'rsrc/css/application/diffusion/diffusion-source.css' => '68b30fd3',
'rsrc/css/application/feed/feed.css' => 'ecd4ec57',
'rsrc/css/application/files/global-drag-and-drop.css' => '5c1b47c2',
'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-badge.css' => 'f25c3476',
'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-chart.css' => '6bf6f78e',
'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-form-view.css' => '4a1a0f5e',
'rsrc/css/phui/phui-form.css' => 'aac1d51d',
'rsrc/css/phui/phui-head-thing.css' => '31638812',
'rsrc/css/phui/phui-header-view.css' => '26cffd3d',
'rsrc/css/phui/phui-head-thing.css' => 'fd311e5f',
'rsrc/css/phui/phui-header-view.css' => '230254d3',
'rsrc/css/phui/phui-hovercard.css' => 'de1a2119',
'rsrc/css/phui/phui-icon-set-selector.css' => '1ab67aad',
'rsrc/css/phui/phui-icon.css' => '3f33ab57',
'rsrc/css/phui/phui-image-mask.css' => 'a8498f9c',
'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-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-pager.css' => 'bea33d23',
'rsrc/css/phui/phui-pinboard-view.css' => '2495140e',
'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-segment-bar-view.css' => '46342871',
'rsrc/css/phui/phui-spacing.css' => '042804d6',
'rsrc/css/phui/phui-status.css' => '37309046',
'rsrc/css/phui/phui-tag-view.css' => '6bbd83e2',
'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.css' => 'e6d89647',
'rsrc/css/phui/workboards/phui-workcard.css' => '3646fb96',
@ -545,17 +545,17 @@ return array(
'conpherence-update-css' => 'faf6be09',
'conpherence-widget-pane-css' => '775eaaba',
'd3' => 'a11a5ff2',
'differential-changeset-view-css' => 'b6b0d1bb',
'differential-core-view-css' => '7ac3cabc',
'differential-changeset-view-css' => '3e3b0b76',
'differential-core-view-css' => '5b7b8ff4',
'differential-inline-comment-editor' => '64a5550f',
'differential-revision-add-comment-css' => 'c47f8c40',
'differential-revision-comment-css' => '14b8565a',
'differential-revision-history-css' => '0e8eb855',
'differential-revision-list-css' => 'f3c47d33',
'differential-table-of-contents-css' => 'ae4b7a55',
'diffusion-icons-css' => '2941baf1',
'diffusion-readme-css' => '356a4f3c',
'diffusion-source-css' => '075ba788',
'diffusion-icons-css' => '3311444d',
'diffusion-readme-css' => '297373eb',
'diffusion-source-css' => '68b30fd3',
'diviner-shared-css' => 'aa3656aa',
'font-aleo' => '8bdb2835',
'font-fontawesome' => 'c43323c5',
@ -805,7 +805,7 @@ return array(
'phui-action-panel-css' => '91c7b835',
'phui-badge-view-css' => 'f25c3476',
'phui-big-info-view-css' => 'bd903741',
'phui-box-css' => '3830ab21',
'phui-box-css' => 'b2d49bae',
'phui-button-css' => 'a64a8de6',
'phui-calendar-css' => 'ccabe893',
'phui-calendar-day-css' => 'd1cf6f93',
@ -822,23 +822,23 @@ return array(
'phui-fontkit-css' => '9cda225e',
'phui-form-css' => 'aac1d51d',
'phui-form-view-css' => '4a1a0f5e',
'phui-head-thing-view-css' => '31638812',
'phui-header-view-css' => '26cffd3d',
'phui-head-thing-view-css' => 'fd311e5f',
'phui-header-view-css' => '230254d3',
'phui-hovercard' => '1bd28176',
'phui-hovercard-view-css' => 'de1a2119',
'phui-icon-set-selector-css' => '1ab67aad',
'phui-icon-view-css' => '3f33ab57',
'phui-image-mask-css' => 'a8498f9c',
'phui-info-panel-css' => '27ea50a1',
'phui-info-view-css' => '6d7c3509',
'phui-info-view-css' => '28efab79',
'phui-inline-comment-view-css' => '5953c28e',
'phui-list-view-css' => '9da2aa00',
'phui-object-box-css' => '91628842',
'phui-object-box-css' => '6b487c57',
'phui-object-item-list-view-css' => '18b2ce8e',
'phui-pager-css' => 'bea33d23',
'phui-pinboard-view-css' => '2495140e',
'phui-profile-menu-css' => '7e92a89a',
'phui-property-list-view-css' => 'b12e801c',
'phui-property-list-view-css' => '1d42ee7c',
'phui-remarkup-preview-css' => '1a8f2591',
'phui-segment-bar-view-css' => '46342871',
'phui-spacing-css' => '042804d6',
@ -846,7 +846,7 @@ return array(
'phui-tag-view-css' => '6bbd83e2',
'phui-theme-css' => '027ba77e',
'phui-timeline-view-css' => 'a0173eba',
'phui-two-column-view-css' => 'e6bf86b6',
'phui-two-column-view-css' => '37d704f3',
'phui-workboard-color-css' => 'ac6fe6a7',
'phui-workboard-view-css' => 'e6d89647',
'phui-workcard-view-css' => '3646fb96',
@ -1124,6 +1124,9 @@ return array(
'javelin-util',
'javelin-uri',
),
'3e3b0b76' => array(
'phui-inline-comment-view-css',
),
'3f5d6dbf' => array(
'javelin-behavior',
'javelin-dom',
@ -1791,9 +1794,6 @@ return array(
'javelin-json',
'phabricator-draggable-list',
),
'b6b0d1bb' => array(
'phui-inline-comment-view-css',
),
'bae58312' => array(
'javelin-install',
'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',
'DifferentialParseRenderTestCase' => 'applications/differential/__tests__/DifferentialParseRenderTestCase.php',
'DifferentialPathField' => 'applications/differential/customfield/DifferentialPathField.php',
'DifferentialPrimaryPaneView' => 'applications/differential/view/DifferentialPrimaryPaneView.php',
'DifferentialProjectReviewersField' => 'applications/differential/customfield/DifferentialProjectReviewersField.php',
'DifferentialProjectsField' => 'applications/differential/customfield/DifferentialProjectsField.php',
'DifferentialQueryConduitAPIMethod' => 'applications/differential/conduit/DifferentialQueryConduitAPIMethod.php',
@ -508,7 +507,6 @@ phutil_register_library_map(array(
'DifferentialRevisionControlSystem' => 'applications/differential/constants/DifferentialRevisionControlSystem.php',
'DifferentialRevisionDependedOnByRevisionEdgeType' => 'applications/differential/edge/DifferentialRevisionDependedOnByRevisionEdgeType.php',
'DifferentialRevisionDependsOnRevisionEdgeType' => 'applications/differential/edge/DifferentialRevisionDependsOnRevisionEdgeType.php',
'DifferentialRevisionDetailView' => 'applications/differential/view/DifferentialRevisionDetailView.php',
'DifferentialRevisionEditController' => 'applications/differential/controller/DifferentialRevisionEditController.php',
'DifferentialRevisionFulltextEngine' => 'applications/differential/search/DifferentialRevisionFulltextEngine.php',
'DifferentialRevisionHasCommitEdgeType' => 'applications/differential/edge/DifferentialRevisionHasCommitEdgeType.php',
@ -635,6 +633,9 @@ phutil_register_library_map(array(
'DiffusionGitBranch' => 'applications/diffusion/data/DiffusionGitBranch.php',
'DiffusionGitBranchTestCase' => 'applications/diffusion/data/__tests__/DiffusionGitBranchTestCase.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',
'DiffusionGitReceivePackSSHWorkflow' => 'applications/diffusion/ssh/DiffusionGitReceivePackSSHWorkflow.php',
'DiffusionGitRequest' => 'applications/diffusion/request/DiffusionGitRequest.php',
@ -1818,6 +1819,8 @@ phutil_register_library_map(array(
'PhabricatorAuthNewController' => 'applications/auth/controller/config/PhabricatorAuthNewController.php',
'PhabricatorAuthOldOAuthRedirectController' => 'applications/auth/controller/PhabricatorAuthOldOAuthRedirectController.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',
'PhabricatorAuthProviderConfig' => 'applications/auth/storage/PhabricatorAuthProviderConfig.php',
'PhabricatorAuthProviderConfigController' => 'applications/auth/controller/config/PhabricatorAuthProviderConfigController.php',
@ -1843,9 +1846,12 @@ phutil_register_library_map(array(
'PhabricatorAuthSessionQuery' => 'applications/auth/query/PhabricatorAuthSessionQuery.php',
'PhabricatorAuthSetupCheck' => 'applications/config/check/PhabricatorAuthSetupCheck.php',
'PhabricatorAuthStartController' => 'applications/auth/controller/PhabricatorAuthStartController.php',
'PhabricatorAuthTOTPKeyTemporaryTokenType' => 'applications/auth/factor/PhabricatorAuthTOTPKeyTemporaryTokenType.php',
'PhabricatorAuthTemporaryToken' => 'applications/auth/storage/PhabricatorAuthTemporaryToken.php',
'PhabricatorAuthTemporaryTokenGarbageCollector' => 'applications/auth/garbagecollector/PhabricatorAuthTemporaryTokenGarbageCollector.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',
'PhabricatorAuthTryFactorAction' => 'applications/auth/action/PhabricatorAuthTryFactorAction.php',
'PhabricatorAuthUnlinkController' => 'applications/auth/controller/PhabricatorAuthUnlinkController.php',
@ -2349,6 +2355,7 @@ phutil_register_library_map(array(
'PhabricatorFeedStoryPublisher' => 'applications/feed/PhabricatorFeedStoryPublisher.php',
'PhabricatorFeedStoryReference' => 'applications/feed/storage/PhabricatorFeedStoryReference.php',
'PhabricatorFile' => 'applications/files/storage/PhabricatorFile.php',
'PhabricatorFileAccessTemporaryTokenType' => 'applications/files/temporarytoken/PhabricatorFileAccessTemporaryTokenType.php',
'PhabricatorFileBundleLoader' => 'applications/files/query/PhabricatorFileBundleLoader.php',
'PhabricatorFileChunk' => 'applications/files/storage/PhabricatorFileChunk.php',
'PhabricatorFileChunkIterator' => 'applications/files/engine/PhabricatorFileChunkIterator.php',
@ -2447,6 +2454,7 @@ phutil_register_library_map(array(
'PhabricatorHandlePool' => 'applications/phid/handle/pool/PhabricatorHandlePool.php',
'PhabricatorHandlePoolTestCase' => 'applications/phid/handle/pool/__tests__/PhabricatorHandlePoolTestCase.php',
'PhabricatorHandleQuery' => 'applications/phid/query/PhabricatorHandleQuery.php',
'PhabricatorHandleRemarkupRule' => 'applications/phid/remarkup/PhabricatorHandleRemarkupRule.php',
'PhabricatorHandlesEditField' => 'applications/transactions/editfield/PhabricatorHandlesEditField.php',
'PhabricatorHarbormasterApplication' => 'applications/harbormaster/application/PhabricatorHarbormasterApplication.php',
'PhabricatorHarbormasterConfigOptions' => 'applications/harbormaster/config/PhabricatorHarbormasterConfigOptions.php',
@ -2493,6 +2501,7 @@ phutil_register_library_map(array(
'PhabricatorInvalidConfigSetupCheck' => 'applications/config/check/PhabricatorInvalidConfigSetupCheck.php',
'PhabricatorIteratedMD5PasswordHasher' => 'infrastructure/util/password/PhabricatorIteratedMD5PasswordHasher.php',
'PhabricatorIteratedMD5PasswordHasherTestCase' => 'infrastructure/util/password/__tests__/PhabricatorIteratedMD5PasswordHasherTestCase.php',
'PhabricatorIteratorFileUploadSource' => 'applications/files/uploadsource/PhabricatorIteratorFileUploadSource.php',
'PhabricatorJIRAAuthProvider' => 'applications/auth/provider/PhabricatorJIRAAuthProvider.php',
'PhabricatorJavelinLinter' => 'infrastructure/lint/linter/PhabricatorJavelinLinter.php',
'PhabricatorJiraIssueHasObjectEdgeType' => 'applications/doorkeeper/edge/PhabricatorJiraIssueHasObjectEdgeType.php',
@ -2669,6 +2678,7 @@ phutil_register_library_map(array(
'PhabricatorNotificationsApplication' => 'applications/notification/application/PhabricatorNotificationsApplication.php',
'PhabricatorNuanceApplication' => 'applications/nuance/application/PhabricatorNuanceApplication.php',
'PhabricatorOAuth1AuthProvider' => 'applications/auth/provider/PhabricatorOAuth1AuthProvider.php',
'PhabricatorOAuth1SecretTemporaryTokenType' => 'applications/auth/provider/PhabricatorOAuth1SecretTemporaryTokenType.php',
'PhabricatorOAuth2AuthProvider' => 'applications/auth/provider/PhabricatorOAuth2AuthProvider.php',
'PhabricatorOAuthAuthProvider' => 'applications/auth/provider/PhabricatorOAuthAuthProvider.php',
'PhabricatorOAuthClientAuthorization' => 'applications/oauthserver/storage/PhabricatorOAuthClientAuthorization.php',
@ -3091,6 +3101,8 @@ phutil_register_library_map(array(
'PhabricatorRepositoryEngine' => 'applications/repository/engine/PhabricatorRepositoryEngine.php',
'PhabricatorRepositoryGitCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/PhabricatorRepositoryGitCommitChangeParserWorker.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',
'PhabricatorRepositoryGraphStream' => 'applications/repository/daemon/PhabricatorRepositoryGraphStream.php',
'PhabricatorRepositoryManagementCacheWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementCacheWorkflow.php',
@ -4580,7 +4592,6 @@ phutil_register_library_map(array(
'DifferentialParseCommitMessageConduitAPIMethod' => 'DifferentialConduitAPIMethod',
'DifferentialParseRenderTestCase' => 'PhabricatorTestCase',
'DifferentialPathField' => 'DifferentialCustomField',
'DifferentialPrimaryPaneView' => 'AphrontView',
'DifferentialProjectReviewersField' => 'DifferentialCustomField',
'DifferentialProjectsField' => 'DifferentialCoreCustomField',
'DifferentialQueryConduitAPIMethod' => 'DifferentialConduitAPIMethod',
@ -4630,7 +4641,6 @@ phutil_register_library_map(array(
'DifferentialRevisionControlSystem' => 'Phobject',
'DifferentialRevisionDependedOnByRevisionEdgeType' => 'PhabricatorEdgeType',
'DifferentialRevisionDependsOnRevisionEdgeType' => 'PhabricatorEdgeType',
'DifferentialRevisionDetailView' => 'AphrontView',
'DifferentialRevisionEditController' => 'DifferentialController',
'DifferentialRevisionFulltextEngine' => 'PhabricatorFulltextEngine',
'DifferentialRevisionHasCommitEdgeType' => 'PhabricatorEdgeType',
@ -4757,6 +4767,9 @@ phutil_register_library_map(array(
'DiffusionGitBranch' => 'Phobject',
'DiffusionGitBranchTestCase' => 'PhabricatorTestCase',
'DiffusionGitFileContentQuery' => 'DiffusionFileContentQuery',
'DiffusionGitLFSAuthenticateWorkflow' => 'DiffusionGitSSHWorkflow',
'DiffusionGitLFSResponse' => 'AphrontResponse',
'DiffusionGitLFSTemporaryTokenType' => 'PhabricatorAuthTemporaryTokenType',
'DiffusionGitRawDiffQuery' => 'DiffusionRawDiffQuery',
'DiffusionGitReceivePackSSHWorkflow' => 'DiffusionGitSSHWorkflow',
'DiffusionGitRequest' => 'DiffusionRequest',
@ -6127,6 +6140,8 @@ phutil_register_library_map(array(
'PhabricatorAuthNewController' => 'PhabricatorAuthProviderConfigController',
'PhabricatorAuthOldOAuthRedirectController' => 'PhabricatorAuthController',
'PhabricatorAuthOneTimeLoginController' => 'PhabricatorAuthController',
'PhabricatorAuthOneTimeLoginTemporaryTokenType' => 'PhabricatorAuthTemporaryTokenType',
'PhabricatorAuthPasswordResetTemporaryTokenType' => 'PhabricatorAuthTemporaryTokenType',
'PhabricatorAuthProvider' => 'Phobject',
'PhabricatorAuthProviderConfig' => array(
'PhabricatorAuthDAO',
@ -6163,12 +6178,15 @@ phutil_register_library_map(array(
'PhabricatorAuthSessionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorAuthSetupCheck' => 'PhabricatorSetupCheck',
'PhabricatorAuthStartController' => 'PhabricatorAuthController',
'PhabricatorAuthTOTPKeyTemporaryTokenType' => 'PhabricatorAuthTemporaryTokenType',
'PhabricatorAuthTemporaryToken' => array(
'PhabricatorAuthDAO',
'PhabricatorPolicyInterface',
),
'PhabricatorAuthTemporaryTokenGarbageCollector' => 'PhabricatorGarbageCollector',
'PhabricatorAuthTemporaryTokenQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorAuthTemporaryTokenType' => 'Phobject',
'PhabricatorAuthTemporaryTokenTypeModule' => 'PhabricatorConfigModule',
'PhabricatorAuthTerminateSessionController' => 'PhabricatorAuthController',
'PhabricatorAuthTryFactorAction' => 'PhabricatorSystemAction',
'PhabricatorAuthUnlinkController' => 'PhabricatorAuthController',
@ -6763,6 +6781,7 @@ phutil_register_library_map(array(
'PhabricatorPolicyInterface',
'PhabricatorDestructibleInterface',
),
'PhabricatorFileAccessTemporaryTokenType' => 'PhabricatorAuthTemporaryTokenType',
'PhabricatorFileBundleLoader' => 'Phobject',
'PhabricatorFileChunk' => array(
'PhabricatorFileDAO',
@ -6882,6 +6901,7 @@ phutil_register_library_map(array(
'PhabricatorHandlePool' => 'Phobject',
'PhabricatorHandlePoolTestCase' => 'PhabricatorTestCase',
'PhabricatorHandleQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorHandleRemarkupRule' => 'PhutilRemarkupRule',
'PhabricatorHandlesEditField' => 'PhabricatorPHIDListEditField',
'PhabricatorHarbormasterApplication' => 'PhabricatorApplication',
'PhabricatorHarbormasterConfigOptions' => 'PhabricatorApplicationConfigOptions',
@ -6928,6 +6948,7 @@ phutil_register_library_map(array(
'PhabricatorInvalidConfigSetupCheck' => 'PhabricatorSetupCheck',
'PhabricatorIteratedMD5PasswordHasher' => 'PhabricatorPasswordHasher',
'PhabricatorIteratedMD5PasswordHasherTestCase' => 'PhabricatorTestCase',
'PhabricatorIteratorFileUploadSource' => 'PhabricatorFileUploadSource',
'PhabricatorJIRAAuthProvider' => 'PhabricatorOAuth1AuthProvider',
'PhabricatorJavelinLinter' => 'ArcanistLinter',
'PhabricatorJiraIssueHasObjectEdgeType' => 'PhabricatorEdgeType',
@ -7116,6 +7137,7 @@ phutil_register_library_map(array(
'PhabricatorNotificationsApplication' => 'PhabricatorApplication',
'PhabricatorNuanceApplication' => 'PhabricatorApplication',
'PhabricatorOAuth1AuthProvider' => 'PhabricatorOAuthAuthProvider',
'PhabricatorOAuth1SecretTemporaryTokenType' => 'PhabricatorAuthTemporaryTokenType',
'PhabricatorOAuth2AuthProvider' => 'PhabricatorOAuthAuthProvider',
'PhabricatorOAuthAuthProvider' => 'PhabricatorAuthProvider',
'PhabricatorOAuthClientAuthorization' => array(
@ -7647,6 +7669,12 @@ phutil_register_library_map(array(
'PhabricatorRepositoryEngine' => 'Phobject',
'PhabricatorRepositoryGitCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker',
'PhabricatorRepositoryGitCommitMessageParserWorker' => 'PhabricatorRepositoryCommitMessageParserWorker',
'PhabricatorRepositoryGitLFSRef' => array(
'PhabricatorRepositoryDAO',
'PhabricatorPolicyInterface',
'PhabricatorDestructibleInterface',
),
'PhabricatorRepositoryGitLFSRefQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorRepositoryGraphCache' => 'Phobject',
'PhabricatorRepositoryGraphStream' => 'Phobject',
'PhabricatorRepositoryManagementCacheWorkflow' => 'PhabricatorRepositoryManagementWorkflow',

View file

@ -25,12 +25,19 @@ class AphrontDefaultApplicationConfiguration
$content_type = idx($_SERVER, '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();
if (strlen($raw_input) && !$is_form_data) {
$data += $parser->parseQueryString($raw_input);
} else if ($_POST) {
$data += $_POST;
}
}
$data += $parser->parseQueryString(idx($_SERVER, 'QUERY_STRING', ''));

View file

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

View file

@ -117,12 +117,37 @@ final class PhabricatorAuditTransaction
return 'red';
case PhabricatorAuditActionConstants::ACCEPT:
return 'green';
case PhabricatorAuditActionConstants::RESIGN:
return 'black';
case PhabricatorAuditActionConstants::CLOSE:
return 'indigo';
}
}
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() {
$old = $this->getOldValue();
$new = $this->getNewValue();

View file

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

View file

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

View file

@ -39,17 +39,6 @@ final class PhabricatorAuthSessionEngine extends Phobject {
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_RESET = 'reset';
const ONETIME_WELCOME = 'welcome';
@ -642,11 +631,12 @@ final class PhabricatorAuthSessionEngine extends Phobject {
$key = Filesystem::readRandomCharacters(32);
$key_hash = $this->getOneTimeLoginKeyHash($user, $email, $key);
$onetime_type = PhabricatorAuthOneTimeLoginTemporaryTokenType::TOKENTYPE;
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
id(new PhabricatorAuthTemporaryToken())
->setObjectPHID($user->getPHID())
->setTokenType(self::ONETIME_TEMPORARY_TOKEN_TYPE)
->setTokenResource($user->getPHID())
->setTokenType($onetime_type)
->setTokenExpires(time() + phutil_units('1 day in seconds'))
->setTokenCode($key_hash)
->save();
@ -685,11 +675,12 @@ final class PhabricatorAuthSessionEngine extends Phobject {
$key = null) {
$key_hash = $this->getOneTimeLoginKeyHash($user, $email, $key);
$onetime_type = PhabricatorAuthOneTimeLoginTemporaryTokenType::TOKENTYPE;
return id(new PhabricatorAuthTemporaryTokenQuery())
->setViewer($user)
->withObjectPHIDs(array($user->getPHID()))
->withTokenTypes(array(self::ONETIME_TEMPORARY_TOKEN_TYPE))
->withTokenResources(array($user->getPHID()))
->withTokenTypes(array($onetime_type))
->withTokenCodes(array($key_hash))
->withExpired(false)
->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 {
const TEMPORARY_TOKEN_TYPE = 'mfa:totp:key';
public function getFactorKey() {
return 'totp';
}
@ -24,6 +22,8 @@ final class PhabricatorTOTPAuthFactor extends PhabricatorAuthFactor {
AphrontRequest $request,
PhabricatorUser $user) {
$totp_token_type = PhabricatorAuthTOTPKeyTemporaryTokenType::TOKENTYPE;
$key = $request->getStr('totpkey');
if (strlen($key)) {
// 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())
->setViewer($user)
->withObjectPHIDs(array($user->getPHID()))
->withTokenTypes(array(self::TEMPORARY_TOKEN_TYPE))
->withTokenResources(array($user->getPHID()))
->withTokenTypes(array($totp_token_type))
->withExpired(false)
->withTokenCodes(array(PhabricatorHash::digest($key)))
->executeOne();
@ -55,8 +55,8 @@ final class PhabricatorTOTPAuthFactor extends PhabricatorAuthFactor {
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
id(new PhabricatorAuthTemporaryToken())
->setObjectPHID($user->getPHID())
->setTokenType(self::TEMPORARY_TOKEN_TYPE)
->setTokenResource($user->getPHID())
->setTokenType($totp_token_type)
->setTokenExpires(time() + phutil_units('1 hour in seconds'))
->setTokenCode(PhabricatorHash::digest($key))
->save();

View file

@ -9,8 +9,6 @@ abstract class PhabricatorOAuth1AuthProvider
const PROPERTY_CONSUMER_SECRET = 'oauth1:consumer:secret';
const PROPERTY_PRIVATE_KEY = 'oauth1:private:key';
const TEMPORARY_TOKEN_TYPE = 'oauth1:request:secret';
protected function getIDKey() {
return self::PROPERTY_CONSUMER_KEY;
}
@ -215,13 +213,14 @@ abstract class PhabricatorOAuth1AuthProvider
private function saveHandshakeTokenSecret($client_code, $secret) {
$secret_type = PhabricatorOAuth1SecretTemporaryTokenType::TOKENTYPE;
$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.
$token = id(new PhabricatorAuthTemporaryTokenQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withObjectPHIDs(array($key))
->withTokenResources(array($key))
->withTokenTypes(array($type))
->executeOne();
if ($token) {
@ -230,7 +229,7 @@ abstract class PhabricatorOAuth1AuthProvider
// Save the new secret.
id(new PhabricatorAuthTemporaryToken())
->setObjectPHID($key)
->setTokenResource($key)
->setTokenType($type)
->setTokenExpires(time() + phutil_units('1 hour in seconds'))
->setTokenCode($secret)
@ -238,12 +237,13 @@ abstract class PhabricatorOAuth1AuthProvider
}
private function loadHandshakeTokenSecret($client_code) {
$secret_type = PhabricatorOAuth1SecretTemporaryTokenType::TOKENTYPE;
$key = $this->getHandshakeTokenKeyFromClientCode($client_code);
$type = $this->getTemporaryTokenType(self::TEMPORARY_TOKEN_TYPE);
$type = $this->getTemporaryTokenType($secret_type);
$token = id(new PhabricatorAuthTemporaryTokenQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withObjectPHIDs(array($key))
->withTokenResources(array($key))
->withTokenTypes(array($type))
->withExpired(false)
->executeOne();
@ -263,6 +263,9 @@ abstract class PhabricatorOAuth1AuthProvider
// others' toes if a user starts Mediawiki and Bitbucket auth at the
// 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();
}

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 {
private $ids;
private $objectPHIDs;
private $tokenResources;
private $tokenTypes;
private $userPHIDs;
private $expired;
private $tokenCodes;
@ -14,8 +15,8 @@ final class PhabricatorAuthTemporaryTokenQuery
return $this;
}
public function withObjectPHIDs(array $object_phids) {
$this->objectPHIDs = $object_phids;
public function withTokenResources(array $resources) {
$this->tokenResources = $resources;
return $this;
}
@ -34,41 +35,39 @@ final class PhabricatorAuthTemporaryTokenQuery
return $this;
}
protected function loadPage() {
$table = new PhabricatorAuthTemporaryToken();
$conn_r = $table->establishConnection('r');
$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);
public function withUserPHIDs(array $phids) {
$this->userPHIDs = $phids;
return $this;
}
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
$where = array();
public function newResultObject() {
return new PhabricatorAuthTemporaryToken();
}
protected function loadPage() {
return $this->loadStandardPage($this->newResultObject());
}
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
$where = parent::buildWhereClauseParts($conn);
if ($this->ids !== null) {
$where[] = qsprintf(
$conn_r,
$conn,
'id IN (%Ld)',
$this->ids);
}
if ($this->objectPHIDs !== null) {
if ($this->tokenResources !== null) {
$where[] = qsprintf(
$conn_r,
'objectPHID IN (%Ls)',
$this->objectPHIDs);
$conn,
'tokenResource IN (%Ls)',
$this->tokenResources);
}
if ($this->tokenTypes !== null) {
$where[] = qsprintf(
$conn_r,
$conn,
'tokenType IN (%Ls)',
$this->tokenTypes);
}
@ -76,12 +75,12 @@ final class PhabricatorAuthTemporaryTokenQuery
if ($this->expired !== null) {
if ($this->expired) {
$where[] = qsprintf(
$conn_r,
$conn,
'tokenExpires <= %d',
time());
} else {
$where[] = qsprintf(
$conn_r,
$conn,
'tokenExpires > %d',
time());
}
@ -89,14 +88,19 @@ final class PhabricatorAuthTemporaryTokenQuery
if ($this->tokenCodes !== null) {
$where[] = qsprintf(
$conn_r,
$conn,
'tokenCode IN (%Ls)',
$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() {

View file

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

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');
}
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) {
static $types = array(
self::TYPE_MOVE_AWAY => true,

View file

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

View file

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

View file

@ -40,7 +40,6 @@ final class DifferentialRevisionViewController extends DifferentialController {
$revision->attachActiveDiff(last($diffs));
$diff_vs = $request->getInt('vs');
$target_id = $request->getInt('id');
$target = idx($diffs, $target_id, end($diffs));
@ -210,14 +209,10 @@ final class DifferentialRevisionViewController extends DifferentialController {
$commits_for_links = array();
}
$revision_detail = id(new DifferentialRevisionDetailView())
->setUser($viewer)
->setRevision($revision)
->setDiff(end($diffs))
->setCustomFields($field_list)
->setURI($request->getRequestURI());
$actions = $this->getRevisionActions($revision);
$header = $this->buildHeader($revision);
$subheader = $this->buildSubheaderView($revision);
$details = $this->buildDetails($revision, $field_list);
$curtain = $this->buildCurtain($revision);
$whitespace = $request->getStr(
'whitespace',
@ -232,21 +227,16 @@ final class DifferentialRevisionViewController extends DifferentialController {
$symbol_indexes = array();
}
$revision_detail->setActions($actions);
$revision_detail->setUser($viewer);
$revision_detail_box = $revision_detail->render();
$revision_warnings = $this->buildRevisionWarnings(
$revision,
$field_list,
$warning_handle_map,
$handles);
$info_view = null;
if ($revision_warnings) {
$revision_warnings = id(new PHUIInfoView())
$info_view = id(new PHUIInfoView())
->setSeverity(PHUIInfoView::SEVERITY_WARNING)
->setErrors($revision_warnings);
$revision_detail_box->setInfoView($revision_warnings);
}
$detail_diffs = array_select_keys(
@ -277,39 +267,31 @@ final class DifferentialRevisionViewController extends DifferentialController {
$comment_view->setQuoteTargetID('comment-content');
}
$wrap_id = celerity_generate_unique_node_id();
$comment_view = phutil_tag(
'div',
array(
'id' => $wrap_id,
),
$comment_view);
$changeset_view = id(new DifferentialChangesetListView())
->setChangesets($changesets)
->setVisibleChangesets($visible_changesets)
->setStandaloneURI('/differential/changeset/')
->setRawFileURIs(
'/differential/changeset/?view=old',
'/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();
$changeset_view->setChangesets($changesets);
$changeset_view->setVisibleChangesets($visible_changesets);
if ($repository) {
$changeset_view->setRepository($repository);
}
if (!$viewer_is_anonymous) {
$changeset_view->setInlineCommentControllerURI(
'/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())
->setUser($viewer)
->setDiffs($diffs)
@ -344,6 +326,233 @@ final class DifferentialRevisionViewController extends DifferentialController {
$comment_form = null;
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(
'authorPHID = %s AND draftKey = %s',
$viewer->getPHID(),
@ -361,8 +570,8 @@ final class DifferentialRevisionViewController extends DifferentialController {
}
}
$comment_form = new DifferentialAddCommentView();
$comment_form->setRevision($revision);
$comment_form = id(new DifferentialAddCommentView())
->setRevision($revision);
$review_warnings = array();
foreach ($field_list->getFields() as $field) {
@ -377,15 +586,15 @@ final class DifferentialRevisionViewController extends DifferentialController {
$comment_form->setInfoView($review_warnings_panel);
}
$comment_form->setActions($this->getRevisionCommentActions($revision));
$action_uri = $this->getApplicationURI(
'comment/save/'.$revision->getID().'/');
$comment_form->setActionURI($action_uri);
$comment_form->setUser($viewer);
$comment_form->setDraft($draft);
$comment_form->setReviewers(mpull($reviewers, 'getFullName', 'getPHID'));
$comment_form->setCCs(mpull($ccs, 'getFullName', 'getPHID'));
$comment_form->setActions($this->getRevisionCommentActions($revision))
->setActionURI($action_uri)
->setUser($viewer)
->setDraft($draft)
->setReviewers(mpull($reviewers, 'getFullName', 'getPHID'))
->setCCs(mpull($ccs, 'getFullName', 'getPHID'));
// TODO: This just makes the "Z" key work. Generalize this and remove
// it at some point.
@ -395,162 +604,7 @@ final class DifferentialRevisionViewController extends DifferentialController {
'class' => 'differential-add-comment-panel',
),
$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;
return $comment_form;
}
private function getRevisionCommentActions(DifferentialRevision $revision) {
@ -558,7 +612,7 @@ final class DifferentialRevisionViewController extends DifferentialController {
DifferentialAction::ACTION_COMMENT => true,
);
$viewer = $this->getRequest()->getUser();
$viewer = $this->getViewer();
$viewer_phid = $viewer->getPHID();
$viewer_is_owner = ($viewer_phid == $revision->getAuthorPHID());
$viewer_is_reviewer = in_array($viewer_phid, $revision->getReviewers());
@ -814,11 +868,12 @@ final class DifferentialRevisionViewController extends DifferentialController {
$viewer = $this->getViewer();
$header = id(new PHUIHeaderView())
->setHeader(pht('Recent Similar Open Revisions'));
->setHeader(pht('Recent Similar Revisions'));
$view = id(new DifferentialRevisionListView())
->setHeader($header)
->setRevisions($revisions)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setUser($viewer);
$phids = $view->getRequiredHandlePHIDs();
@ -845,7 +900,7 @@ final class DifferentialRevisionViewController extends DifferentialController {
assert_instances_of($changesets, 'DifferentialChangeset');
assert_instances_of($vs_changesets, 'DifferentialChangeset');
$viewer = $this->getRequest()->getUser();
$viewer = $this->getViewer();
id(new DifferentialHunkQuery())
->setViewer($viewer)
@ -978,7 +1033,8 @@ final class DifferentialRevisionViewController extends DifferentialController {
}
$box = id(new PHUIObjectBoxView())
->setHeaderText(pht('Diff Detail'))
->setHeaderText(pht('DIFF DETAIL'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setUser($viewer);
$last_tab = null;
@ -1061,7 +1117,8 @@ final class DifferentialRevisionViewController extends DifferentialController {
}
$box_view = id(new PHUIObjectBoxView())
->setHeaderText(pht('Active Operations'));
->setHeaderText(pht('ACTIVE OPERATIONS'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);
return id(new DrydockRepositoryOperationStatusView())
->setUser($viewer)
@ -1074,11 +1131,11 @@ final class DifferentialRevisionViewController extends DifferentialController {
DifferentialRevision $revision) {
$viewer = $this->getViewer();
if (!$diff->getUnitMessages()) {
if (!$diff->getBuildable()) {
return null;
}
if (!$diff->getBuildable()) {
if (!$diff->getUnitMessages()) {
return null;
}
@ -1109,6 +1166,7 @@ final class DifferentialRevisionViewController extends DifferentialController {
->setBuildable($diff->getBuildable())
->setUnitMessages($diff->getUnitMessages())
->setLimit(5)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setShowViewAll(true);
}

View file

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

View file

@ -70,8 +70,6 @@ final class DifferentialHovercardEngineExtension
$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');
$header_text = $is_serious
? pht('Add Comment')
: pht('Leap Into Action');
: pht('Leap Into Action!');
$header = id(new PHUIHeaderView())
->setHeader($header_text);

View file

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

View file

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

View file

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

View file

@ -48,26 +48,37 @@ final class DiffusionBranchTableController extends DiffusionController {
->withRepository($repository)
->execute();
$view = id(new DiffusionBranchTableView())
$table = id(new DiffusionBranchTableView())
->setUser($viewer)
->setBranches($branches)
->setCommits($commits)
->setDiffusionRequest($drequest);
$panel = id(new PHUIObjectBoxView())
->setHeaderText(pht('Branches'))
->setTable($view);
$content = $panel;
$content = id(new PHUIObjectBoxView())
->setHeaderText($repository->getName())
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($table);
}
$crumbs = $this->buildCrumbs(
array(
'branches' => true,
));
$crumbs->setBorder(true);
$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()
->setTitle(
array(
@ -77,8 +88,7 @@ final class DiffusionBranchTableController extends DiffusionController {
->setCrumbs($crumbs)
->appendChild(
array(
$content,
$pager_box,
$view,
));
}

View file

@ -55,20 +55,17 @@ final class DiffusionBrowseController extends DiffusionController {
}
private function browseSearch() {
$drequest = $this->getDiffusionRequest();
$header = $this->buildHeaderView($drequest);
$actions = $this->buildActionView($drequest);
$properties = $this->buildPropertyView($drequest, $actions);
$search_form = $this->renderSearchForm();
$search_results = $this->renderSearchResults();
$object_box = id(new PHUIObjectBoxView())
->setHeader($this->buildHeaderView($drequest))
->addPropertyList($properties);
$content = array();
$content[] = $object_box;
$content[] = $this->renderSearchForm($collapsed = false);
$content[] = $this->renderSearchResults();
$search_form = id(new PHUIObjectBoxView())
->setHeaderText(pht('Search'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->appendChild($search_form);
$crumbs = $this->buildCrumbs(
array(
@ -76,6 +73,14 @@ final class DiffusionBrowseController extends DiffusionController {
'path' => true,
'view' => 'browse',
));
$crumbs->setBorder(true);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter(array(
$search_form,
$search_results,
));
return $this->newPage()
->setTitle(
@ -84,7 +89,7 @@ final class DiffusionBrowseController extends DiffusionController {
$drequest->getRepository()->getDisplayName(),
))
->setCrumbs($crumbs)
->appendChild($content);
->appendChild($view);
}
private function browseFile() {
@ -187,7 +192,25 @@ final class DiffusionBrowseController extends DiffusionController {
}
$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();
if ($file->isViewableImage()) {
@ -218,20 +241,18 @@ final class DiffusionBrowseController extends DiffusionController {
require_celerity_resource('diffusion-source-css');
// Render the page.
$view = $this->buildActionView($drequest);
$action_list = $this->enrichActionView(
$view = $this->buildCurtain($drequest);
$curtain = $this->enrichCurtain(
$view,
$drequest,
$show_blame,
$show_color);
$properties = $this->buildPropertyView($drequest, $action_list);
$object_box = id(new PHUIObjectBoxView())
->setHeader($this->buildHeaderView($drequest))
->addPropertyList($properties);
$properties = $this->buildPropertyView($drequest);
$header = $this->buildHeaderView($drequest);
$header->setHeaderIcon('fa-file-code-o');
$content = array();
$content[] = $object_box;
$follow = $request->getStr('follow');
if ($follow) {
@ -277,17 +298,31 @@ final class DiffusionBrowseController extends DiffusionController {
'path' => true,
'view' => 'browse',
));
$crumbs->setBorder(true);
$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()
->setTitle(
array(
$basename,
$repository->getDisplayName(),
))
->setTitle($title)
->setCrumbs($crumbs)
->appendChild($content);
->appendChild(
array(
$view,
));
}
public function browseDirectory(
@ -300,23 +335,21 @@ final class DiffusionBrowseController extends DiffusionController {
$reason = $results->getReasonForEmptyResultSet();
$content = array();
$actions = $this->buildActionView($drequest);
$properties = $this->buildPropertyView($drequest, $actions);
$curtain = $this->buildCurtain($drequest);
$details = $this->buildPropertyView($drequest);
$object_box = id(new PHUIObjectBoxView())
->setHeader($this->buildHeaderView($drequest))
->addPropertyList($properties);
$header = $this->buildHeaderView($drequest);
$header->setHeaderIcon('fa-folder-open');
$content[] = $object_box;
$content[] = $this->renderSearchForm($collapsed = true);
$search_form = $this->renderSearchForm();
$empty_result = null;
$browse_panel = null;
if (!$results->isValidResults()) {
$empty_result = new DiffusionEmptyResultView();
$empty_result->setDiffusionRequest($drequest);
$empty_result->setDiffusionBrowseResultSet($results);
$empty_result->setView($request->getStr('view'));
$content[] = $empty_result;
} else {
$phids = array();
foreach ($results->getPaths() as $result) {
@ -331,21 +364,30 @@ final class DiffusionBrowseController extends DiffusionController {
$phids = array_keys($phids);
$handles = $this->loadViewerHandles($phids);
$browse_table = new DiffusionBrowseTableView();
$browse_table->setDiffusionRequest($drequest);
$browse_table->setHandles($handles);
$browse_table->setPaths($results->getPaths());
$browse_table->setUser($request->getUser());
$browse_table = id(new DiffusionBrowseTableView())
->setDiffusionRequest($drequest)
->setHandles($handles)
->setPaths($results->getPaths())
->setUser($request->getUser());
$browse_panel = new PHUIObjectBoxView();
$browse_panel->setHeaderText($drequest->getPath(), '/');
$browse_panel->setTable($browse_table);
$browse_header = id(new PHUIHeaderView())
->setHeader(nonempty(basename($drequest->getPath()), '/'))
->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();
$content[] = $this->renderDirectoryReadme($results);
$open_revisions = $this->buildOpenRevisions();
$readme = $this->renderDirectoryReadme($results);
$crumbs = $this->buildCrumbs(
array(
@ -355,18 +397,34 @@ final class DiffusionBrowseController extends DiffusionController {
));
$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()
->setTitle(
array(
->setTitle(array(
nonempty(basename($drequest->getPath()), '/'),
$repository->getDisplayName(),
))
->setCrumbs($crumbs)
->appendChild(
array(
$content,
$pager_box,
$view,
));
}
@ -431,6 +489,7 @@ final class DiffusionBrowseController extends DiffusionController {
$box = id(new PHUIObjectBoxView())
->setHeaderText($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($table);
$pager_box = $this->renderTablePagerBox($pager);
@ -697,12 +756,14 @@ final class DiffusionBrowseController extends DiffusionController {
$edit = $this->renderEditButton();
$file = $this->renderFileButton();
$header = id(new PHUIHeaderView())
->setHeader(pht('File Contents'))
->setHeader(basename($this->getDiffusionRequest()->getPath()))
->setHeaderIcon('fa-file-code-o')
->addActionLink($edit)
->addActionLink($file);
$corpus = id(new PHUIObjectBoxView())
->setHeader($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->appendChild($corpus)
->setCollapsed(true);
@ -737,16 +798,16 @@ final class DiffusionBrowseController extends DiffusionController {
return $corpus;
}
private function enrichActionView(
PhabricatorActionListView $view,
private function enrichCurtain(
PHUICurtainView $curtain,
DiffusionRequest $drequest,
$show_blame,
$show_color) {
$viewer = $this->getRequest()->getUser();
$viewer = $this->getViewer();
$base_uri = $this->getRequest()->getRequestURI();
$view->addAction(
$curtain->addAction(
id(new PhabricatorActionView())
->setName(pht('Show Last Change'))
->setHref(
@ -766,7 +827,7 @@ final class DiffusionBrowseController extends DiffusionController {
$blame_value = 1;
}
$view->addAction(
$curtain->addAction(
id(new PhabricatorActionView())
->setName($blame_text)
->setHref($base_uri->alter('blame', $blame_value))
@ -784,7 +845,7 @@ final class DiffusionBrowseController extends DiffusionController {
$highlight_value = 1;
}
$view->addAction(
$curtain->addAction(
id(new PhabricatorActionView())
->setName($highlight_text)
->setHref($base_uri->alter('color', $highlight_value))
@ -809,14 +870,57 @@ final class DiffusionBrowseController extends DiffusionController {
))->alter('lint', '');
}
$view->addAction(
$curtain->addAction(
id(new PhabricatorActionView())
->setName($lint_text)
->setHref($href)
->setIcon('fa-exclamation-triangle')
->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() {
@ -844,7 +948,7 @@ final class DiffusionBrowseController extends DiffusionController {
return $button;
}
private function renderFileButton($file_uri = null) {
private function renderFileButton($file_uri = null, $label = null) {
$base_uri = $this->getRequest()->getRequestURI();
@ -858,6 +962,10 @@ final class DiffusionBrowseController extends DiffusionController {
$icon = 'fa-file-text';
}
if ($label !== null) {
$text = $label;
}
$button = id(new PHUIButtonView())
->setTag('a')
->setText($text)
@ -867,6 +975,21 @@ final class DiffusionBrowseController extends DiffusionController {
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(
array $lines,
@ -1265,11 +1388,13 @@ final class DiffusionBrowseController extends DiffusionController {
$file = $this->renderFileButton($file_uri);
$header = id(new PHUIHeaderView())
->setHeader(pht('Image'))
->addActionLink($file);
->setHeader(basename($this->getDiffusionRequest()->getPath()))
->addActionLink($file)
->setHeaderIcon('fa-file-image-o');
return id(new PHUIObjectBoxView())
->setHeader($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($properties);
}
@ -1282,11 +1407,12 @@ final class DiffusionBrowseController extends DiffusionController {
$file = $this->renderFileButton($file_uri);
$header = id(new PHUIHeaderView())
->setHeader(pht('Details'))
->setHeader(pht('DETAILS'))
->addActionLink($file);
$box = id(new PHUIObjectBoxView())
->setHeader($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->appendChild($text);
return $box;
@ -1298,7 +1424,7 @@ final class DiffusionBrowseController extends DiffusionController {
->appendChild($message);
$header = id(new PHUIHeaderView())
->setHeader(pht('Details'));
->setHeader(pht('DETAILS'));
$box = id(new PHUIObjectBoxView())
->setHeader($header)
@ -1461,12 +1587,12 @@ final class DiffusionBrowseController extends DiffusionController {
return "{$summary}\n{$date} \xC2\xB7 {$author}";
}
protected function renderSearchForm($collapsed) {
protected function renderSearchForm() {
$drequest = $this->getDiffusionRequest();
$forms = array();
$form = id(new AphrontFormView())
->setUser($this->getRequest()->getUser())
->setUser($this->getViewer())
->setMethod('GET');
switch ($drequest->getRepository()->getVersionControlSystem()) {
@ -1492,22 +1618,10 @@ final class DiffusionBrowseController extends DiffusionController {
break;
}
$filter = new AphrontListFilterView();
$filter->appendChild($forms);
require_celerity_resource('diffusion-icons-css');
$form_box = phutil_tag_div('diffusion-search-boxen', $forms);
if ($collapsed) {
$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;
return $form_box;
}
protected function markupText($text) {
@ -1526,28 +1640,29 @@ final class DiffusionBrowseController extends DiffusionController {
}
protected function buildHeaderView(DiffusionRequest $drequest) {
$viewer = $this->getRequest()->getUser();
$viewer = $this->getViewer();
$tag = $this->renderCommitHashTag($drequest);
$header = id(new PHUIHeaderView())
->setUser($viewer)
->setHeader($this->renderPathLinks($drequest, $mode = 'browse'))
->setPolicyObject($drequest->getRepository());
->addTag($tag);
return $header;
}
protected function buildActionView(DiffusionRequest $drequest) {
$viewer = $this->getRequest()->getUser();
protected function buildCurtain(DiffusionRequest $drequest) {
$viewer = $this->getViewer();
$view = id(new PhabricatorActionListView())
->setUser($viewer);
$curtain = $this->newCurtainView($drequest);
$history_uri = $drequest->generateURI(
array(
'action' => 'history',
));
$view->addAction(
$curtain->addAction(
id(new PhabricatorActionView())
->setName(pht('View History'))
->setHref($history_uri)
@ -1559,40 +1674,22 @@ final class DiffusionBrowseController extends DiffusionController {
'commit' => '',
'action' => 'browse',
));
$view->addAction(
$curtain->addAction(
id(new PhabricatorActionView())
->setName(pht('Jump to HEAD'))
->setHref($head_uri)
->setIcon('fa-home')
->setDisabled(!$behind_head));
return $view;
return $curtain;
}
protected function buildPropertyView(
DiffusionRequest $drequest,
PhabricatorActionListView $actions) {
DiffusionRequest $drequest) {
$viewer = $this->getViewer();
$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)));
->setUser($viewer);
if ($drequest->getSymbolicType() == 'tag') {
$symbolic = $drequest->getSymbolicCommit();
@ -1616,49 +1713,13 @@ final class DiffusionBrowseController extends DiffusionController {
}
}
$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'));
}
$view->addProperty(pht('Packages'), $ownership);
}
if ($view->hasAnyProperties()) {
return $view;
}
return null;
}
private function buildOpenRevisions() {
$viewer = $this->getViewer();
@ -1865,4 +1926,90 @@ final class DiffusionBrowseController extends DiffusionController {
$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();
$drequest = $this->getDiffusionRequest();
$content = array();
$data = $this->callConduitWithDiffusionRequest(
'diffusion.diffquery',
array(
@ -42,9 +40,11 @@ final class DiffusionChangeController extends DiffusionController {
0 => $changeset,
);
$changeset_header = $this->buildChangesetHeader($drequest);
$changeset_view = new DifferentialChangesetListView();
$changeset_view->setTitle(pht('Change'));
$changeset_view->setChangesets($changesets);
$changeset_view->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);
$changeset_view->setVisibleChangesets($changesets);
$changeset_view->setRenderingReferences(
array(
@ -68,11 +68,11 @@ final class DiffusionChangeController extends DiffusionController {
$changeset_view->setWhitespace(
DifferentialChangesetParser::WHITESPACE_SHOW_ALL);
$changeset_view->setUser($viewer);
$changeset_view->setHeader($changeset_header);
// TODO: This is pretty awkward, unify the CSS between Diffusion and
// Differential better.
require_celerity_resource('differential-core-view-css');
$content[] = $changeset_view->render();
$crumbs = $this->buildCrumbs(
array(
@ -80,19 +80,18 @@ final class DiffusionChangeController extends DiffusionController {
'path' => true,
'view' => 'change',
));
$crumbs->setBorder(true);
$links = $this->renderPathLinks($drequest, $mode = 'browse');
$header = $this->buildHeader($drequest, $links);
$header = id(new PHUIHeaderView())
->setHeader($links)
->setUser($viewer)
->setPolicyObject($drequest->getRepository());
$actions = $this->buildActionView($drequest);
$properties = $this->buildPropertyView($drequest, $actions);
$object_box = id(new PHUIObjectBoxView())
$view = id(new PHUITwoColumnView())
->setHeader($header)
->addPropertyList($properties);
->setMainColumn(array(
))
->setFooter(array(
$changeset_view,
));
return $this->newPage()
->setTitle(
@ -103,25 +102,41 @@ final class DiffusionChangeController extends DiffusionController {
->setCrumbs($crumbs)
->appendChild(
array(
$object_box,
$content,
$view,
));
}
private function buildActionView(DiffusionRequest $drequest) {
$viewer = $this->getRequest()->getUser();
private function buildHeader(
DiffusionRequest $drequest,
$links) {
$viewer = $this->getViewer();
$view = id(new PhabricatorActionListView())
->setUser($viewer);
$tag = $this->renderCommitHashTag($drequest);
$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(
array(
'action' => 'history',
));
$view->addAction(
id(new PhabricatorActionView())
->setName(pht('View History'))
$header->addActionLink(
id(new PHUIButtonView())
->setTag('a')
->setText(pht('View History'))
->setHref($history_uri)
->setIcon('fa-clock-o'));
@ -130,13 +145,14 @@ final class DiffusionChangeController extends DiffusionController {
'action' => 'browse',
));
$view->addAction(
id(new PhabricatorActionView())
->setName(pht('Browse Content'))
$header->addActionLink(
id(new PHUIButtonView())
->setTag('a')
->setText(pht('Browse Content'))
->setHref($browse_uri)
->setIcon('fa-files-o'));
return $view;
return $header;
}
protected function buildPropertyView(

View file

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

View file

@ -291,6 +291,7 @@ abstract class DiffusionController extends PhabricatorController {
return id(new PHUIInfoView())
->setSeverity(PHUIInfoView::SEVERITY_WARNING)
->setTitle($title)
->setFlush(true)
->appendChild($body);
}
@ -300,6 +301,27 @@ abstract class DiffusionController extends PhabricatorController {
->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) {
$readme_path = $browse->getReadmePath();
if ($readme_path === null) {

View file

@ -40,8 +40,6 @@ final class DiffusionHistoryController extends DiffusionController {
$history = $pager->sliceResults($history);
$show_graph = !strlen($drequest->getPath());
$content = array();
$history_table = id(new DiffusionHistoryTableView())
->setUser($request->getUser())
->setDiffusionRequest($drequest)
@ -55,23 +53,13 @@ final class DiffusionHistoryController extends DiffusionController {
$history_table->setIsTail(!$pager->getHasMorePages());
}
$history_panel = new PHUIObjectBoxView();
$history_panel->setHeaderText(pht('History'));
$history_panel->setTable($history_table);
$history_header = $this->buildHistoryHeader($drequest);
$history_panel = id(new PHUIObjectBoxView())
->setHeader($history_header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($history_table);
$content[] = $history_panel;
$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);
$header = $this->buildHeader($drequest, $repository);
$crumbs = $this->buildCrumbs(
array(
@ -79,9 +67,17 @@ final class DiffusionHistoryController extends DiffusionController {
'path' => true,
'view' => 'history',
));
$crumbs->setBorder(true);
$pager_box = $this->renderTablePagerBox($pager);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter(array(
$history_panel,
$pager_box,
));
return $this->newPage()
->setTitle(
array(
@ -91,28 +87,39 @@ final class DiffusionHistoryController extends DiffusionController {
->setCrumbs($crumbs)
->appendChild(
array(
$object_box,
$content,
$pager_box,
$view,
));
}
private function buildActionView(DiffusionRequest $drequest) {
$viewer = $this->getRequest()->getUser();
private function buildHeader(DiffusionRequest $drequest) {
$viewer = $this->getViewer();
$view = id(new PhabricatorActionListView())
->setUser($viewer);
$tag = $this->renderCommitHashTag($drequest);
$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(
array(
'action' => 'browse',
));
$view->addAction(
id(new PhabricatorActionView())
->setName(pht('Browse Content'))
$browse_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Browse'))
->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
// recent history entry to figure it out.
@ -130,41 +137,18 @@ final class DiffusionHistoryController extends DiffusionController {
->alter('copies', true);
}
$view->addAction(
id(new PhabricatorActionView())
->setName($branch_name)
$branch_button = id(new PHUIButtonView())
->setTag('a')
->setText($branch_name)
->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(
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;
return $header;
}
}

View file

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

View file

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

View file

@ -16,11 +16,14 @@ final class DiffusionRepositoryController extends DiffusionController {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$content = array();
$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
// on a valid branch, and the repository is not empty.
@ -68,14 +71,24 @@ final class DiffusionRepositoryController extends DiffusionController {
}
if ($page_has_content) {
$content[] = $this->buildNormalContent($drequest);
$content = $this->buildNormalContent($drequest);
} else {
$content[] = id(new PHUIInfoView())
$content = id(new PHUIInfoView())
->setTitle($empty_title)
->setSeverity(PHUIInfoView::SEVERITY_WARNING)
->setErrors(array($empty_message));
}
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setCurtain($curtain)
->setMainColumn(array(
$property_table,
$description,
$locate_file,
))
->setFooter($content);
return $this->newPage()
->setTitle(
array(
@ -83,7 +96,9 @@ final class DiffusionRepositoryController extends DiffusionController {
$repository->getDisplayName(),
))
->setCrumbs($crumbs)
->appendChild($content);
->appendChild(array(
$view,
));
}
@ -206,13 +221,13 @@ final class DiffusionRepositoryController extends DiffusionController {
return $content;
}
private function buildPropertiesTable(PhabricatorRepository $repository) {
$user = $this->getRequest()->getUser();
private function buildHeaderView(PhabricatorRepository $repository) {
$viewer = $this->getViewer();
$header = id(new PHUIHeaderView())
->setHeader($repository->getName())
->setUser($user)
->setPolicyObject($repository);
->setUser($viewer)
->setPolicyObject($repository)
->setHeaderIcon('fa-code');
if (!$repository->isTracked()) {
$header->setStatus('fa-ban', 'dark', pht('Inactive'));
@ -227,12 +242,64 @@ final class DiffusionRepositoryController extends DiffusionController {
$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())
->setObject($repository)
->setUser($user);
->setUser($viewer);
if ($repository->isHosted()) {
$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())
->setHeader($header)
->addPropertyList($view);
->setHeaderText(pht('DETAILS'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->appendChild($view);
$info = null;
$drequest = $this->getDiffusionRequest();
@ -344,7 +400,7 @@ final class DiffusionRepositoryController extends DiffusionController {
}
private function buildBranchListTable(DiffusionRequest $drequest) {
$viewer = $this->getRequest()->getUser();
$viewer = $this->getViewer();
if ($drequest->getBranch() === null) {
return null;
@ -379,7 +435,8 @@ final class DiffusionRepositoryController extends DiffusionController {
->setBranches($branches)
->setCommits($commits);
$panel = new PHUIObjectBoxView();
$panel = id(new PHUIObjectBoxView())
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);
$header = new PHUIHeaderView();
$header->setHeader(pht('Branches'));
@ -388,7 +445,7 @@ final class DiffusionRepositoryController extends DiffusionController {
}
$button = new PHUIButtonView();
$button->setText(pht('Show All Branches'));
$button->setText(pht('Show All'));
$button->setTag('a');
$button->setIcon('fa-code-fork');
$button->setHref($drequest->generateURI(
@ -404,7 +461,7 @@ final class DiffusionRepositoryController extends DiffusionController {
}
private function buildTagListTable(DiffusionRequest $drequest) {
$viewer = $this->getRequest()->getUser();
$viewer = $this->getViewer();
$repository = $drequest->getRepository();
switch ($repository->getVersionControlSystem()) {
@ -469,46 +526,11 @@ final class DiffusionRepositoryController extends DiffusionController {
$panel->setHeader($header);
$panel->setTable($view);
$panel->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);
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(
$history_results,
$history,
@ -551,7 +573,7 @@ final class DiffusionRepositoryController extends DiffusionController {
->setIcon('fa-list-alt');
$button = id(new PHUIButtonView())
->setText(pht('View Full History'))
->setText(pht('View History'))
->setHref($drequest->generateURI(
array(
'action' => 'history',
@ -559,7 +581,8 @@ final class DiffusionRepositoryController extends DiffusionController {
->setTag('a')
->setIcon($icon);
$panel = new PHUIObjectBoxView();
$panel = id(new PHUIObjectBoxView())
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);
$header = id(new PHUIHeaderView())
->setHeader(pht('Recent Commits'))
->addActionLink($button);
@ -569,6 +592,46 @@ final class DiffusionRepositoryController extends DiffusionController {
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(
$browse_results,
$browse_paths,
@ -606,9 +669,10 @@ final class DiffusionRepositoryController extends DiffusionController {
$browse_uri = $drequest->generateURI(array('action' => 'browse'));
$browse_panel = new PHUIObjectBoxView();
$browse_panel = id(new PHUIObjectBoxView())
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);
$header = id(new PHUIHeaderView())
->setHeader(pht('Repository'));
->setHeader($repository->getName());
$icon = id(new PHUIIconView())
->setIcon('fa-folder-open');
@ -621,38 +685,6 @@ final class DiffusionRepositoryController extends DiffusionController {
$header->addActionLink($button);
$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);
$pager->setURI($browse_uri, 'offset');
@ -664,7 +696,6 @@ final class DiffusionRepositoryController extends DiffusionController {
}
return array(
$locate_panel,
$browse_panel,
$pager_box,
);

View file

@ -262,10 +262,26 @@ final class DiffusionRepositoryCreateController
$crumbs = $this->buildApplicationCrumbs();
$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()
->setTitle($title)
->setCrumbs($crumbs)
->appendChild($form);
->appendChild($view);
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -45,7 +45,10 @@ final class DiffusionRepositoryEditStagingController
$crumbs = $this->buildApplicationCrumbs();
$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())
->setUser($viewer)
@ -68,14 +71,21 @@ final class DiffusionRepositoryEditStagingController
->setValue(pht('Save'))
->addCancelButton($edit_uri));
$object_box = id(new PHUIObjectBoxView())
->setHeaderText($title)
$form_box = id(new PHUIObjectBoxView())
->setHeaderText(pht('Staging'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setForm($form);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter(array(
$form_box,
));
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
->appendChild($object_box);
->appendChild($view);
}
}

View file

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

View file

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

View file

@ -59,7 +59,10 @@ final class DiffusionRepositorySymbolsController
$crumbs = $this->buildApplicationCrumbs();
$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())
->setUser($viewer)
@ -85,15 +88,22 @@ final class DiffusionRepositorySymbolsController
->setValue(pht('Save'))
->addCancelButton($edit_uri));
$object_box = id(new PHUIObjectBoxView())
->setHeaderText($title)
$form_box = id(new PHUIObjectBoxView())
->setHeaderText(pht('Symbols'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setForm($form)
->setFormErrors($errors);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter(array(
$form_box,
));
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
->appendChild($object_box);
->appendChild($view);
}
private function getInstructions() {

View file

@ -5,7 +5,12 @@ final class DiffusionServeController extends DiffusionController {
private $serviceViewer;
private $serviceRepository;
private $isGitLFSRequest;
private $gitLFSToken;
public function setServiceViewer(PhabricatorUser $viewer) {
$this->getRequest()->setUser($viewer);
$this->serviceViewer = $viewer;
return $this;
}
@ -23,6 +28,14 @@ final class DiffusionServeController extends DiffusionController {
return $this->serviceRepository;
}
public function getIsGitLFSRequest() {
return $this->isGitLFSRequest;
}
public function getGitLFSToken() {
return $this->gitLFSToken;
}
public function isVCSRequest(AphrontRequest $request) {
$identifier = $this->getRepositoryIdentifierFromRequest($request);
if ($identifier === null) {
@ -31,6 +44,10 @@ final class DiffusionServeController extends DiffusionController {
$content_type = $request->getHTTPHeader('Content-Type');
$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;
if ($request->getExists('service')) {
@ -46,6 +63,14 @@ final class DiffusionServeController extends DiffusionController {
} else if ($content_type == 'application/x-git-receive-pack-request') {
// We get this for `git-receive-pack`.
$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')) {
// Mercurial also sends an Accept header like
// "application/mercurial-0.1", and a User-Agent like
@ -142,7 +167,17 @@ final class DiffusionServeController extends DiffusionController {
$username = $_SERVER['PHP_AUTH_USER'];
$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);
}
if (!$viewer) {
return new PhabricatorVCSResponse(
403,
@ -202,6 +237,11 @@ final class DiffusionServeController extends DiffusionController {
}
}
$response = $this->validateGitLFSRequest($repository, $viewer);
if ($response) {
return $response;
}
$this->setServiceRepository($repository);
if (!$repository->isTracked()) {
@ -212,6 +252,12 @@ final class DiffusionServeController extends DiffusionController {
$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()) {
case PhabricatorRepository::SERVE_READONLY:
if ($is_push) {
@ -221,6 +267,16 @@ final class DiffusionServeController extends DiffusionController {
}
break;
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) {
$can_push = PhabricatorPolicyFilter::hasCapability(
$viewer,
@ -230,7 +286,9 @@ final class DiffusionServeController extends DiffusionController {
if ($viewer->isLoggedIn()) {
return new PhabricatorVCSResponse(
403,
pht('You do not have permission to push to this repository.'));
pht(
'You do not have permission to push to this '.
'repository.'));
} else {
if ($allow_auth) {
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();
$req_type = $this->isVCSRequest($request);
@ -324,6 +375,14 @@ final class DiffusionServeController extends DiffusionController {
PhabricatorRepository $repository,
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
// to a host which can serve it.
$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 doesn't get the right result for Git LFS yet.
switch ($repository->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$service = $request->getStr('service');
@ -514,6 +575,52 @@ final class DiffusionServeController extends DiffusionController {
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(
$username,
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(
pht('No matching symbol could be found in any indexed repository.'));
$panel = id(new PHUIObjectBoxView())
->setHeaderText(pht('Similar Symbols'))
->setTable($table);
$header = id(new PHUIHeaderView())
->setHeader(pht('Similar Symbols'))
->setHeaderIcon('fa-bullseye');
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Find Symbol'));
$crumbs->setBorder(true);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter(array(
$table,
));
return $this->newPage()
->setTitle(pht('Find Symbol'))
->setCrumbs($crumbs)
->appendChild($panel);
->appendChild($view);
}
}

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

@ -95,7 +95,9 @@ abstract class DiffusionView extends AphrontView {
}
$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 ($display_name !== null) {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -26,7 +26,6 @@ final class PhabricatorFile extends PhabricatorFileDAO
PhabricatorPolicyInterface,
PhabricatorDestructibleInterface {
const ONETIME_TEMPORARY_TOKEN_TYPE = 'file:onetime';
const STORAGE_FORMAT_RAW = 'raw';
const METADATA_IMAGE_WIDTH = 'width';
@ -1119,12 +1118,13 @@ final class PhabricatorFile extends PhabricatorFileDAO
protected function generateOneTimeToken() {
$key = Filesystem::readRandomCharacters(16);
$token_type = PhabricatorFileAccessTemporaryTokenType::TOKENTYPE;
// Save the new secret.
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
$token = id(new PhabricatorAuthTemporaryToken())
->setObjectPHID($this->getPHID())
->setTokenType(self::ONETIME_TEMPORARY_TOKEN_TYPE)
->setTokenResource($this->getPHID())
->setTokenType($token_type)
->setTokenExpires(time() + phutil_units('1 hour in seconds'))
->setTokenCode(PhabricatorHash::digest($key))
->save();
@ -1134,10 +1134,12 @@ final class PhabricatorFile extends PhabricatorFileDAO
}
public function validateOneTimeToken($token_code) {
$token_type = PhabricatorFileAccessTemporaryTokenType::TOKENTYPE;
$token = id(new PhabricatorAuthTemporaryTokenQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withObjectPHIDs(array($this->getPHID()))
->withTokenTypes(array(self::ONETIME_TEMPORARY_TOKEN_TYPE))
->withTokenResources(array($this->getPHID()))
->withTokenTypes(array($token_type))
->withExpired(false)
->withTokenCodes(array(PhabricatorHash::digest($token_code)))
->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();
$this->didRewind = true;
} else {
if ($data->valid()) {
$data->next();
}
}
if (!$data->valid()) {
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 $excuse;
private $showViewAll;
private $background;
public function setBuildable(HarbormasterBuildable $buildable) {
$this->buildable = $buildable;
@ -33,6 +34,11 @@ final class HarbormasterUnitSummaryView extends AphrontView {
return $this;
}
public function setBackground($background) {
$this->background = $background;
return $this;
}
public function render() {
$messages = $this->messages;
$buildable = $this->buildable;
@ -54,9 +60,14 @@ final class HarbormasterUnitSummaryView extends AphrontView {
$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())
->setHeader(pht('Unit Tests'))
->setStatus($tag_icon, $tag_color, $tag_text);
->setHeader(array(pht('Unit Tests'), $tag));
if ($this->showViewAll) {
$view_all = id(new PHUIButtonView())
@ -98,6 +109,10 @@ final class HarbormasterUnitSummaryView extends AphrontView {
$box->setTable($table);
if ($this->background) {
$box->setBackground($this->background);
}
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
// an account, changes the email address, and sends themselves a password
// reset link, it could otherwise remain live for a short period of time
@ -710,8 +710,8 @@ final class PhabricatorUserEditor extends PhabricatorEditor {
$user,
array($user->getPHID()),
array(
PhabricatorAuthSessionEngine::ONETIME_TEMPORARY_TOKEN_TYPE,
PhabricatorAuthSessionEngine::PASSWORD_TEMPORARY_TOKEN_TYPE,
PhabricatorAuthOneTimeLoginTemporaryTokenType::TOKENTYPE,
PhabricatorAuthPasswordResetTemporaryTokenType::TOKENTYPE,
));
}

View file

@ -742,6 +742,38 @@ final class PhabricatorUser
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) {
$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) {
$engine = $this->getEngine();
$viewer = $engine->getConfig('viewer');
$text_mode = $engine->isTextMode();
$html_mode = $engine->isHTMLMailMode();
if (!$this->isFlatText($matches[0])) {
return $matches[0];
@ -28,46 +30,45 @@ final class PhabricatorPhurlLinkRemarkupRule extends PhutilRemarkupRule {
$monogram = null;
$is_monogram = '/^U(?P<id>[1-9]\d*)/';
$query = id(new PhabricatorPhurlURLQuery())
->setViewer($viewer);
if (preg_match($is_monogram, $ref, $monogram)) {
$phurls = id(new PhabricatorPhurlURLQuery())
->setViewer($viewer)
->withIDs(array($monogram[1]))
->execute();
$query->withIDs(array($monogram[1]));
} else if (ctype_digit($ref)) {
$phurls = id(new PhabricatorPhurlURLQuery())
->setViewer($viewer)
->withIDs(array($ref))
->execute();
$query->withIDs(array($ref));
} else {
$phurls = id(new PhabricatorPhurlURLQuery())
->setViewer($viewer)
->withAliases(array($ref))
->execute();
$query->withAliases(array($ref));
}
$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) {
return $phurl->getDisplayName().
' <'.
$phurl->getRedirectURI().
'>';
}
return pht(
'%s <%s>',
$name,
$uri);
} else {
$link = phutil_tag(
'a',
array(
'href' => $phurl->getRedirectURI(),
'href' => $uri,
'target' => '_blank',
),
$phurl->getDisplayName());
$name);
}
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 $this->getRawHTTPCloneURIObject();
}
private function getRawHTTPCloneURIObject() {
$uri = PhabricatorEnv::getProductionURI($this->getURI());
$uri = new PhutilURI($uri);
@ -1819,6 +1823,38 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
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() {
if ($this->isGit() || $this->isHg()) {
return true;
@ -2399,6 +2435,14 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
$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();
}

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(
'columns' => array('repositoryID', 'pathID', 'commitSequence'),
),
'key_history' => array(
'columns' => array('commitID', 'isDirect', 'changeType'),
),
));
$this->buildRawSchema(

View file

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

View file

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

View file

@ -4,6 +4,9 @@ final class PHUIDiffTableOfContentsListView extends AphrontView {
private $items = array();
private $authorityPackages;
private $header;
private $infoView;
private $background;
public function addItem(PHUIDiffTableOfContentsItemView $item) {
$this->items[] = $item;
@ -20,6 +23,21 @@ final class PHUIDiffTableOfContentsListView extends AphrontView {
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() {
$this->requireResource('differential-core-view-css');
$this->requireResource('differential-table-of-contents-css');
@ -142,11 +160,24 @@ final class PHUIDiffTableOfContentsListView extends AphrontView {
->setAnchorName('toc')
->setNavigationMarker(true);
return id(new PHUIObjectBoxView())
->setHeaderText(pht('Table of Contents'))
$header = id(new PHUIHeaderView())
->setHeader(pht('Table of Contents'));
if ($this->header) {
$header = $this->header;
}
$box = id(new PHUIObjectBoxView())
->setHeader($header)
->setBackground($this->background)
->setTable($table)
->appendChild($anchor)
->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 PhabricatorEmojiRemarkupRule();
$rules[] = new PhabricatorHandleRemarkupRule();
$applications = PhabricatorApplication::getAllInstalledApplications();
foreach ($applications as $application) {

View file

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

View file

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

View file

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

View file

@ -83,6 +83,26 @@ final class PhabricatorStartup {
* @task info
*/
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;
}
@ -128,47 +148,6 @@ final class PhabricatorStartup {
self::detectPostMaxSizeTriggered();
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 {
position: relative;
margin: 0;
padding-top: 32px;
padding-top: 16px;
overflow-x: auto;
/* Fixes what seems to be a layout bug in Firefox which causes scrollbars,
@ -265,7 +265,7 @@ td.cov-I {
.differential-changeset h1 {
font-size: {$biggestfontsize};
padding: 2px 0 12px 12px;
padding: 2px 0 20px 12px;
line-height: 20px;
color: #000;
}
@ -322,7 +322,7 @@ td.cov-I {
.differential-changeset-buttons {
float: right;
margin-right: 8px;
margin-right: 12px;
}
.device-phone .differential-changeset-buttons {
@ -362,3 +362,7 @@ tr.differential-inline-hidden {
tr.differential-inline-loading {
opacity: 0.5;
}
.differential-review-stage {
position: relative;
}

View file

@ -3,7 +3,7 @@
*/
.differential-primary-pane {
margin-bottom: 32px;
margin-top: -20px;
}
.differential-panel {
@ -23,3 +23,7 @@
-ms-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