mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-01 19:22:42 +01:00
(stable) Promote 2016 Week 3
This commit is contained in:
commit
eac1124bd9
119 changed files with 3303 additions and 2995 deletions
105
externals/s3/README.txt
vendored
105
externals/s3/README.txt
vendored
|
@ -1,105 +0,0 @@
|
||||||
AMAZON S3 PHP CLASS
|
|
||||||
|
|
||||||
|
|
||||||
USING THE CLASS
|
|
||||||
|
|
||||||
OO method (e,g; $s3->getObject(...)):
|
|
||||||
$s3 = new S3(awsAccessKey, awsSecretKey);
|
|
||||||
|
|
||||||
Statically (e,g; S3::getObject(...)):
|
|
||||||
S3::setAuth(awsAccessKey, awsSecretKey);
|
|
||||||
|
|
||||||
|
|
||||||
For class documentation see:
|
|
||||||
http://undesigned.org.za/files/s3-class-documentation/index.html
|
|
||||||
|
|
||||||
|
|
||||||
OBJECTS
|
|
||||||
|
|
||||||
|
|
||||||
Put an object from a string:
|
|
||||||
$s3->putObject($string, $bucketName, $uploadName, S3::ACL_PUBLIC_READ)
|
|
||||||
Legacy function: $s3->putObjectString($string, $bucketName, $uploadName, S3::ACL_PUBLIC_READ)
|
|
||||||
|
|
||||||
|
|
||||||
Put an object from a file:
|
|
||||||
$s3->putObject($s3->inputFile($file, false), $bucketName, $uploadName, S3::ACL_PUBLIC_READ)
|
|
||||||
Legacy function: $s3->putObjectFile($uploadFile, $bucketName, $uploadName, S3::ACL_PUBLIC_READ)
|
|
||||||
|
|
||||||
|
|
||||||
Put an object from a resource (buffer/file size is required):
|
|
||||||
Please note: the resource will be fclose()'d automatically
|
|
||||||
$s3->putObject($s3->inputResource(fopen($file, 'rb'), filesize($file)), $bucketName, $uploadName, S3::ACL_PUBLIC_READ)
|
|
||||||
|
|
||||||
|
|
||||||
Get an object:
|
|
||||||
$s3->getObject($bucketName, $uploadName)
|
|
||||||
|
|
||||||
|
|
||||||
Save an object to file:
|
|
||||||
$s3->getObject($bucketName, $uploadName, $saveName)
|
|
||||||
|
|
||||||
|
|
||||||
Save an object to a resource of any type:
|
|
||||||
$s3->getObject($bucketName, $uploadName, fopen('savefile.txt', 'wb'))
|
|
||||||
|
|
||||||
|
|
||||||
Copy an object:
|
|
||||||
$s3->copyObject($srcBucket, $srcName, $bucketName, $saveName, $metaHeaders = array(), $requestHeaders = array())
|
|
||||||
|
|
||||||
|
|
||||||
Delete an object:
|
|
||||||
$s3->deleteObject($bucketName, $uploadName)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BUCKETS
|
|
||||||
|
|
||||||
|
|
||||||
Get a list of buckets:
|
|
||||||
$s3->listBuckets() // Simple bucket list
|
|
||||||
$s3->listBuckets(true) // Detailed bucket list
|
|
||||||
|
|
||||||
|
|
||||||
Create a public-read bucket:
|
|
||||||
$s3->putBucket($bucketName, S3::ACL_PUBLIC_READ)
|
|
||||||
$s3->putBucket($bucketName, S3::ACL_PUBLIC_READ, 'EU') // EU-hosted bucket
|
|
||||||
|
|
||||||
|
|
||||||
Get the contents of a bucket:
|
|
||||||
$s3->getBucket($bucketName)
|
|
||||||
|
|
||||||
|
|
||||||
Get a bucket's location:
|
|
||||||
$s3->getBucketLocation($bucketName)
|
|
||||||
|
|
||||||
|
|
||||||
Delete a bucket:
|
|
||||||
$s3->deleteBucket($bucketName)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
KNOWN ISSUES
|
|
||||||
|
|
||||||
Files larger than 2GB are not supported on 32 bit systems due to PHP’s signed integer problem
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
MORE INFORMATION
|
|
||||||
|
|
||||||
|
|
||||||
Project URL:
|
|
||||||
http://undesigned.org.za/2007/10/22/amazon-s3-php-class
|
|
||||||
|
|
||||||
Class documentation:
|
|
||||||
http://undesigned.org.za/files/s3-class-documentation/index.html
|
|
||||||
|
|
||||||
Bug reports:
|
|
||||||
https://github.com/tpyo/amazon-s3-php-class/issues
|
|
||||||
|
|
||||||
Amazon S3 documentation:
|
|
||||||
http://docs.amazonwebservices.com/AmazonS3/2006-03-01/
|
|
||||||
|
|
||||||
|
|
||||||
EOF
|
|
2317
externals/s3/S3.php
vendored
2317
externals/s3/S3.php
vendored
File diff suppressed because it is too large
Load diff
|
@ -7,11 +7,11 @@
|
||||||
*/
|
*/
|
||||||
return array(
|
return array(
|
||||||
'names' => array(
|
'names' => array(
|
||||||
'core.pkg.css' => '3ea6dc33',
|
'core.pkg.css' => '1eed0b4f',
|
||||||
'core.pkg.js' => '57dff7df',
|
'core.pkg.js' => '6ae03393',
|
||||||
'darkconsole.pkg.js' => 'e7393ebb',
|
'darkconsole.pkg.js' => 'e7393ebb',
|
||||||
'differential.pkg.css' => '2de124c9',
|
'differential.pkg.css' => '2de124c9',
|
||||||
'differential.pkg.js' => '64e69521',
|
'differential.pkg.js' => 'f83532f8',
|
||||||
'diffusion.pkg.css' => 'f45955ed',
|
'diffusion.pkg.css' => 'f45955ed',
|
||||||
'diffusion.pkg.js' => '3a9a8bfa',
|
'diffusion.pkg.js' => '3a9a8bfa',
|
||||||
'maniphest.pkg.css' => '4845691a',
|
'maniphest.pkg.css' => '4845691a',
|
||||||
|
@ -102,7 +102,7 @@ return array(
|
||||||
'rsrc/css/application/tokens/tokens.css' => '3d0f239e',
|
'rsrc/css/application/tokens/tokens.css' => '3d0f239e',
|
||||||
'rsrc/css/application/uiexample/example.css' => '528b19de',
|
'rsrc/css/application/uiexample/example.css' => '528b19de',
|
||||||
'rsrc/css/core/core.css' => 'a76cefc9',
|
'rsrc/css/core/core.css' => 'a76cefc9',
|
||||||
'rsrc/css/core/remarkup.css' => '7afb543c',
|
'rsrc/css/core/remarkup.css' => 'b6ad82e4',
|
||||||
'rsrc/css/core/syntax.css' => '9fd11da8',
|
'rsrc/css/core/syntax.css' => '9fd11da8',
|
||||||
'rsrc/css/core/z-index.css' => '57ddcaa2',
|
'rsrc/css/core/z-index.css' => '57ddcaa2',
|
||||||
'rsrc/css/diviner/diviner-shared.css' => 'aa3656aa',
|
'rsrc/css/diviner/diviner-shared.css' => 'aa3656aa',
|
||||||
|
@ -375,13 +375,13 @@ return array(
|
||||||
'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => '82439934',
|
'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => '82439934',
|
||||||
'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '453c5375',
|
'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '453c5375',
|
||||||
'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => 'd4eecc63',
|
'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => 'd4eecc63',
|
||||||
'rsrc/js/application/differential/ChangesetViewManager.js' => '58562350',
|
'rsrc/js/application/differential/ChangesetViewManager.js' => 'a2828756',
|
||||||
'rsrc/js/application/differential/DifferentialInlineCommentEditor.js' => '64a5550f',
|
'rsrc/js/application/differential/DifferentialInlineCommentEditor.js' => '64a5550f',
|
||||||
'rsrc/js/application/differential/behavior-add-reviewers-and-ccs.js' => 'e10f8e18',
|
'rsrc/js/application/differential/behavior-add-reviewers-and-ccs.js' => 'e10f8e18',
|
||||||
'rsrc/js/application/differential/behavior-comment-jump.js' => '4fdb476d',
|
'rsrc/js/application/differential/behavior-comment-jump.js' => '4fdb476d',
|
||||||
'rsrc/js/application/differential/behavior-comment-preview.js' => 'b064af76',
|
'rsrc/js/application/differential/behavior-comment-preview.js' => 'b064af76',
|
||||||
'rsrc/js/application/differential/behavior-diff-radios.js' => 'e1ff79b1',
|
'rsrc/js/application/differential/behavior-diff-radios.js' => 'e1ff79b1',
|
||||||
'rsrc/js/application/differential/behavior-dropdown-menus.js' => '2035b9cb',
|
'rsrc/js/application/differential/behavior-dropdown-menus.js' => '9a6b9324',
|
||||||
'rsrc/js/application/differential/behavior-edit-inline-comments.js' => '65ef6074',
|
'rsrc/js/application/differential/behavior-edit-inline-comments.js' => '65ef6074',
|
||||||
'rsrc/js/application/differential/behavior-keyboard-nav.js' => '2c426492',
|
'rsrc/js/application/differential/behavior-keyboard-nav.js' => '2c426492',
|
||||||
'rsrc/js/application/differential/behavior-populate.js' => '8694b1df',
|
'rsrc/js/application/differential/behavior-populate.js' => '8694b1df',
|
||||||
|
@ -424,9 +424,10 @@ return array(
|
||||||
'rsrc/js/application/releeph/releeph-request-state-change.js' => 'a0b57eb8',
|
'rsrc/js/application/releeph/releeph-request-state-change.js' => 'a0b57eb8',
|
||||||
'rsrc/js/application/releeph/releeph-request-typeahead.js' => 'de2e896f',
|
'rsrc/js/application/releeph/releeph-request-typeahead.js' => 'de2e896f',
|
||||||
'rsrc/js/application/repository/repository-crossreference.js' => 'e5339c43',
|
'rsrc/js/application/repository/repository-crossreference.js' => 'e5339c43',
|
||||||
|
'rsrc/js/application/search/behavior-reorder-profile-menu-items.js' => 'e2e0a072',
|
||||||
'rsrc/js/application/search/behavior-reorder-queries.js' => 'e9581f08',
|
'rsrc/js/application/search/behavior-reorder-queries.js' => 'e9581f08',
|
||||||
'rsrc/js/application/slowvote/behavior-slowvote-embed.js' => '887ad43f',
|
'rsrc/js/application/slowvote/behavior-slowvote-embed.js' => '887ad43f',
|
||||||
'rsrc/js/application/transactions/behavior-comment-actions.js' => 'b65559c0',
|
'rsrc/js/application/transactions/behavior-comment-actions.js' => '1f2fcaf8',
|
||||||
'rsrc/js/application/transactions/behavior-reorder-configs.js' => 'd7a74243',
|
'rsrc/js/application/transactions/behavior-reorder-configs.js' => 'd7a74243',
|
||||||
'rsrc/js/application/transactions/behavior-reorder-fields.js' => 'b59e1e96',
|
'rsrc/js/application/transactions/behavior-reorder-fields.js' => 'b59e1e96',
|
||||||
'rsrc/js/application/transactions/behavior-show-older-transactions.js' => 'dbbf48b6',
|
'rsrc/js/application/transactions/behavior-show-older-transactions.js' => 'dbbf48b6',
|
||||||
|
@ -492,7 +493,7 @@ return array(
|
||||||
'rsrc/js/core/behavior-reorder-applications.js' => '76b9fc3e',
|
'rsrc/js/core/behavior-reorder-applications.js' => '76b9fc3e',
|
||||||
'rsrc/js/core/behavior-reveal-content.js' => '60821bc7',
|
'rsrc/js/core/behavior-reveal-content.js' => '60821bc7',
|
||||||
'rsrc/js/core/behavior-scrollbar.js' => '834a1173',
|
'rsrc/js/core/behavior-scrollbar.js' => '834a1173',
|
||||||
'rsrc/js/core/behavior-search-typeahead.js' => '048330fa',
|
'rsrc/js/core/behavior-search-typeahead.js' => '0b7a4f6e',
|
||||||
'rsrc/js/core/behavior-select-on-click.js' => '4e3e79a6',
|
'rsrc/js/core/behavior-select-on-click.js' => '4e3e79a6',
|
||||||
'rsrc/js/core/behavior-time-typeahead.js' => 'f80d6bf0',
|
'rsrc/js/core/behavior-time-typeahead.js' => 'f80d6bf0',
|
||||||
'rsrc/js/core/behavior-toggle-class.js' => '5d7c9f33',
|
'rsrc/js/core/behavior-toggle-class.js' => '5d7c9f33',
|
||||||
|
@ -523,7 +524,7 @@ return array(
|
||||||
'aphront-typeahead-control-css' => '0e403212',
|
'aphront-typeahead-control-css' => '0e403212',
|
||||||
'auth-css' => '0877ed6e',
|
'auth-css' => '0877ed6e',
|
||||||
'bulk-job-css' => 'df9c1d4a',
|
'bulk-job-css' => 'df9c1d4a',
|
||||||
'changeset-view-manager' => '58562350',
|
'changeset-view-manager' => 'a2828756',
|
||||||
'conduit-api-css' => '7bc725c4',
|
'conduit-api-css' => '7bc725c4',
|
||||||
'config-options-css' => '0ede4c9b',
|
'config-options-css' => '0ede4c9b',
|
||||||
'config-welcome-css' => '6abd79be',
|
'config-welcome-css' => '6abd79be',
|
||||||
|
@ -570,7 +571,7 @@ return array(
|
||||||
'javelin-behavior-audit-preview' => 'd835b03a',
|
'javelin-behavior-audit-preview' => 'd835b03a',
|
||||||
'javelin-behavior-bulk-job-reload' => 'edf8a145',
|
'javelin-behavior-bulk-job-reload' => 'edf8a145',
|
||||||
'javelin-behavior-choose-control' => '327a00d1',
|
'javelin-behavior-choose-control' => '327a00d1',
|
||||||
'javelin-behavior-comment-actions' => 'b65559c0',
|
'javelin-behavior-comment-actions' => '1f2fcaf8',
|
||||||
'javelin-behavior-config-reorder-fields' => 'b6993408',
|
'javelin-behavior-config-reorder-fields' => 'b6993408',
|
||||||
'javelin-behavior-conpherence-drag-and-drop-photo' => 'cf86d16a',
|
'javelin-behavior-conpherence-drag-and-drop-photo' => 'cf86d16a',
|
||||||
'javelin-behavior-conpherence-menu' => '1d45c74d',
|
'javelin-behavior-conpherence-menu' => '1d45c74d',
|
||||||
|
@ -588,7 +589,7 @@ return array(
|
||||||
'javelin-behavior-differential-add-reviewers-and-ccs' => 'e10f8e18',
|
'javelin-behavior-differential-add-reviewers-and-ccs' => 'e10f8e18',
|
||||||
'javelin-behavior-differential-comment-jump' => '4fdb476d',
|
'javelin-behavior-differential-comment-jump' => '4fdb476d',
|
||||||
'javelin-behavior-differential-diff-radios' => 'e1ff79b1',
|
'javelin-behavior-differential-diff-radios' => 'e1ff79b1',
|
||||||
'javelin-behavior-differential-dropdown-menus' => '2035b9cb',
|
'javelin-behavior-differential-dropdown-menus' => '9a6b9324',
|
||||||
'javelin-behavior-differential-edit-inline-comments' => '65ef6074',
|
'javelin-behavior-differential-edit-inline-comments' => '65ef6074',
|
||||||
'javelin-behavior-differential-feedback-preview' => 'b064af76',
|
'javelin-behavior-differential-feedback-preview' => 'b064af76',
|
||||||
'javelin-behavior-differential-keyboard-navigation' => '2c426492',
|
'javelin-behavior-differential-keyboard-navigation' => '2c426492',
|
||||||
|
@ -640,7 +641,7 @@ return array(
|
||||||
'javelin-behavior-phabricator-oncopy' => '2926fff2',
|
'javelin-behavior-phabricator-oncopy' => '2926fff2',
|
||||||
'javelin-behavior-phabricator-remarkup-assist' => 'b60b6d9b',
|
'javelin-behavior-phabricator-remarkup-assist' => 'b60b6d9b',
|
||||||
'javelin-behavior-phabricator-reveal-content' => '60821bc7',
|
'javelin-behavior-phabricator-reveal-content' => '60821bc7',
|
||||||
'javelin-behavior-phabricator-search-typeahead' => '048330fa',
|
'javelin-behavior-phabricator-search-typeahead' => '0b7a4f6e',
|
||||||
'javelin-behavior-phabricator-show-older-transactions' => 'dbbf48b6',
|
'javelin-behavior-phabricator-show-older-transactions' => 'dbbf48b6',
|
||||||
'javelin-behavior-phabricator-tooltips' => '3ee3408b',
|
'javelin-behavior-phabricator-tooltips' => '3ee3408b',
|
||||||
'javelin-behavior-phabricator-transaction-comment-form' => 'b23b49e6',
|
'javelin-behavior-phabricator-transaction-comment-form' => 'b23b49e6',
|
||||||
|
@ -663,6 +664,7 @@ return array(
|
||||||
'javelin-behavior-remarkup-preview' => '4b700e9e',
|
'javelin-behavior-remarkup-preview' => '4b700e9e',
|
||||||
'javelin-behavior-reorder-applications' => '76b9fc3e',
|
'javelin-behavior-reorder-applications' => '76b9fc3e',
|
||||||
'javelin-behavior-reorder-columns' => 'e1d25dfb',
|
'javelin-behavior-reorder-columns' => 'e1d25dfb',
|
||||||
|
'javelin-behavior-reorder-profile-menu-items' => 'e2e0a072',
|
||||||
'javelin-behavior-repository-crossreference' => 'e5339c43',
|
'javelin-behavior-repository-crossreference' => 'e5339c43',
|
||||||
'javelin-behavior-scrollbar' => '834a1173',
|
'javelin-behavior-scrollbar' => '834a1173',
|
||||||
'javelin-behavior-search-reorder-queries' => 'e9581f08',
|
'javelin-behavior-search-reorder-queries' => 'e9581f08',
|
||||||
|
@ -757,7 +759,7 @@ return array(
|
||||||
'phabricator-object-selector-css' => '85ee8ce6',
|
'phabricator-object-selector-css' => '85ee8ce6',
|
||||||
'phabricator-phtize' => 'd254d646',
|
'phabricator-phtize' => 'd254d646',
|
||||||
'phabricator-prefab' => '666c80c5',
|
'phabricator-prefab' => '666c80c5',
|
||||||
'phabricator-remarkup-css' => '7afb543c',
|
'phabricator-remarkup-css' => 'b6ad82e4',
|
||||||
'phabricator-search-results-css' => '7dea472c',
|
'phabricator-search-results-css' => '7dea472c',
|
||||||
'phabricator-shaped-request' => '7cbe244b',
|
'phabricator-shaped-request' => '7cbe244b',
|
||||||
'phabricator-side-menu-view-css' => '91b7a42c',
|
'phabricator-side-menu-view-css' => '91b7a42c',
|
||||||
|
@ -878,16 +880,6 @@ return array(
|
||||||
'javelin-behavior-device',
|
'javelin-behavior-device',
|
||||||
'phabricator-title',
|
'phabricator-title',
|
||||||
),
|
),
|
||||||
'048330fa' => array(
|
|
||||||
'javelin-behavior',
|
|
||||||
'javelin-typeahead-ondemand-source',
|
|
||||||
'javelin-typeahead',
|
|
||||||
'javelin-dom',
|
|
||||||
'javelin-uri',
|
|
||||||
'javelin-util',
|
|
||||||
'javelin-stratcom',
|
|
||||||
'phabricator-prefab',
|
|
||||||
),
|
|
||||||
'05270951' => array(
|
'05270951' => array(
|
||||||
'javelin-util',
|
'javelin-util',
|
||||||
'javelin-magical-init',
|
'javelin-magical-init',
|
||||||
|
@ -915,6 +907,16 @@ return array(
|
||||||
'javelin-dom',
|
'javelin-dom',
|
||||||
'javelin-router',
|
'javelin-router',
|
||||||
),
|
),
|
||||||
|
'0b7a4f6e' => array(
|
||||||
|
'javelin-behavior',
|
||||||
|
'javelin-typeahead-ondemand-source',
|
||||||
|
'javelin-typeahead',
|
||||||
|
'javelin-dom',
|
||||||
|
'javelin-uri',
|
||||||
|
'javelin-util',
|
||||||
|
'javelin-stratcom',
|
||||||
|
'phabricator-prefab',
|
||||||
|
),
|
||||||
'0f764c35' => array(
|
'0f764c35' => array(
|
||||||
'javelin-install',
|
'javelin-install',
|
||||||
'javelin-util',
|
'javelin-util',
|
||||||
|
@ -969,17 +971,14 @@ return array(
|
||||||
'javelin-dom',
|
'javelin-dom',
|
||||||
'javelin-reactor-dom',
|
'javelin-reactor-dom',
|
||||||
),
|
),
|
||||||
'2035b9cb' => array(
|
'1f2fcaf8' => array(
|
||||||
'javelin-behavior',
|
'javelin-behavior',
|
||||||
'javelin-dom',
|
|
||||||
'javelin-util',
|
|
||||||
'javelin-stratcom',
|
'javelin-stratcom',
|
||||||
'javelin-workflow',
|
'javelin-workflow',
|
||||||
'phuix-dropdown-menu',
|
'javelin-dom',
|
||||||
'phuix-action-list-view',
|
'phuix-form-control-view',
|
||||||
'phuix-action-view',
|
'phuix-icon-view',
|
||||||
'phabricator-phtize',
|
'javelin-behavior-phabricator-gesture',
|
||||||
'changeset-view-manager',
|
|
||||||
),
|
),
|
||||||
'21ba5861' => array(
|
'21ba5861' => array(
|
||||||
'javelin-behavior',
|
'javelin-behavior',
|
||||||
|
@ -1201,16 +1200,6 @@ return array(
|
||||||
'javelin-request',
|
'javelin-request',
|
||||||
'javelin-util',
|
'javelin-util',
|
||||||
),
|
),
|
||||||
58562350 => array(
|
|
||||||
'javelin-dom',
|
|
||||||
'javelin-util',
|
|
||||||
'javelin-stratcom',
|
|
||||||
'javelin-install',
|
|
||||||
'javelin-workflow',
|
|
||||||
'javelin-router',
|
|
||||||
'javelin-behavior-device',
|
|
||||||
'javelin-vector',
|
|
||||||
),
|
|
||||||
'59a7976a' => array(
|
'59a7976a' => array(
|
||||||
'javelin-install',
|
'javelin-install',
|
||||||
'javelin-dom',
|
'javelin-dom',
|
||||||
|
@ -1562,6 +1551,18 @@ return array(
|
||||||
'javelin-dom',
|
'javelin-dom',
|
||||||
'javelin-reactor-dom',
|
'javelin-reactor-dom',
|
||||||
),
|
),
|
||||||
|
'9a6b9324' => array(
|
||||||
|
'javelin-behavior',
|
||||||
|
'javelin-dom',
|
||||||
|
'javelin-util',
|
||||||
|
'javelin-stratcom',
|
||||||
|
'javelin-workflow',
|
||||||
|
'phuix-dropdown-menu',
|
||||||
|
'phuix-action-list-view',
|
||||||
|
'phuix-action-view',
|
||||||
|
'phabricator-phtize',
|
||||||
|
'changeset-view-manager',
|
||||||
|
),
|
||||||
'9e54692d' => array(
|
'9e54692d' => array(
|
||||||
'javelin-install',
|
'javelin-install',
|
||||||
'javelin-dom',
|
'javelin-dom',
|
||||||
|
@ -1601,6 +1602,16 @@ return array(
|
||||||
'javelin-vector',
|
'javelin-vector',
|
||||||
'javelin-install',
|
'javelin-install',
|
||||||
),
|
),
|
||||||
|
'a2828756' => array(
|
||||||
|
'javelin-dom',
|
||||||
|
'javelin-util',
|
||||||
|
'javelin-stratcom',
|
||||||
|
'javelin-install',
|
||||||
|
'javelin-workflow',
|
||||||
|
'javelin-router',
|
||||||
|
'javelin-behavior-device',
|
||||||
|
'javelin-vector',
|
||||||
|
),
|
||||||
'a464fe03' => array(
|
'a464fe03' => array(
|
||||||
'javelin-behavior',
|
'javelin-behavior',
|
||||||
'javelin-uri',
|
'javelin-uri',
|
||||||
|
@ -1740,15 +1751,6 @@ return array(
|
||||||
'javelin-workflow',
|
'javelin-workflow',
|
||||||
'javelin-vector',
|
'javelin-vector',
|
||||||
),
|
),
|
||||||
'b65559c0' => array(
|
|
||||||
'javelin-behavior',
|
|
||||||
'javelin-stratcom',
|
|
||||||
'javelin-workflow',
|
|
||||||
'javelin-dom',
|
|
||||||
'phuix-form-control-view',
|
|
||||||
'phuix-icon-view',
|
|
||||||
'javelin-behavior-phabricator-gesture',
|
|
||||||
),
|
|
||||||
'b6993408' => array(
|
'b6993408' => array(
|
||||||
'javelin-behavior',
|
'javelin-behavior',
|
||||||
'javelin-stratcom',
|
'javelin-stratcom',
|
||||||
|
@ -1933,6 +1935,13 @@ return array(
|
||||||
'e292eaf4' => array(
|
'e292eaf4' => array(
|
||||||
'javelin-install',
|
'javelin-install',
|
||||||
),
|
),
|
||||||
|
'e2e0a072' => array(
|
||||||
|
'javelin-behavior',
|
||||||
|
'javelin-stratcom',
|
||||||
|
'javelin-workflow',
|
||||||
|
'javelin-dom',
|
||||||
|
'phabricator-draggable-list',
|
||||||
|
),
|
||||||
'e379b58e' => array(
|
'e379b58e' => array(
|
||||||
'javelin-behavior',
|
'javelin-behavior',
|
||||||
'javelin-stratcom',
|
'javelin-stratcom',
|
||||||
|
|
5
resources/sql/autopatches/20160110.repo.01.slug.sql
Normal file
5
resources/sql/autopatches/20160110.repo.01.slug.sql
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_repository.repository
|
||||||
|
ADD repositorySlug VARCHAR(64) COLLATE {$COLLATE_SORT};
|
||||||
|
|
||||||
|
ALTER TABLE {$NAMESPACE}_repository.repository
|
||||||
|
ADD UNIQUE KEY `key_slug` (repositorySlug);
|
49
resources/sql/autopatches/20160110.repo.02.slug.php
Normal file
49
resources/sql/autopatches/20160110.repo.02.slug.php
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$table = new PhabricatorRepository();
|
||||||
|
$conn_w = $table->establishConnection('w');
|
||||||
|
|
||||||
|
foreach (new LiskMigrationIterator($table) as $repository) {
|
||||||
|
$slug = $repository->getRepositorySlug();
|
||||||
|
|
||||||
|
if ($slug !== null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$clone_name = $repository->getDetail('clone-name');
|
||||||
|
|
||||||
|
if (!strlen($clone_name)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!PhabricatorRepository::isValidRepositorySlug($clone_name)) {
|
||||||
|
echo tsprintf(
|
||||||
|
"%s\n",
|
||||||
|
pht(
|
||||||
|
'Repository "%s" has a "Clone/Checkout As" name which is no longer '.
|
||||||
|
'valid ("%s"). You can edit the repository to give it a new, valid '.
|
||||||
|
'short name.',
|
||||||
|
$repository->getDisplayName(),
|
||||||
|
$clone_name));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
queryfx(
|
||||||
|
$conn_w,
|
||||||
|
'UPDATE %T SET repositorySlug = %s WHERE id = %d',
|
||||||
|
$table->getTableName(),
|
||||||
|
$clone_name,
|
||||||
|
$repository->getID());
|
||||||
|
} catch (AphrontDuplicateKeyQueryException $ex) {
|
||||||
|
echo tsprintf(
|
||||||
|
"%s\n",
|
||||||
|
pht(
|
||||||
|
'Repository "%s" has a duplicate "Clone/Checkout As" name ("%s"). '.
|
||||||
|
'Each name must now be unique. You can edit the repository to give '.
|
||||||
|
'it a new, unique short name.',
|
||||||
|
$repository->getDisplayName(),
|
||||||
|
$clone_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
2
resources/sql/autopatches/20160111.repo.01.slugx.sql
Normal file
2
resources/sql/autopatches/20160111.repo.01.slugx.sql
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
UPDATE {$NAMESPACE}_repository.repository_transaction
|
||||||
|
SET transactionType = 'repo:slug' WHERE transactionType = 'repo:clone-name';
|
7
resources/sql/autopatches/20160112.repo.01.uri.sql
Normal file
7
resources/sql/autopatches/20160112.repo.01.uri.sql
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
CREATE TABLE {$NAMESPACE}_repository.repository_uriindex (
|
||||||
|
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
repositoryPHID VARBINARY(64) NOT NULL,
|
||||||
|
repositoryURI LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT},
|
||||||
|
KEY `key_repository` (repositoryPHID),
|
||||||
|
KEY `key_uri` (repositoryURI(128))
|
||||||
|
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
|
7
resources/sql/autopatches/20160112.repo.02.uri.index.php
Normal file
7
resources/sql/autopatches/20160112.repo.02.uri.index.php
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$table = new PhabricatorRepository();
|
||||||
|
|
||||||
|
foreach (new LiskMigrationIterator($table) as $repo) {
|
||||||
|
$repo->updateURIIndex();
|
||||||
|
}
|
13
resources/sql/autopatches/20160113.propanel.1.storage.sql
Normal file
13
resources/sql/autopatches/20160113.propanel.1.storage.sql
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
CREATE TABLE {$NAMESPACE}_search.search_profilepanelconfiguration (
|
||||||
|
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
phid VARBINARY(64) NOT NULL,
|
||||||
|
profilePHID VARBINARY(64) NOT NULL,
|
||||||
|
panelKey VARCHAR(64) NOT NULL COLLATE {$COLLATE_TEXT},
|
||||||
|
builtinKey VARCHAR(64) COLLATE {$COLLATE_TEXT},
|
||||||
|
panelOrder INT UNSIGNED,
|
||||||
|
visibility VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT},
|
||||||
|
panelProperties LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT},
|
||||||
|
dateCreated INT UNSIGNED NOT NULL,
|
||||||
|
dateModified INT UNSIGNED NOT NULL,
|
||||||
|
KEY `key_profile` (profilePHID, panelOrder)
|
||||||
|
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
|
19
resources/sql/autopatches/20160113.propanel.2.xaction.sql
Normal file
19
resources/sql/autopatches/20160113.propanel.2.xaction.sql
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
CREATE TABLE {$NAMESPACE}_search.search_profilepanelconfigurationtransaction (
|
||||||
|
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
phid VARBINARY(64) NOT NULL,
|
||||||
|
authorPHID VARBINARY(64) NOT NULL,
|
||||||
|
objectPHID VARBINARY(64) NOT NULL,
|
||||||
|
viewPolicy VARBINARY(64) NOT NULL,
|
||||||
|
editPolicy VARBINARY(64) NOT NULL,
|
||||||
|
commentPHID VARBINARY(64) DEFAULT NULL,
|
||||||
|
commentVersion INT UNSIGNED NOT NULL,
|
||||||
|
transactionType VARCHAR(32) COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||||
|
oldValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||||
|
newValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||||
|
contentSource LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||||
|
metadata LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||||
|
dateCreated INT UNSIGNED NOT NULL,
|
||||||
|
dateModified INT UNSIGNED NOT NULL,
|
||||||
|
UNIQUE KEY `key_phid` (`phid`),
|
||||||
|
KEY `key_object` (`objectPHID`)
|
||||||
|
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
|
|
@ -249,6 +249,7 @@ phutil_register_library_map(array(
|
||||||
'ConduitStringParameterType' => 'applications/conduit/parametertype/ConduitStringParameterType.php',
|
'ConduitStringParameterType' => 'applications/conduit/parametertype/ConduitStringParameterType.php',
|
||||||
'ConduitTokenGarbageCollector' => 'applications/conduit/garbagecollector/ConduitTokenGarbageCollector.php',
|
'ConduitTokenGarbageCollector' => 'applications/conduit/garbagecollector/ConduitTokenGarbageCollector.php',
|
||||||
'ConduitUserListParameterType' => 'applications/conduit/parametertype/ConduitUserListParameterType.php',
|
'ConduitUserListParameterType' => 'applications/conduit/parametertype/ConduitUserListParameterType.php',
|
||||||
|
'ConduitUserParameterType' => 'applications/conduit/parametertype/ConduitUserParameterType.php',
|
||||||
'ConduitWildParameterType' => 'applications/conduit/parametertype/ConduitWildParameterType.php',
|
'ConduitWildParameterType' => 'applications/conduit/parametertype/ConduitWildParameterType.php',
|
||||||
'ConpherenceColumnViewController' => 'applications/conpherence/controller/ConpherenceColumnViewController.php',
|
'ConpherenceColumnViewController' => 'applications/conpherence/controller/ConpherenceColumnViewController.php',
|
||||||
'ConpherenceConduitAPIMethod' => 'applications/conpherence/conduit/ConpherenceConduitAPIMethod.php',
|
'ConpherenceConduitAPIMethod' => 'applications/conpherence/conduit/ConpherenceConduitAPIMethod.php',
|
||||||
|
@ -256,7 +257,6 @@ phutil_register_library_map(array(
|
||||||
'ConpherenceConstants' => 'applications/conpherence/constants/ConpherenceConstants.php',
|
'ConpherenceConstants' => 'applications/conpherence/constants/ConpherenceConstants.php',
|
||||||
'ConpherenceController' => 'applications/conpherence/controller/ConpherenceController.php',
|
'ConpherenceController' => 'applications/conpherence/controller/ConpherenceController.php',
|
||||||
'ConpherenceCreateThreadConduitAPIMethod' => 'applications/conpherence/conduit/ConpherenceCreateThreadConduitAPIMethod.php',
|
'ConpherenceCreateThreadConduitAPIMethod' => 'applications/conpherence/conduit/ConpherenceCreateThreadConduitAPIMethod.php',
|
||||||
'ConpherenceCreateThreadMailReceiver' => 'applications/conpherence/mail/ConpherenceCreateThreadMailReceiver.php',
|
|
||||||
'ConpherenceDAO' => 'applications/conpherence/storage/ConpherenceDAO.php',
|
'ConpherenceDAO' => 'applications/conpherence/storage/ConpherenceDAO.php',
|
||||||
'ConpherenceDurableColumnView' => 'applications/conpherence/view/ConpherenceDurableColumnView.php',
|
'ConpherenceDurableColumnView' => 'applications/conpherence/view/ConpherenceDurableColumnView.php',
|
||||||
'ConpherenceEditor' => 'applications/conpherence/editor/ConpherenceEditor.php',
|
'ConpherenceEditor' => 'applications/conpherence/editor/ConpherenceEditor.php',
|
||||||
|
@ -734,6 +734,7 @@ phutil_register_library_map(array(
|
||||||
'DiffusionRepositorySymbolsController' => 'applications/diffusion/controller/DiffusionRepositorySymbolsController.php',
|
'DiffusionRepositorySymbolsController' => 'applications/diffusion/controller/DiffusionRepositorySymbolsController.php',
|
||||||
'DiffusionRepositoryTag' => 'applications/diffusion/data/DiffusionRepositoryTag.php',
|
'DiffusionRepositoryTag' => 'applications/diffusion/data/DiffusionRepositoryTag.php',
|
||||||
'DiffusionRepositoryTestAutomationController' => 'applications/diffusion/controller/DiffusionRepositoryTestAutomationController.php',
|
'DiffusionRepositoryTestAutomationController' => 'applications/diffusion/controller/DiffusionRepositoryTestAutomationController.php',
|
||||||
|
'DiffusionRepositoryURIsIndexEngineExtension' => 'applications/diffusion/engineextension/DiffusionRepositoryURIsIndexEngineExtension.php',
|
||||||
'DiffusionRequest' => 'applications/diffusion/request/DiffusionRequest.php',
|
'DiffusionRequest' => 'applications/diffusion/request/DiffusionRequest.php',
|
||||||
'DiffusionResolveRefsConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionResolveRefsConduitAPIMethod.php',
|
'DiffusionResolveRefsConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionResolveRefsConduitAPIMethod.php',
|
||||||
'DiffusionResolveUserQuery' => 'applications/diffusion/query/DiffusionResolveUserQuery.php',
|
'DiffusionResolveUserQuery' => 'applications/diffusion/query/DiffusionResolveUserQuery.php',
|
||||||
|
@ -1200,6 +1201,7 @@ phutil_register_library_map(array(
|
||||||
'HeraldTranscriptDestructionEngineExtension' => 'applications/herald/engineextension/HeraldTranscriptDestructionEngineExtension.php',
|
'HeraldTranscriptDestructionEngineExtension' => 'applications/herald/engineextension/HeraldTranscriptDestructionEngineExtension.php',
|
||||||
'HeraldTranscriptGarbageCollector' => 'applications/herald/garbagecollector/HeraldTranscriptGarbageCollector.php',
|
'HeraldTranscriptGarbageCollector' => 'applications/herald/garbagecollector/HeraldTranscriptGarbageCollector.php',
|
||||||
'HeraldTranscriptListController' => 'applications/herald/controller/HeraldTranscriptListController.php',
|
'HeraldTranscriptListController' => 'applications/herald/controller/HeraldTranscriptListController.php',
|
||||||
|
'HeraldTranscriptPHIDType' => 'applications/herald/phid/HeraldTranscriptPHIDType.php',
|
||||||
'HeraldTranscriptQuery' => 'applications/herald/query/HeraldTranscriptQuery.php',
|
'HeraldTranscriptQuery' => 'applications/herald/query/HeraldTranscriptQuery.php',
|
||||||
'HeraldTranscriptSearchEngine' => 'applications/herald/query/HeraldTranscriptSearchEngine.php',
|
'HeraldTranscriptSearchEngine' => 'applications/herald/query/HeraldTranscriptSearchEngine.php',
|
||||||
'HeraldTranscriptTestCase' => 'applications/herald/storage/__tests__/HeraldTranscriptTestCase.php',
|
'HeraldTranscriptTestCase' => 'applications/herald/storage/__tests__/HeraldTranscriptTestCase.php',
|
||||||
|
@ -2418,6 +2420,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorLegalpadDocumentPHIDType' => 'applications/legalpad/phid/PhabricatorLegalpadDocumentPHIDType.php',
|
'PhabricatorLegalpadDocumentPHIDType' => 'applications/legalpad/phid/PhabricatorLegalpadDocumentPHIDType.php',
|
||||||
'PhabricatorLegalpadSignaturePolicyRule' => 'applications/legalpad/policyrule/PhabricatorLegalpadSignaturePolicyRule.php',
|
'PhabricatorLegalpadSignaturePolicyRule' => 'applications/legalpad/policyrule/PhabricatorLegalpadSignaturePolicyRule.php',
|
||||||
'PhabricatorLibraryTestCase' => '__tests__/PhabricatorLibraryTestCase.php',
|
'PhabricatorLibraryTestCase' => '__tests__/PhabricatorLibraryTestCase.php',
|
||||||
|
'PhabricatorLinkProfilePanel' => 'applications/search/profilepanel/PhabricatorLinkProfilePanel.php',
|
||||||
'PhabricatorLipsumArtist' => 'applications/lipsum/image/PhabricatorLipsumArtist.php',
|
'PhabricatorLipsumArtist' => 'applications/lipsum/image/PhabricatorLipsumArtist.php',
|
||||||
'PhabricatorLipsumGenerateWorkflow' => 'applications/lipsum/management/PhabricatorLipsumGenerateWorkflow.php',
|
'PhabricatorLipsumGenerateWorkflow' => 'applications/lipsum/management/PhabricatorLipsumGenerateWorkflow.php',
|
||||||
'PhabricatorLipsumManagementWorkflow' => 'applications/lipsum/management/PhabricatorLipsumManagementWorkflow.php',
|
'PhabricatorLipsumManagementWorkflow' => 'applications/lipsum/management/PhabricatorLipsumManagementWorkflow.php',
|
||||||
|
@ -2825,6 +2828,16 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorPolicyTestObject' => 'applications/policy/__tests__/PhabricatorPolicyTestObject.php',
|
'PhabricatorPolicyTestObject' => 'applications/policy/__tests__/PhabricatorPolicyTestObject.php',
|
||||||
'PhabricatorPolicyType' => 'applications/policy/constants/PhabricatorPolicyType.php',
|
'PhabricatorPolicyType' => 'applications/policy/constants/PhabricatorPolicyType.php',
|
||||||
'PhabricatorPonderApplication' => 'applications/ponder/application/PhabricatorPonderApplication.php',
|
'PhabricatorPonderApplication' => 'applications/ponder/application/PhabricatorPonderApplication.php',
|
||||||
|
'PhabricatorProfilePanel' => 'applications/search/profilepanel/PhabricatorProfilePanel.php',
|
||||||
|
'PhabricatorProfilePanelConfiguration' => 'applications/search/storage/PhabricatorProfilePanelConfiguration.php',
|
||||||
|
'PhabricatorProfilePanelConfigurationQuery' => 'applications/search/query/PhabricatorProfilePanelConfigurationQuery.php',
|
||||||
|
'PhabricatorProfilePanelConfigurationTransaction' => 'applications/search/storage/PhabricatorProfilePanelConfigurationTransaction.php',
|
||||||
|
'PhabricatorProfilePanelEditEngine' => 'applications/search/editor/PhabricatorProfilePanelEditEngine.php',
|
||||||
|
'PhabricatorProfilePanelEditor' => 'applications/search/editor/PhabricatorProfilePanelEditor.php',
|
||||||
|
'PhabricatorProfilePanelEngine' => 'applications/search/engine/PhabricatorProfilePanelEngine.php',
|
||||||
|
'PhabricatorProfilePanelIconSet' => 'applications/search/profilepanel/PhabricatorProfilePanelIconSet.php',
|
||||||
|
'PhabricatorProfilePanelInterface' => 'applications/search/interface/PhabricatorProfilePanelInterface.php',
|
||||||
|
'PhabricatorProfilePanelPHIDType' => 'applications/search/phidtype/PhabricatorProfilePanelPHIDType.php',
|
||||||
'PhabricatorProject' => 'applications/project/storage/PhabricatorProject.php',
|
'PhabricatorProject' => 'applications/project/storage/PhabricatorProject.php',
|
||||||
'PhabricatorProjectAddHeraldAction' => 'applications/project/herald/PhabricatorProjectAddHeraldAction.php',
|
'PhabricatorProjectAddHeraldAction' => 'applications/project/herald/PhabricatorProjectAddHeraldAction.php',
|
||||||
'PhabricatorProjectApplication' => 'applications/project/application/PhabricatorProjectApplication.php',
|
'PhabricatorProjectApplication' => 'applications/project/application/PhabricatorProjectApplication.php',
|
||||||
|
@ -2855,6 +2868,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorProjectDAO' => 'applications/project/storage/PhabricatorProjectDAO.php',
|
'PhabricatorProjectDAO' => 'applications/project/storage/PhabricatorProjectDAO.php',
|
||||||
'PhabricatorProjectDatasource' => 'applications/project/typeahead/PhabricatorProjectDatasource.php',
|
'PhabricatorProjectDatasource' => 'applications/project/typeahead/PhabricatorProjectDatasource.php',
|
||||||
'PhabricatorProjectDescriptionField' => 'applications/project/customfield/PhabricatorProjectDescriptionField.php',
|
'PhabricatorProjectDescriptionField' => 'applications/project/customfield/PhabricatorProjectDescriptionField.php',
|
||||||
|
'PhabricatorProjectDetailsProfilePanel' => 'applications/project/profilepanel/PhabricatorProjectDetailsProfilePanel.php',
|
||||||
'PhabricatorProjectEditController' => 'applications/project/controller/PhabricatorProjectEditController.php',
|
'PhabricatorProjectEditController' => 'applications/project/controller/PhabricatorProjectEditController.php',
|
||||||
'PhabricatorProjectEditEngine' => 'applications/project/engine/PhabricatorProjectEditEngine.php',
|
'PhabricatorProjectEditEngine' => 'applications/project/engine/PhabricatorProjectEditEngine.php',
|
||||||
'PhabricatorProjectEditPictureController' => 'applications/project/controller/PhabricatorProjectEditPictureController.php',
|
'PhabricatorProjectEditPictureController' => 'applications/project/controller/PhabricatorProjectEditPictureController.php',
|
||||||
|
@ -2876,6 +2890,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorProjectMembersDatasource' => 'applications/project/typeahead/PhabricatorProjectMembersDatasource.php',
|
'PhabricatorProjectMembersDatasource' => 'applications/project/typeahead/PhabricatorProjectMembersDatasource.php',
|
||||||
'PhabricatorProjectMembersEditController' => 'applications/project/controller/PhabricatorProjectMembersEditController.php',
|
'PhabricatorProjectMembersEditController' => 'applications/project/controller/PhabricatorProjectMembersEditController.php',
|
||||||
'PhabricatorProjectMembersPolicyRule' => 'applications/project/policyrule/PhabricatorProjectMembersPolicyRule.php',
|
'PhabricatorProjectMembersPolicyRule' => 'applications/project/policyrule/PhabricatorProjectMembersPolicyRule.php',
|
||||||
|
'PhabricatorProjectMembersProfilePanel' => 'applications/project/profilepanel/PhabricatorProjectMembersProfilePanel.php',
|
||||||
'PhabricatorProjectMembersRemoveController' => 'applications/project/controller/PhabricatorProjectMembersRemoveController.php',
|
'PhabricatorProjectMembersRemoveController' => 'applications/project/controller/PhabricatorProjectMembersRemoveController.php',
|
||||||
'PhabricatorProjectMilestonesController' => 'applications/project/controller/PhabricatorProjectMilestonesController.php',
|
'PhabricatorProjectMilestonesController' => 'applications/project/controller/PhabricatorProjectMilestonesController.php',
|
||||||
'PhabricatorProjectMoveController' => 'applications/project/controller/PhabricatorProjectMoveController.php',
|
'PhabricatorProjectMoveController' => 'applications/project/controller/PhabricatorProjectMoveController.php',
|
||||||
|
@ -2885,6 +2900,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorProjectOrUserDatasource' => 'applications/project/typeahead/PhabricatorProjectOrUserDatasource.php',
|
'PhabricatorProjectOrUserDatasource' => 'applications/project/typeahead/PhabricatorProjectOrUserDatasource.php',
|
||||||
'PhabricatorProjectOrUserFunctionDatasource' => 'applications/project/typeahead/PhabricatorProjectOrUserFunctionDatasource.php',
|
'PhabricatorProjectOrUserFunctionDatasource' => 'applications/project/typeahead/PhabricatorProjectOrUserFunctionDatasource.php',
|
||||||
'PhabricatorProjectPHIDResolver' => 'applications/phid/resolver/PhabricatorProjectPHIDResolver.php',
|
'PhabricatorProjectPHIDResolver' => 'applications/phid/resolver/PhabricatorProjectPHIDResolver.php',
|
||||||
|
'PhabricatorProjectPanelController' => 'applications/project/controller/PhabricatorProjectPanelController.php',
|
||||||
'PhabricatorProjectProfileController' => 'applications/project/controller/PhabricatorProjectProfileController.php',
|
'PhabricatorProjectProfileController' => 'applications/project/controller/PhabricatorProjectProfileController.php',
|
||||||
'PhabricatorProjectProjectHasMemberEdgeType' => 'applications/project/edge/PhabricatorProjectProjectHasMemberEdgeType.php',
|
'PhabricatorProjectProjectHasMemberEdgeType' => 'applications/project/edge/PhabricatorProjectProjectHasMemberEdgeType.php',
|
||||||
'PhabricatorProjectProjectHasObjectEdgeType' => 'applications/project/edge/PhabricatorProjectProjectHasObjectEdgeType.php',
|
'PhabricatorProjectProjectHasObjectEdgeType' => 'applications/project/edge/PhabricatorProjectProjectHasObjectEdgeType.php',
|
||||||
|
@ -2908,6 +2924,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorProjectUserFunctionDatasource' => 'applications/project/typeahead/PhabricatorProjectUserFunctionDatasource.php',
|
'PhabricatorProjectUserFunctionDatasource' => 'applications/project/typeahead/PhabricatorProjectUserFunctionDatasource.php',
|
||||||
'PhabricatorProjectViewController' => 'applications/project/controller/PhabricatorProjectViewController.php',
|
'PhabricatorProjectViewController' => 'applications/project/controller/PhabricatorProjectViewController.php',
|
||||||
'PhabricatorProjectWatchController' => 'applications/project/controller/PhabricatorProjectWatchController.php',
|
'PhabricatorProjectWatchController' => 'applications/project/controller/PhabricatorProjectWatchController.php',
|
||||||
|
'PhabricatorProjectWorkboardProfilePanel' => 'applications/project/profilepanel/PhabricatorProjectWorkboardProfilePanel.php',
|
||||||
'PhabricatorProjectsEditEngineExtension' => 'applications/project/engineextension/PhabricatorProjectsEditEngineExtension.php',
|
'PhabricatorProjectsEditEngineExtension' => 'applications/project/engineextension/PhabricatorProjectsEditEngineExtension.php',
|
||||||
'PhabricatorProjectsEditField' => 'applications/transactions/editfield/PhabricatorProjectsEditField.php',
|
'PhabricatorProjectsEditField' => 'applications/transactions/editfield/PhabricatorProjectsEditField.php',
|
||||||
'PhabricatorProjectsFulltextEngineExtension' => 'applications/project/engineextension/PhabricatorProjectsFulltextEngineExtension.php',
|
'PhabricatorProjectsFulltextEngineExtension' => 'applications/project/engineextension/PhabricatorProjectsFulltextEngineExtension.php',
|
||||||
|
@ -3009,6 +3026,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorRepositoryTransaction' => 'applications/repository/storage/PhabricatorRepositoryTransaction.php',
|
'PhabricatorRepositoryTransaction' => 'applications/repository/storage/PhabricatorRepositoryTransaction.php',
|
||||||
'PhabricatorRepositoryTransactionQuery' => 'applications/repository/query/PhabricatorRepositoryTransactionQuery.php',
|
'PhabricatorRepositoryTransactionQuery' => 'applications/repository/query/PhabricatorRepositoryTransactionQuery.php',
|
||||||
'PhabricatorRepositoryType' => 'applications/repository/constants/PhabricatorRepositoryType.php',
|
'PhabricatorRepositoryType' => 'applications/repository/constants/PhabricatorRepositoryType.php',
|
||||||
|
'PhabricatorRepositoryURIIndex' => 'applications/repository/storage/PhabricatorRepositoryURIIndex.php',
|
||||||
'PhabricatorRepositoryURINormalizer' => 'applications/repository/data/PhabricatorRepositoryURINormalizer.php',
|
'PhabricatorRepositoryURINormalizer' => 'applications/repository/data/PhabricatorRepositoryURINormalizer.php',
|
||||||
'PhabricatorRepositoryURINormalizerTestCase' => 'applications/repository/data/__tests__/PhabricatorRepositoryURINormalizerTestCase.php',
|
'PhabricatorRepositoryURINormalizerTestCase' => 'applications/repository/data/__tests__/PhabricatorRepositoryURINormalizerTestCase.php',
|
||||||
'PhabricatorRepositoryURITestCase' => 'applications/repository/storage/__tests__/PhabricatorRepositoryURITestCase.php',
|
'PhabricatorRepositoryURITestCase' => 'applications/repository/storage/__tests__/PhabricatorRepositoryURITestCase.php',
|
||||||
|
@ -4184,6 +4202,7 @@ phutil_register_library_map(array(
|
||||||
'ConduitStringParameterType' => 'ConduitParameterType',
|
'ConduitStringParameterType' => 'ConduitParameterType',
|
||||||
'ConduitTokenGarbageCollector' => 'PhabricatorGarbageCollector',
|
'ConduitTokenGarbageCollector' => 'PhabricatorGarbageCollector',
|
||||||
'ConduitUserListParameterType' => 'ConduitListParameterType',
|
'ConduitUserListParameterType' => 'ConduitListParameterType',
|
||||||
|
'ConduitUserParameterType' => 'ConduitParameterType',
|
||||||
'ConduitWildParameterType' => 'ConduitListParameterType',
|
'ConduitWildParameterType' => 'ConduitListParameterType',
|
||||||
'ConpherenceColumnViewController' => 'ConpherenceController',
|
'ConpherenceColumnViewController' => 'ConpherenceController',
|
||||||
'ConpherenceConduitAPIMethod' => 'ConduitAPIMethod',
|
'ConpherenceConduitAPIMethod' => 'ConduitAPIMethod',
|
||||||
|
@ -4191,7 +4210,6 @@ phutil_register_library_map(array(
|
||||||
'ConpherenceConstants' => 'Phobject',
|
'ConpherenceConstants' => 'Phobject',
|
||||||
'ConpherenceController' => 'PhabricatorController',
|
'ConpherenceController' => 'PhabricatorController',
|
||||||
'ConpherenceCreateThreadConduitAPIMethod' => 'ConpherenceConduitAPIMethod',
|
'ConpherenceCreateThreadConduitAPIMethod' => 'ConpherenceConduitAPIMethod',
|
||||||
'ConpherenceCreateThreadMailReceiver' => 'PhabricatorMailReceiver',
|
|
||||||
'ConpherenceDAO' => 'PhabricatorLiskDAO',
|
'ConpherenceDAO' => 'PhabricatorLiskDAO',
|
||||||
'ConpherenceDurableColumnView' => 'AphrontTagView',
|
'ConpherenceDurableColumnView' => 'AphrontTagView',
|
||||||
'ConpherenceEditor' => 'PhabricatorApplicationTransactionEditor',
|
'ConpherenceEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||||
|
@ -4707,6 +4725,7 @@ phutil_register_library_map(array(
|
||||||
'DiffusionRepositorySymbolsController' => 'DiffusionRepositoryEditController',
|
'DiffusionRepositorySymbolsController' => 'DiffusionRepositoryEditController',
|
||||||
'DiffusionRepositoryTag' => 'Phobject',
|
'DiffusionRepositoryTag' => 'Phobject',
|
||||||
'DiffusionRepositoryTestAutomationController' => 'DiffusionRepositoryEditController',
|
'DiffusionRepositoryTestAutomationController' => 'DiffusionRepositoryEditController',
|
||||||
|
'DiffusionRepositoryURIsIndexEngineExtension' => 'PhabricatorIndexEngineExtension',
|
||||||
'DiffusionRequest' => 'Phobject',
|
'DiffusionRequest' => 'Phobject',
|
||||||
'DiffusionResolveRefsConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
|
'DiffusionResolveRefsConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
|
||||||
'DiffusionResolveUserQuery' => 'Phobject',
|
'DiffusionResolveUserQuery' => 'Phobject',
|
||||||
|
@ -5279,6 +5298,7 @@ phutil_register_library_map(array(
|
||||||
'HeraldTranscriptDestructionEngineExtension' => 'PhabricatorDestructionEngineExtension',
|
'HeraldTranscriptDestructionEngineExtension' => 'PhabricatorDestructionEngineExtension',
|
||||||
'HeraldTranscriptGarbageCollector' => 'PhabricatorGarbageCollector',
|
'HeraldTranscriptGarbageCollector' => 'PhabricatorGarbageCollector',
|
||||||
'HeraldTranscriptListController' => 'HeraldController',
|
'HeraldTranscriptListController' => 'HeraldController',
|
||||||
|
'HeraldTranscriptPHIDType' => 'PhabricatorPHIDType',
|
||||||
'HeraldTranscriptQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
'HeraldTranscriptQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
'HeraldTranscriptSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
'HeraldTranscriptSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||||
'HeraldTranscriptTestCase' => 'PhabricatorTestCase',
|
'HeraldTranscriptTestCase' => 'PhabricatorTestCase',
|
||||||
|
@ -6697,6 +6717,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorLegalpadDocumentPHIDType' => 'PhabricatorPHIDType',
|
'PhabricatorLegalpadDocumentPHIDType' => 'PhabricatorPHIDType',
|
||||||
'PhabricatorLegalpadSignaturePolicyRule' => 'PhabricatorPolicyRule',
|
'PhabricatorLegalpadSignaturePolicyRule' => 'PhabricatorPolicyRule',
|
||||||
'PhabricatorLibraryTestCase' => 'PhutilLibraryTestCase',
|
'PhabricatorLibraryTestCase' => 'PhutilLibraryTestCase',
|
||||||
|
'PhabricatorLinkProfilePanel' => 'PhabricatorProfilePanel',
|
||||||
'PhabricatorLipsumArtist' => 'Phobject',
|
'PhabricatorLipsumArtist' => 'Phobject',
|
||||||
'PhabricatorLipsumGenerateWorkflow' => 'PhabricatorLipsumManagementWorkflow',
|
'PhabricatorLipsumGenerateWorkflow' => 'PhabricatorLipsumManagementWorkflow',
|
||||||
'PhabricatorLipsumManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
'PhabricatorLipsumManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
||||||
|
@ -7168,6 +7189,20 @@ phutil_register_library_map(array(
|
||||||
),
|
),
|
||||||
'PhabricatorPolicyType' => 'PhabricatorPolicyConstants',
|
'PhabricatorPolicyType' => 'PhabricatorPolicyConstants',
|
||||||
'PhabricatorPonderApplication' => 'PhabricatorApplication',
|
'PhabricatorPonderApplication' => 'PhabricatorApplication',
|
||||||
|
'PhabricatorProfilePanel' => 'Phobject',
|
||||||
|
'PhabricatorProfilePanelConfiguration' => array(
|
||||||
|
'PhabricatorSearchDAO',
|
||||||
|
'PhabricatorPolicyInterface',
|
||||||
|
'PhabricatorExtendedPolicyInterface',
|
||||||
|
'PhabricatorApplicationTransactionInterface',
|
||||||
|
),
|
||||||
|
'PhabricatorProfilePanelConfigurationQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
|
'PhabricatorProfilePanelConfigurationTransaction' => 'PhabricatorApplicationTransaction',
|
||||||
|
'PhabricatorProfilePanelEditEngine' => 'PhabricatorEditEngine',
|
||||||
|
'PhabricatorProfilePanelEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||||
|
'PhabricatorProfilePanelEngine' => 'Phobject',
|
||||||
|
'PhabricatorProfilePanelIconSet' => 'PhabricatorIconSet',
|
||||||
|
'PhabricatorProfilePanelPHIDType' => 'PhabricatorPHIDType',
|
||||||
'PhabricatorProject' => array(
|
'PhabricatorProject' => array(
|
||||||
'PhabricatorProjectDAO',
|
'PhabricatorProjectDAO',
|
||||||
'PhabricatorApplicationTransactionInterface',
|
'PhabricatorApplicationTransactionInterface',
|
||||||
|
@ -7179,6 +7214,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorDestructibleInterface',
|
'PhabricatorDestructibleInterface',
|
||||||
'PhabricatorFulltextInterface',
|
'PhabricatorFulltextInterface',
|
||||||
'PhabricatorConduitResultInterface',
|
'PhabricatorConduitResultInterface',
|
||||||
|
'PhabricatorProfilePanelInterface',
|
||||||
),
|
),
|
||||||
'PhabricatorProjectAddHeraldAction' => 'PhabricatorProjectHeraldAction',
|
'PhabricatorProjectAddHeraldAction' => 'PhabricatorProjectHeraldAction',
|
||||||
'PhabricatorProjectApplication' => 'PhabricatorApplication',
|
'PhabricatorProjectApplication' => 'PhabricatorApplication',
|
||||||
|
@ -7220,6 +7256,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorProjectDAO' => 'PhabricatorLiskDAO',
|
'PhabricatorProjectDAO' => 'PhabricatorLiskDAO',
|
||||||
'PhabricatorProjectDatasource' => 'PhabricatorTypeaheadDatasource',
|
'PhabricatorProjectDatasource' => 'PhabricatorTypeaheadDatasource',
|
||||||
'PhabricatorProjectDescriptionField' => 'PhabricatorProjectStandardCustomField',
|
'PhabricatorProjectDescriptionField' => 'PhabricatorProjectStandardCustomField',
|
||||||
|
'PhabricatorProjectDetailsProfilePanel' => 'PhabricatorProfilePanel',
|
||||||
'PhabricatorProjectEditController' => 'PhabricatorProjectController',
|
'PhabricatorProjectEditController' => 'PhabricatorProjectController',
|
||||||
'PhabricatorProjectEditEngine' => 'PhabricatorEditEngine',
|
'PhabricatorProjectEditEngine' => 'PhabricatorEditEngine',
|
||||||
'PhabricatorProjectEditPictureController' => 'PhabricatorProjectController',
|
'PhabricatorProjectEditPictureController' => 'PhabricatorProjectController',
|
||||||
|
@ -7240,6 +7277,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorProjectMembersDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
'PhabricatorProjectMembersDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
||||||
'PhabricatorProjectMembersEditController' => 'PhabricatorProjectController',
|
'PhabricatorProjectMembersEditController' => 'PhabricatorProjectController',
|
||||||
'PhabricatorProjectMembersPolicyRule' => 'PhabricatorPolicyRule',
|
'PhabricatorProjectMembersPolicyRule' => 'PhabricatorPolicyRule',
|
||||||
|
'PhabricatorProjectMembersProfilePanel' => 'PhabricatorProfilePanel',
|
||||||
'PhabricatorProjectMembersRemoveController' => 'PhabricatorProjectController',
|
'PhabricatorProjectMembersRemoveController' => 'PhabricatorProjectController',
|
||||||
'PhabricatorProjectMilestonesController' => 'PhabricatorProjectController',
|
'PhabricatorProjectMilestonesController' => 'PhabricatorProjectController',
|
||||||
'PhabricatorProjectMoveController' => 'PhabricatorProjectController',
|
'PhabricatorProjectMoveController' => 'PhabricatorProjectController',
|
||||||
|
@ -7249,6 +7287,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorProjectOrUserDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
'PhabricatorProjectOrUserDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
||||||
'PhabricatorProjectOrUserFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
'PhabricatorProjectOrUserFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
||||||
'PhabricatorProjectPHIDResolver' => 'PhabricatorPHIDResolver',
|
'PhabricatorProjectPHIDResolver' => 'PhabricatorPHIDResolver',
|
||||||
|
'PhabricatorProjectPanelController' => 'PhabricatorProjectController',
|
||||||
'PhabricatorProjectProfileController' => 'PhabricatorProjectController',
|
'PhabricatorProjectProfileController' => 'PhabricatorProjectController',
|
||||||
'PhabricatorProjectProjectHasMemberEdgeType' => 'PhabricatorEdgeType',
|
'PhabricatorProjectProjectHasMemberEdgeType' => 'PhabricatorEdgeType',
|
||||||
'PhabricatorProjectProjectHasObjectEdgeType' => 'PhabricatorEdgeType',
|
'PhabricatorProjectProjectHasObjectEdgeType' => 'PhabricatorEdgeType',
|
||||||
|
@ -7275,6 +7314,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorProjectUserFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
'PhabricatorProjectUserFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
||||||
'PhabricatorProjectViewController' => 'PhabricatorProjectController',
|
'PhabricatorProjectViewController' => 'PhabricatorProjectController',
|
||||||
'PhabricatorProjectWatchController' => 'PhabricatorProjectController',
|
'PhabricatorProjectWatchController' => 'PhabricatorProjectController',
|
||||||
|
'PhabricatorProjectWorkboardProfilePanel' => 'PhabricatorProfilePanel',
|
||||||
'PhabricatorProjectsEditEngineExtension' => 'PhabricatorEditEngineExtension',
|
'PhabricatorProjectsEditEngineExtension' => 'PhabricatorEditEngineExtension',
|
||||||
'PhabricatorProjectsEditField' => 'PhabricatorTokenizerEditField',
|
'PhabricatorProjectsEditField' => 'PhabricatorTokenizerEditField',
|
||||||
'PhabricatorProjectsFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension',
|
'PhabricatorProjectsFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension',
|
||||||
|
@ -7415,6 +7455,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorRepositoryTransaction' => 'PhabricatorApplicationTransaction',
|
'PhabricatorRepositoryTransaction' => 'PhabricatorApplicationTransaction',
|
||||||
'PhabricatorRepositoryTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
'PhabricatorRepositoryTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||||
'PhabricatorRepositoryType' => 'Phobject',
|
'PhabricatorRepositoryType' => 'Phobject',
|
||||||
|
'PhabricatorRepositoryURIIndex' => 'PhabricatorRepositoryDAO',
|
||||||
'PhabricatorRepositoryURINormalizer' => 'Phobject',
|
'PhabricatorRepositoryURINormalizer' => 'Phobject',
|
||||||
'PhabricatorRepositoryURINormalizerTestCase' => 'PhabricatorTestCase',
|
'PhabricatorRepositoryURINormalizerTestCase' => 'PhabricatorTestCase',
|
||||||
'PhabricatorRepositoryURITestCase' => 'PhabricatorTestCase',
|
'PhabricatorRepositoryURITestCase' => 'PhabricatorTestCase',
|
||||||
|
|
|
@ -635,4 +635,19 @@ abstract class PhabricatorApplication
|
||||||
return $base.'(?:query/(?P<queryKey>[^/]+)/)?';
|
return $base.'(?:query/(?P<queryKey>[^/]+)/)?';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function getPanelRouting($controller) {
|
||||||
|
$edit_route = $this->getEditRoutePattern();
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'(?P<panelAction>view)/(?P<panelID>[^/]+)/' => $controller,
|
||||||
|
'(?P<panelAction>hide)/(?P<panelID>[^/]+)/' => $controller,
|
||||||
|
'(?P<panelAction>configure)/' => $controller,
|
||||||
|
'(?P<panelAction>reorder)/' => $controller,
|
||||||
|
'(?P<panelAction>edit)/'.$edit_route => $controller,
|
||||||
|
'(?P<panelAction>new)/(?<panelKey>[^/]+)/'.$edit_route => $controller,
|
||||||
|
'(?P<panelAction>builtin)/(?<panelID>[^/]+)/'.$edit_route
|
||||||
|
=> $controller,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ConduitUserParameterType
|
||||||
|
extends ConduitParameterType {
|
||||||
|
|
||||||
|
protected function getParameterValue(array $request, $key) {
|
||||||
|
$value = parent::getParameterValue($request, $key);
|
||||||
|
|
||||||
|
if ($value === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_string($value)) {
|
||||||
|
$this->raiseValidationException(
|
||||||
|
$request,
|
||||||
|
$key,
|
||||||
|
pht('Expected PHID or null, got something else.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$user_phids = id(new PhabricatorUserPHIDResolver())
|
||||||
|
->setViewer($this->getViewer())
|
||||||
|
->resolvePHIDs(array($value));
|
||||||
|
|
||||||
|
return nonempty(head($user_phids), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getParameterTypeName() {
|
||||||
|
return 'phid|string|null';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getParameterFormatDescriptions() {
|
||||||
|
return array(
|
||||||
|
pht('User PHID.'),
|
||||||
|
pht('Username.'),
|
||||||
|
pht('Literal null.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getParameterExamples() {
|
||||||
|
return array(
|
||||||
|
'"PHID-USER-1111"',
|
||||||
|
'"alincoln"',
|
||||||
|
'null',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -13,6 +13,8 @@ final class PhabricatorStorageSetupCheck extends PhabricatorSetupCheck {
|
||||||
$engines = PhabricatorFileStorageEngine::loadWritableChunkEngines();
|
$engines = PhabricatorFileStorageEngine::loadWritableChunkEngines();
|
||||||
$chunk_engine_active = (bool)$engines;
|
$chunk_engine_active = (bool)$engines;
|
||||||
|
|
||||||
|
$this->checkS3();
|
||||||
|
|
||||||
if (!$chunk_engine_active) {
|
if (!$chunk_engine_active) {
|
||||||
$doc_href = PhabricatorEnv::getDocLink('Configuring File Storage');
|
$doc_href = PhabricatorEnv::getDocLink('Configuring File Storage');
|
||||||
|
|
||||||
|
@ -140,4 +142,55 @@ final class PhabricatorStorageSetupCheck extends PhabricatorSetupCheck {
|
||||||
->addPhabricatorConfig('storage.local-disk.path');
|
->addPhabricatorConfig('storage.local-disk.path');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function checkS3() {
|
||||||
|
$access_key = PhabricatorEnv::getEnvConfig('amazon-s3.access-key');
|
||||||
|
$secret_key = PhabricatorEnv::getEnvConfig('amazon-s3.secret-key');
|
||||||
|
$region = PhabricatorEnv::getEnvConfig('amazon-s3.region');
|
||||||
|
$endpoint = PhabricatorEnv::getEnvConfig('amazon-s3.endpoint');
|
||||||
|
|
||||||
|
$how_many = 0;
|
||||||
|
|
||||||
|
if (strlen($access_key)) {
|
||||||
|
$how_many++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen($secret_key)) {
|
||||||
|
$how_many++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen($region)) {
|
||||||
|
$how_many++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen($endpoint)) {
|
||||||
|
$how_many++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nothing configured, no issues here.
|
||||||
|
if ($how_many === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Everything configured, no issues here.
|
||||||
|
if ($how_many === 4) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$message = pht(
|
||||||
|
'File storage in Amazon S3 has been partially configured, but you are '.
|
||||||
|
'missing some required settings. S3 will not be available to store '.
|
||||||
|
'files until you complete the configuration. Either configure S3 fully '.
|
||||||
|
'or remove the partial configuration.');
|
||||||
|
|
||||||
|
$this->newIssue('storage.s3.partial-config')
|
||||||
|
->setShortName(pht('S3 Partially Configured'))
|
||||||
|
->setName(pht('Amazon S3 is Only Partially Configured'))
|
||||||
|
->setMessage($message)
|
||||||
|
->addPhabricatorConfig('amazon-s3.access-key')
|
||||||
|
->addPhabricatorConfig('amazon-s3.secret-key')
|
||||||
|
->addPhabricatorConfig('amazon-s3.region')
|
||||||
|
->addPhabricatorConfig('amazon-s3.endpoint');
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,14 +33,27 @@ final class PhabricatorAWSConfigOptions
|
||||||
$this->newOption('amazon-s3.secret-key', 'string', null)
|
$this->newOption('amazon-s3.secret-key', 'string', null)
|
||||||
->setHidden(true)
|
->setHidden(true)
|
||||||
->setDescription(pht('Secret key for Amazon S3.')),
|
->setDescription(pht('Secret key for Amazon S3.')),
|
||||||
|
$this->newOption('amazon-s3.region', 'string', null)
|
||||||
|
->setLocked(true)
|
||||||
|
->setDescription(
|
||||||
|
pht(
|
||||||
|
'Amazon S3 region where your S3 bucket is located. When you '.
|
||||||
|
'specify a region, you should also specify a corresponding '.
|
||||||
|
'endpoint with `amazon-s3.endpoint`. You can find a list of '.
|
||||||
|
'available regions and endpoints in the AWS documentation.'))
|
||||||
|
->addExample('us-west-1', pht('USWest Region')),
|
||||||
$this->newOption('amazon-s3.endpoint', 'string', null)
|
$this->newOption('amazon-s3.endpoint', 'string', null)
|
||||||
->setLocked(true)
|
->setLocked(true)
|
||||||
->setDescription(
|
->setDescription(
|
||||||
pht(
|
pht(
|
||||||
'Explicit S3 endpoint to use. Leave empty to have Phabricator '.
|
'Explicit S3 endpoint to use. This should be the endpoint '.
|
||||||
'select and endpoint. Normally, you do not need to set this.'))
|
'which corresponds to the region you have selected in '.
|
||||||
->addExample(null, pht('Use default endpoint'))
|
'`amazon-s3.region`. Phabricator can not determine the correct '.
|
||||||
->addExample('s3.amazon.com', pht('Use specific endpoint')),
|
'endpoint automatically because some endpoint locations are '.
|
||||||
|
'irregular.'))
|
||||||
|
->addExample(
|
||||||
|
's3-us-west-1.amazonaws.com',
|
||||||
|
pht('Use specific endpoint')),
|
||||||
$this->newOption('amazon-ec2.access-key', 'string', null)
|
$this->newOption('amazon-ec2.access-key', 'string', null)
|
||||||
->setLocked(true)
|
->setLocked(true)
|
||||||
->setDescription(pht('Access key for Amazon EC2.')),
|
->setDescription(pht('Access key for Amazon EC2.')),
|
||||||
|
|
|
@ -21,7 +21,14 @@ abstract class PhabricatorApplicationConfigOptions extends Phobject {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($option->isCustomType()) {
|
if ($option->isCustomType()) {
|
||||||
return $option->getCustomObject()->validateOption($option, $value);
|
try {
|
||||||
|
return $option->getCustomObject()->validateOption($option, $value);
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
// If custom validators threw exceptions, convert them to configuation
|
||||||
|
// validation exceptions so we repair the configuration and raise
|
||||||
|
// an error.
|
||||||
|
throw new PhabricatorConfigValidationException($ex->getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ($option->getType()) {
|
switch ($option->getType()) {
|
||||||
|
|
|
@ -275,20 +275,21 @@ final class PhabricatorSetupIssueView extends AphrontView {
|
||||||
$update = array();
|
$update = array();
|
||||||
foreach ($configs as $config) {
|
foreach ($configs as $config) {
|
||||||
if (idx($options, $config) && $options[$config]->getLocked()) {
|
if (idx($options, $config) && $options[$config]->getLocked()) {
|
||||||
continue;
|
$name = pht('View "%s"', $config);
|
||||||
|
} else {
|
||||||
|
$name = pht('Edit "%s"', $config);
|
||||||
}
|
}
|
||||||
$link = phutil_tag(
|
$link = phutil_tag(
|
||||||
'a',
|
'a',
|
||||||
array(
|
array(
|
||||||
'href' => '/config/edit/'.$config.'/?issue='.$issue->getIssueKey(),
|
'href' => '/config/edit/'.$config.'/?issue='.$issue->getIssueKey(),
|
||||||
),
|
),
|
||||||
pht('Edit %s', $config));
|
$name);
|
||||||
$update[] = phutil_tag('li', array(), $link);
|
$update[] = phutil_tag('li', array(), $link);
|
||||||
}
|
}
|
||||||
if ($update) {
|
if ($update) {
|
||||||
$update = phutil_tag('ul', array(), $update);
|
$update = phutil_tag('ul', array(), $update);
|
||||||
if (!$related) {
|
if (!$related) {
|
||||||
|
|
||||||
$update_info = phutil_tag(
|
$update_info = phutil_tag(
|
||||||
'p',
|
'p',
|
||||||
array(),
|
array(),
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
final class ConpherenceCreateThreadMailReceiver
|
|
||||||
extends PhabricatorMailReceiver {
|
|
||||||
|
|
||||||
public function isEnabled() {
|
|
||||||
$app_class = 'PhabricatorConpherenceApplication';
|
|
||||||
return PhabricatorApplication::isClassInstalled($app_class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function canAcceptMail(PhabricatorMetaMTAReceivedMail $mail) {
|
|
||||||
$usernames = $this->getMailUsernames($mail);
|
|
||||||
if (!$usernames) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$users = $this->loadMailUsers($mail);
|
|
||||||
if (count($users) != count($usernames)) {
|
|
||||||
// At least some of the addresses are not users, so don't accept this as
|
|
||||||
// a new Conpherence thread.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getMailUsernames(PhabricatorMetaMTAReceivedMail $mail) {
|
|
||||||
$usernames = array();
|
|
||||||
foreach ($mail->getToAddresses() as $to_address) {
|
|
||||||
$address = self::stripMailboxPrefix($to_address);
|
|
||||||
$usernames[] = id(new PhutilEmailAddress($address))->getLocalPart();
|
|
||||||
}
|
|
||||||
|
|
||||||
return array_unique($usernames);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function loadMailUsers(PhabricatorMetaMTAReceivedMail $mail) {
|
|
||||||
$usernames = $this->getMailUsernames($mail);
|
|
||||||
if (!$usernames) {
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
|
|
||||||
return id(new PhabricatorUser())->loadAllWhere(
|
|
||||||
'username in (%Ls)',
|
|
||||||
$usernames);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function processReceivedMail(
|
|
||||||
PhabricatorMetaMTAReceivedMail $mail,
|
|
||||||
PhabricatorUser $sender) {
|
|
||||||
|
|
||||||
$users = $this->loadMailUsers($mail);
|
|
||||||
$phids = mpull($users, 'getPHID');
|
|
||||||
|
|
||||||
$conpherence = id(new ConpherenceReplyHandler())
|
|
||||||
->setMailReceiver(ConpherenceThread::initializeNewRoom($sender))
|
|
||||||
->setMailAddedParticipantPHIDs($phids)
|
|
||||||
->setActor($sender)
|
|
||||||
->setExcludeMailRecipientPHIDs($mail->loadAllRecipientPHIDs())
|
|
||||||
->processEmail($mail);
|
|
||||||
|
|
||||||
if ($conpherence) {
|
|
||||||
$mail->setRelatedPHID($conpherence->getPHID());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -71,9 +71,15 @@ final class PhabricatorDaemonBulkJobViewController
|
||||||
->setUser($viewer)
|
->setUser($viewer)
|
||||||
->setObject($job);
|
->setObject($job);
|
||||||
|
|
||||||
|
if ($job->isConfirming()) {
|
||||||
|
$continue_uri = $job->getMonitorURI();
|
||||||
|
} else {
|
||||||
|
$continue_uri = $job->getDoneURI();
|
||||||
|
}
|
||||||
|
|
||||||
$actions->addAction(
|
$actions->addAction(
|
||||||
id(new PhabricatorActionView())
|
id(new PhabricatorActionView())
|
||||||
->setHref($job->getDoneURI())
|
->setHref($continue_uri)
|
||||||
->setIcon('fa-arrow-circle-o-right')
|
->setIcon('fa-arrow-circle-o-right')
|
||||||
->setName(pht('Continue')));
|
->setName(pht('Continue')));
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,26 @@ final class DifferentialCreateRawDiffConduitAPIMethod
|
||||||
$changes = $parser->parseDiff($raw_diff);
|
$changes = $parser->parseDiff($raw_diff);
|
||||||
$diff = DifferentialDiff::newFromRawChanges($viewer, $changes);
|
$diff = DifferentialDiff::newFromRawChanges($viewer, $changes);
|
||||||
|
|
||||||
|
// We're bounded by doing INSERTs for all the hunks and changesets, so
|
||||||
|
// estimate the number of inserts we'll require.
|
||||||
|
$size = 0;
|
||||||
|
foreach ($diff->getChangesets() as $changeset) {
|
||||||
|
$hunks = $changeset->getHunks();
|
||||||
|
$size += 1 + count($hunks);
|
||||||
|
}
|
||||||
|
|
||||||
|
$raw_limit = 10000;
|
||||||
|
if ($size > $raw_limit) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'The raw diff you have submitted is too large to parse (it affects '.
|
||||||
|
'more than %s paths and hunks). Differential should only be used '.
|
||||||
|
'for changes which are small enough to receive detailed human '.
|
||||||
|
'review. See "Differential User Guide: Large Changes" in the '.
|
||||||
|
'documentation for more information.',
|
||||||
|
new PhutilNumber($raw_limit)));
|
||||||
|
}
|
||||||
|
|
||||||
$diff_data_dict = array(
|
$diff_data_dict = array(
|
||||||
'creationMethod' => 'web',
|
'creationMethod' => 'web',
|
||||||
'authorPHID' => $viewer->getPHID(),
|
'authorPHID' => $viewer->getPHID(),
|
||||||
|
|
|
@ -129,8 +129,8 @@ final class DifferentialChangesetListView extends AphrontView {
|
||||||
array(
|
array(
|
||||||
'pht' => array(
|
'pht' => array(
|
||||||
'Open in Editor' => pht('Open in Editor'),
|
'Open in Editor' => pht('Open in Editor'),
|
||||||
'Show Entire File' => pht('Show Entire File'),
|
'Show All Context' => pht('Show All Context'),
|
||||||
'Entire File Shown' => pht('Entire File Shown'),
|
'All Context Shown' => pht('All Context Shown'),
|
||||||
"Can't Toggle Unloaded File" => pht("Can't Toggle Unloaded File"),
|
"Can't Toggle Unloaded File" => pht("Can't Toggle Unloaded File"),
|
||||||
'Expand File' => pht('Expand File'),
|
'Expand File' => pht('Expand File'),
|
||||||
'Collapse File' => pht('Collapse File'),
|
'Collapse File' => pht('Collapse File'),
|
||||||
|
|
|
@ -71,7 +71,7 @@ final class DiffusionLintSaveRunner extends Phobject {
|
||||||
} else if ($uuid) {
|
} else if ($uuid) {
|
||||||
$repository_query->withUUIDs(array($uuid));
|
$repository_query->withUUIDs(array($uuid));
|
||||||
} else if ($remote_uri) {
|
} else if ($remote_uri) {
|
||||||
$repository_query->withRemoteURIs(array($remote_uri));
|
$repository_query->withURIs(array($remote_uri));
|
||||||
}
|
}
|
||||||
|
|
||||||
$repository = $repository_query->executeOne();
|
$repository = $repository_query->executeOne();
|
||||||
|
|
|
@ -79,6 +79,7 @@ final class DiffusionQueryCommitsConduitAPIMethod
|
||||||
'repositoryPHID' => $commit->getRepository()->getPHID(),
|
'repositoryPHID' => $commit->getRepository()->getPHID(),
|
||||||
'identifier' => $commit->getCommitIdentifier(),
|
'identifier' => $commit->getCommitIdentifier(),
|
||||||
'epoch' => $commit->getEpoch(),
|
'epoch' => $commit->getEpoch(),
|
||||||
|
'authorEpoch' => $commit_data->getCommitDetail('authorEpoch'),
|
||||||
'uri' => $uri,
|
'uri' => $uri,
|
||||||
'isImporting' => !$commit->isImported(),
|
'isImporting' => !$commit->isImported(),
|
||||||
'summary' => $commit->getSummary(),
|
'summary' => $commit->getSummary(),
|
||||||
|
@ -99,6 +100,7 @@ final class DiffusionQueryCommitsConduitAPIMethod
|
||||||
->withIdentifier($commit->getCommitIdentifier())
|
->withIdentifier($commit->getCommitIdentifier())
|
||||||
->execute();
|
->execute();
|
||||||
|
|
||||||
|
$dict['authorEpoch'] = $lowlevel_commitref->getAuthorEpoch();
|
||||||
$dict['author'] = $lowlevel_commitref->getAuthor();
|
$dict['author'] = $lowlevel_commitref->getAuthor();
|
||||||
$dict['authorName'] = $lowlevel_commitref->getAuthorName();
|
$dict['authorName'] = $lowlevel_commitref->getAuthorName();
|
||||||
$dict['authorEmail'] = $lowlevel_commitref->getAuthorEmail();
|
$dict['authorEmail'] = $lowlevel_commitref->getAuthorEmail();
|
||||||
|
|
|
@ -1761,7 +1761,7 @@ final class DiffusionBrowseController extends DiffusionController {
|
||||||
'size' => 600,
|
'size' => 600,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
$commit->getShortName());
|
$commit->getLocalName());
|
||||||
|
|
||||||
$links[$identifier] = $commit_link;
|
$links[$identifier] = $commit_link;
|
||||||
}
|
}
|
||||||
|
|
|
@ -492,8 +492,12 @@ final class DiffusionCommitController extends DiffusionController {
|
||||||
|
|
||||||
if (!$repository->isSVN()) {
|
if (!$repository->isSVN()) {
|
||||||
$authored_info = id(new PHUIStatusItemView());
|
$authored_info = id(new PHUIStatusItemView());
|
||||||
// TODO: In Git, a distinct authorship date is available. When present,
|
|
||||||
// we should show it here.
|
$author_epoch = $data->getCommitDetail('authorEpoch');
|
||||||
|
if ($author_epoch !== null) {
|
||||||
|
$authored_info->setNote(
|
||||||
|
phabricator_datetime($author_epoch, $viewer));
|
||||||
|
}
|
||||||
|
|
||||||
if ($author_phid) {
|
if ($author_phid) {
|
||||||
$authored_info->setTarget($handles[$author_phid]->renderLink());
|
$authored_info->setTarget($handles[$author_phid]->renderLink());
|
||||||
|
|
|
@ -17,21 +17,20 @@ final class DiffusionRepositoryEditBasicController
|
||||||
|
|
||||||
$v_name = $repository->getName();
|
$v_name = $repository->getName();
|
||||||
$v_desc = $repository->getDetail('description');
|
$v_desc = $repository->getDetail('description');
|
||||||
$v_clone_name = $repository->getDetail('clone-name');
|
$v_slug = $repository->getRepositorySlug();
|
||||||
$v_projects = PhabricatorEdgeQuery::loadDestinationPHIDs(
|
$v_projects = PhabricatorEdgeQuery::loadDestinationPHIDs(
|
||||||
$repository->getPHID(),
|
$repository->getPHID(),
|
||||||
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST);
|
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST);
|
||||||
$e_name = true;
|
$e_name = true;
|
||||||
|
$e_slug = null;
|
||||||
$errors = array();
|
$errors = array();
|
||||||
|
|
||||||
|
$validation_exception = null;
|
||||||
if ($request->isFormPost()) {
|
if ($request->isFormPost()) {
|
||||||
$v_name = $request->getStr('name');
|
$v_name = $request->getStr('name');
|
||||||
$v_desc = $request->getStr('description');
|
$v_desc = $request->getStr('description');
|
||||||
$v_projects = $request->getArr('projectPHIDs');
|
$v_projects = $request->getArr('projectPHIDs');
|
||||||
|
$v_slug = $request->getStr('slug');
|
||||||
if ($repository->isHosted()) {
|
|
||||||
$v_clone_name = $request->getStr('cloneName');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!strlen($v_name)) {
|
if (!strlen($v_name)) {
|
||||||
$e_name = pht('Required');
|
$e_name = pht('Required');
|
||||||
|
@ -47,7 +46,7 @@ final class DiffusionRepositoryEditBasicController
|
||||||
$type_name = PhabricatorRepositoryTransaction::TYPE_NAME;
|
$type_name = PhabricatorRepositoryTransaction::TYPE_NAME;
|
||||||
$type_desc = PhabricatorRepositoryTransaction::TYPE_DESCRIPTION;
|
$type_desc = PhabricatorRepositoryTransaction::TYPE_DESCRIPTION;
|
||||||
$type_edge = PhabricatorTransactions::TYPE_EDGE;
|
$type_edge = PhabricatorTransactions::TYPE_EDGE;
|
||||||
$type_clone_name = PhabricatorRepositoryTransaction::TYPE_CLONE_NAME;
|
$type_slug = PhabricatorRepositoryTransaction::TYPE_SLUG;
|
||||||
|
|
||||||
$xactions[] = id(clone $template)
|
$xactions[] = id(clone $template)
|
||||||
->setTransactionType($type_name)
|
->setTransactionType($type_name)
|
||||||
|
@ -58,8 +57,8 @@ final class DiffusionRepositoryEditBasicController
|
||||||
->setNewValue($v_desc);
|
->setNewValue($v_desc);
|
||||||
|
|
||||||
$xactions[] = id(clone $template)
|
$xactions[] = id(clone $template)
|
||||||
->setTransactionType($type_clone_name)
|
->setTransactionType($type_slug)
|
||||||
->setNewValue($v_clone_name);
|
->setNewValue($v_slug);
|
||||||
|
|
||||||
$xactions[] = id(clone $template)
|
$xactions[] = id(clone $template)
|
||||||
->setTransactionType($type_edge)
|
->setTransactionType($type_edge)
|
||||||
|
@ -71,13 +70,20 @@ final class DiffusionRepositoryEditBasicController
|
||||||
'=' => array_fuse($v_projects),
|
'=' => array_fuse($v_projects),
|
||||||
));
|
));
|
||||||
|
|
||||||
id(new PhabricatorRepositoryEditor())
|
$editor = id(new PhabricatorRepositoryEditor())
|
||||||
->setContinueOnNoEffect(true)
|
->setContinueOnNoEffect(true)
|
||||||
->setContentSourceFromRequest($request)
|
->setContentSourceFromRequest($request)
|
||||||
->setActor($viewer)
|
->setActor($viewer);
|
||||||
->applyTransactions($repository, $xactions);
|
|
||||||
|
|
||||||
return id(new AphrontRedirectResponse())->setURI($edit_uri);
|
try {
|
||||||
|
$editor->applyTransactions($repository, $xactions);
|
||||||
|
|
||||||
|
return id(new AphrontRedirectResponse())->setURI($edit_uri);
|
||||||
|
} catch (PhabricatorApplicationTransactionValidationException $ex) {
|
||||||
|
$validation_exception = $ex;
|
||||||
|
|
||||||
|
$e_slug = $ex->getShortMessage($type_slug);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,22 +99,13 @@ final class DiffusionRepositoryEditBasicController
|
||||||
->setName('name')
|
->setName('name')
|
||||||
->setLabel(pht('Name'))
|
->setLabel(pht('Name'))
|
||||||
->setValue($v_name)
|
->setValue($v_name)
|
||||||
->setError($e_name));
|
->setError($e_name))
|
||||||
|
->appendChild(
|
||||||
if ($repository->isHosted()) {
|
id(new AphrontFormTextControl())
|
||||||
$form
|
->setName('slug')
|
||||||
->appendChild(
|
->setLabel(pht('Short Name'))
|
||||||
id(new AphrontFormTextControl())
|
->setValue($v_slug)
|
||||||
->setName('cloneName')
|
->setError($e_slug))
|
||||||
->setLabel(pht('Clone/Checkout As'))
|
|
||||||
->setValue($v_clone_name)
|
|
||||||
->setCaption(
|
|
||||||
pht(
|
|
||||||
'Optional directory name to use when cloning or checking out '.
|
|
||||||
'this repository.')));
|
|
||||||
}
|
|
||||||
|
|
||||||
$form
|
|
||||||
->appendChild(
|
->appendChild(
|
||||||
id(new PhabricatorRemarkupControl())
|
id(new PhabricatorRemarkupControl())
|
||||||
->setUser($viewer)
|
->setUser($viewer)
|
||||||
|
@ -130,6 +127,7 @@ final class DiffusionRepositoryEditBasicController
|
||||||
|
|
||||||
$object_box = id(new PHUIObjectBoxView())
|
$object_box = id(new PHUIObjectBoxView())
|
||||||
->setHeaderText($title)
|
->setHeaderText($title)
|
||||||
|
->setValidationException($validation_exception)
|
||||||
->setForm($form)
|
->setForm($form)
|
||||||
->setFormErrors($errors);
|
->setFormErrors($errors);
|
||||||
|
|
||||||
|
|
|
@ -286,15 +286,12 @@ final class DiffusionRepositoryEditMainController
|
||||||
$view->addProperty(pht('Type'), $type);
|
$view->addProperty(pht('Type'), $type);
|
||||||
$view->addProperty(pht('Callsign'), $repository->getCallsign());
|
$view->addProperty(pht('Callsign'), $repository->getCallsign());
|
||||||
|
|
||||||
$clone_name = $repository->getDetail('clone-name');
|
$short_name = $repository->getRepositorySlug();
|
||||||
|
if ($short_name === null) {
|
||||||
if ($repository->isHosted()) {
|
$short_name = $repository->getCloneName();
|
||||||
$view->addProperty(
|
$short_name = phutil_tag('em', array(), $short_name);
|
||||||
pht('Clone/Checkout As'),
|
|
||||||
$clone_name
|
|
||||||
? $clone_name.'/'
|
|
||||||
: phutil_tag('em', array(), $repository->getCloneName().'/'));
|
|
||||||
}
|
}
|
||||||
|
$view->addProperty(pht('Short Name'), $short_name);
|
||||||
|
|
||||||
$view->invokeWillRenderEvent();
|
$view->invokeWillRenderEvent();
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
final class DiffusionCommitRef extends Phobject {
|
final class DiffusionCommitRef extends Phobject {
|
||||||
|
|
||||||
private $message;
|
private $message;
|
||||||
|
private $authorEpoch;
|
||||||
private $authorName;
|
private $authorName;
|
||||||
private $authorEmail;
|
private $authorEmail;
|
||||||
private $committerName;
|
private $committerName;
|
||||||
|
@ -11,6 +12,7 @@ final class DiffusionCommitRef extends Phobject {
|
||||||
|
|
||||||
public static function newFromConduitResult(array $result) {
|
public static function newFromConduitResult(array $result) {
|
||||||
$ref = id(new DiffusionCommitRef())
|
$ref = id(new DiffusionCommitRef())
|
||||||
|
->setAuthorEpoch(idx($result, 'authorEpoch'))
|
||||||
->setCommitterEmail(idx($result, 'committerEmail'))
|
->setCommitterEmail(idx($result, 'committerEmail'))
|
||||||
->setCommitterName(idx($result, 'committerName'))
|
->setCommitterName(idx($result, 'committerName'))
|
||||||
->setAuthorEmail(idx($result, 'authorEmail'))
|
->setAuthorEmail(idx($result, 'authorEmail'))
|
||||||
|
@ -38,6 +40,15 @@ final class DiffusionCommitRef extends Phobject {
|
||||||
return $this->hashes;
|
return $this->hashes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setAuthorEpoch($author_epoch) {
|
||||||
|
$this->authorEpoch = $author_epoch;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAuthorEpoch() {
|
||||||
|
return $this->authorEpoch;
|
||||||
|
}
|
||||||
|
|
||||||
public function setCommitterEmail($committer_email) {
|
public function setCommitterEmail($committer_email) {
|
||||||
$this->committerEmail = $committer_email;
|
$this->committerEmail = $committer_email;
|
||||||
return $this;
|
return $this;
|
||||||
|
|
|
@ -308,6 +308,7 @@ final class DiffusionCommitHookEngine extends Phobject {
|
||||||
$rules = null;
|
$rules = null;
|
||||||
$blocking_effect = null;
|
$blocking_effect = null;
|
||||||
$blocked_update = null;
|
$blocked_update = null;
|
||||||
|
$blocking_xscript = null;
|
||||||
foreach ($updates as $update) {
|
foreach ($updates as $update) {
|
||||||
$adapter = id(clone $adapter_template)
|
$adapter = id(clone $adapter_template)
|
||||||
->setPushLog($update);
|
->setPushLog($update);
|
||||||
|
@ -332,6 +333,7 @@ final class DiffusionCommitHookEngine extends Phobject {
|
||||||
if ($effect->getAction() == $block_action) {
|
if ($effect->getAction() == $block_action) {
|
||||||
$blocking_effect = $effect;
|
$blocking_effect = $effect;
|
||||||
$blocked_update = $update;
|
$blocked_update = $update;
|
||||||
|
$blocking_xscript = $xscript;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -357,13 +359,16 @@ final class DiffusionCommitHookEngine extends Phobject {
|
||||||
throw new DiffusionCommitHookRejectException(
|
throw new DiffusionCommitHookRejectException(
|
||||||
pht(
|
pht(
|
||||||
"This push was rejected by Herald push rule %s.\n".
|
"This push was rejected by Herald push rule %s.\n".
|
||||||
"Change: %s\n".
|
" Change: %s\n".
|
||||||
" Rule: %s\n".
|
" Rule: %s\n".
|
||||||
"Reason: %s",
|
" Reason: %s\n".
|
||||||
|
"Transcript: %s",
|
||||||
$rule->getMonogram(),
|
$rule->getMonogram(),
|
||||||
$blocked_name,
|
$blocked_name,
|
||||||
$rule->getName(),
|
$rule->getName(),
|
||||||
$message));
|
$message,
|
||||||
|
PhabricatorEnv::getProductionURI(
|
||||||
|
'/herald/transcript/'.$blocking_xscript->getID().'/')));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class DiffusionRepositoryURIsIndexEngineExtension
|
||||||
|
extends PhabricatorIndexEngineExtension {
|
||||||
|
|
||||||
|
const EXTENSIONKEY = 'diffusion.repositories.uri';
|
||||||
|
|
||||||
|
public function getExtensionName() {
|
||||||
|
return pht('Repository URIs');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function shouldIndexObject($object) {
|
||||||
|
return ($object instanceof PhabricatorRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function indexObject(
|
||||||
|
PhabricatorIndexEngine $engine,
|
||||||
|
$object) {
|
||||||
|
$object->updateURIIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -52,7 +52,7 @@ final class DiffusionLowLevelCommitQuery
|
||||||
'UTF-8',
|
'UTF-8',
|
||||||
implode(
|
implode(
|
||||||
'%x00',
|
'%x00',
|
||||||
array('%e', '%cn', '%ce', '%an', '%ae', '%T', '%s%n%n%b')),
|
array('%e', '%cn', '%ce', '%an', '%ae', '%T', '%at', '%s%n%n%b')),
|
||||||
$this->identifier);
|
$this->identifier);
|
||||||
|
|
||||||
$parts = explode("\0", $info);
|
$parts = explode("\0", $info);
|
||||||
|
@ -77,13 +77,19 @@ final class DiffusionLowLevelCommitQuery
|
||||||
->setHashValue($parts[4]),
|
->setHashValue($parts[4]),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$author_epoch = (int)$parts[5];
|
||||||
|
if (!$author_epoch) {
|
||||||
|
$author_epoch = null;
|
||||||
|
}
|
||||||
|
|
||||||
return id(new DiffusionCommitRef())
|
return id(new DiffusionCommitRef())
|
||||||
->setCommitterName($parts[0])
|
->setCommitterName($parts[0])
|
||||||
->setCommitterEmail($parts[1])
|
->setCommitterEmail($parts[1])
|
||||||
->setAuthorName($parts[2])
|
->setAuthorName($parts[2])
|
||||||
->setAuthorEmail($parts[3])
|
->setAuthorEmail($parts[3])
|
||||||
->setHashes($hashes)
|
->setHashes($hashes)
|
||||||
->setMessage($parts[5]);
|
->setAuthorEpoch($author_epoch)
|
||||||
|
->setMessage($parts[6]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function loadMercurialCommitRef() {
|
private function loadMercurialCommitRef() {
|
||||||
|
|
|
@ -24,13 +24,31 @@ final class DiffusionRepositoryDatasource
|
||||||
->withDatasourceQuery($raw_query);
|
->withDatasourceQuery($raw_query);
|
||||||
$repos = $this->executeQuery($query);
|
$repos = $this->executeQuery($query);
|
||||||
|
|
||||||
|
$type_icon = id(new PhabricatorRepositoryRepositoryPHIDType())
|
||||||
|
->getTypeIcon();
|
||||||
|
|
||||||
|
$image_sprite =
|
||||||
|
"phabricator-search-icon phui-font-fa phui-icon-view {$type_icon}";
|
||||||
|
|
||||||
$results = array();
|
$results = array();
|
||||||
foreach ($repos as $repo) {
|
foreach ($repos as $repo) {
|
||||||
|
$display_name = $repo->getMonogram().' '.$repo->getName();
|
||||||
|
|
||||||
|
$name = $display_name;
|
||||||
|
$slug = $repo->getRepositorySlug();
|
||||||
|
if (strlen($slug)) {
|
||||||
|
$name = "{$name} {$slug}";
|
||||||
|
}
|
||||||
|
|
||||||
$results[] = id(new PhabricatorTypeaheadResult())
|
$results[] = id(new PhabricatorTypeaheadResult())
|
||||||
->setName($repo->getMonogram().' '.$repo->getName())
|
->setName($name)
|
||||||
|
->setDisplayName($display_name)
|
||||||
->setURI($repo->getURI())
|
->setURI($repo->getURI())
|
||||||
->setPHID($repo->getPHID())
|
->setPHID($repo->getPHID())
|
||||||
->setPriorityString($repo->getMonogram());
|
->setPriorityString($repo->getMonogram())
|
||||||
|
->setPriorityType('repo')
|
||||||
|
->setImageSprite($image_sprite)
|
||||||
|
->setDisplayType(pht('Repository'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $results;
|
return $results;
|
||||||
|
|
|
@ -128,7 +128,7 @@ abstract class DiffusionView extends AphrontView {
|
||||||
$commit,
|
$commit,
|
||||||
$summary = '') {
|
$summary = '') {
|
||||||
|
|
||||||
$commit_name = $repository->formatCommitName($commit);
|
$commit_name = $repository->formatCommitName($commit, $local = true);
|
||||||
|
|
||||||
if (strlen($summary)) {
|
if (strlen($summary)) {
|
||||||
$commit_name .= ': '.$summary;
|
$commit_name .= ': '.$summary;
|
||||||
|
|
|
@ -35,7 +35,7 @@ final class PhabricatorDivinerApplication extends PhabricatorApplication {
|
||||||
return array(
|
return array(
|
||||||
'/diviner/' => array(
|
'/diviner/' => array(
|
||||||
'' => 'DivinerMainController',
|
'' => 'DivinerMainController',
|
||||||
'query/((?<key>[^/]+)/)?' => 'DivinerAtomListController',
|
'query/((?<queryKey>[^/]+)/)?' => 'DivinerAtomListController',
|
||||||
'find/' => 'DivinerFindController',
|
'find/' => 'DivinerFindController',
|
||||||
),
|
),
|
||||||
'/book/(?P<book>[^/]+)/' => 'DivinerBookController',
|
'/book/(?P<book>[^/]+)/' => 'DivinerBookController',
|
||||||
|
|
|
@ -7,14 +7,9 @@ final class DivinerAtomListController extends DivinerController {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleRequest(AphrontRequest $request) {
|
public function handleRequest(AphrontRequest $request) {
|
||||||
$query_key = $request->getURIData('key');
|
return id(new DivinerAtomSearchEngine())
|
||||||
|
->setController($this)
|
||||||
$controller = id(new PhabricatorApplicationSearchController())
|
->buildResponse();
|
||||||
->setQueryKey($query_key)
|
|
||||||
->setSearchEngine(new DivinerAtomSearchEngine())
|
|
||||||
->setNavigation($this->buildSideNavView());
|
|
||||||
|
|
||||||
return $this->delegateToController($controller);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,19 +2,9 @@
|
||||||
|
|
||||||
abstract class DivinerController extends PhabricatorController {
|
abstract class DivinerController extends PhabricatorController {
|
||||||
|
|
||||||
protected function buildSideNavView() {
|
|
||||||
$menu = $this->buildApplicationMenu();
|
|
||||||
return AphrontSideNavFilterView::newFromMenu($menu);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function buildApplicationMenu() {
|
public function buildApplicationMenu() {
|
||||||
$menu = new PHUIListView();
|
return $this->newApplicationMenu()
|
||||||
|
->setSearchEngine(new DivinerAtomSearchEngine());
|
||||||
id(new DivinerAtomSearchEngine())
|
|
||||||
->setViewer($this->getRequest()->getViewer())
|
|
||||||
->addNavigationItems($menu);
|
|
||||||
|
|
||||||
return $menu;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function renderAtomList(array $symbols) {
|
protected function renderAtomList(array $symbols) {
|
||||||
|
|
|
@ -103,7 +103,7 @@ final class DivinerAtomSearchEngine extends PhabricatorApplicationSearchEngine {
|
||||||
|
|
||||||
protected function getBuiltinQueryNames() {
|
protected function getBuiltinQueryNames() {
|
||||||
return array(
|
return array(
|
||||||
'all' => pht('All'),
|
'all' => pht('All Atoms'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,7 @@ final class PhabricatorFilesApplication extends PhabricatorApplication {
|
||||||
return array(
|
return array(
|
||||||
'/F(?P<id>[1-9]\d*)' => 'PhabricatorFileInfoController',
|
'/F(?P<id>[1-9]\d*)' => 'PhabricatorFileInfoController',
|
||||||
'/file/' => array(
|
'/file/' => array(
|
||||||
'(query/(?P<key>[^/]+)/)?' => 'PhabricatorFileListController',
|
'(query/(?P<queryKey>[^/]+)/)?' => 'PhabricatorFileListController',
|
||||||
'upload/' => 'PhabricatorFileUploadController',
|
'upload/' => 'PhabricatorFileUploadController',
|
||||||
'dropupload/' => 'PhabricatorFileDropUploadController',
|
'dropupload/' => 'PhabricatorFileDropUploadController',
|
||||||
'compose/' => 'PhabricatorFileComposeController',
|
'compose/' => 'PhabricatorFileComposeController',
|
||||||
|
|
|
@ -2,28 +2,9 @@
|
||||||
|
|
||||||
abstract class PhabricatorFileController extends PhabricatorController {
|
abstract class PhabricatorFileController extends PhabricatorController {
|
||||||
|
|
||||||
protected function buildSideNavView() {
|
|
||||||
$menu = $this->buildMenu($for_devices = false);
|
|
||||||
return AphrontSideNavFilterView::newFromMenu($menu);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function buildApplicationMenu() {
|
public function buildApplicationMenu() {
|
||||||
return $this->buildMenu($for_devices = true);
|
return $this->newApplicationMenu()
|
||||||
|
->setSearchEngine(new PhabricatorFileSearchEngine());
|
||||||
}
|
}
|
||||||
|
|
||||||
private function buildMenu($for_devices) {
|
|
||||||
$menu = new PHUIListView();
|
|
||||||
|
|
||||||
if ($for_devices) {
|
|
||||||
$menu->newLink(pht('Upload File'), $this->getApplicationURI('/upload/'));
|
|
||||||
}
|
|
||||||
|
|
||||||
id(new PhabricatorFileSearchEngine())
|
|
||||||
->setViewer($this->getRequest()->getUser())
|
|
||||||
->addNavigationItems($menu);
|
|
||||||
|
|
||||||
return $menu;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,16 +11,14 @@ final class PhabricatorFileListController extends PhabricatorFileController {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleRequest(AphrontRequest $request) {
|
public function handleRequest(AphrontRequest $request) {
|
||||||
$controller = id(new PhabricatorApplicationSearchController())
|
return id(new PhabricatorFileSearchEngine())
|
||||||
->setQueryKey($request->getURIData('key'))
|
->setController($this)
|
||||||
->setSearchEngine(new PhabricatorFileSearchEngine())
|
->buildResponse();
|
||||||
->setNavigation($this->buildSideNavView());
|
|
||||||
|
|
||||||
return $this->delegateToController($controller);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildApplicationCrumbs() {
|
protected function buildApplicationCrumbs() {
|
||||||
$crumbs = parent::buildApplicationCrumbs();
|
$crumbs = parent::buildApplicationCrumbs();
|
||||||
|
|
||||||
$crumbs->addAction(
|
$crumbs->addAction(
|
||||||
id(new PHUIListItemView())
|
id(new PHUIListItemView())
|
||||||
->setName(pht('Upload File'))
|
->setName(pht('Upload File'))
|
||||||
|
|
|
@ -28,8 +28,14 @@ final class PhabricatorS3FileStorageEngine
|
||||||
$bucket = PhabricatorEnv::getEnvConfig('storage.s3.bucket');
|
$bucket = PhabricatorEnv::getEnvConfig('storage.s3.bucket');
|
||||||
$access_key = PhabricatorEnv::getEnvConfig('amazon-s3.access-key');
|
$access_key = PhabricatorEnv::getEnvConfig('amazon-s3.access-key');
|
||||||
$secret_key = PhabricatorEnv::getEnvConfig('amazon-s3.secret-key');
|
$secret_key = PhabricatorEnv::getEnvConfig('amazon-s3.secret-key');
|
||||||
|
$endpoint = PhabricatorEnv::getEnvConfig('amazon-s3.endpoint');
|
||||||
|
$region = PhabricatorEnv::getEnvConfig('amazon-s3.region');
|
||||||
|
|
||||||
return (strlen($bucket) && strlen($access_key) && strlen($secret_key));
|
return (strlen($bucket) &&
|
||||||
|
strlen($access_key) &&
|
||||||
|
strlen($secret_key) &&
|
||||||
|
strlen($endpoint) &&
|
||||||
|
strlen($region));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -68,11 +74,11 @@ final class PhabricatorS3FileStorageEngine
|
||||||
'type' => 's3',
|
'type' => 's3',
|
||||||
'method' => 'putObject',
|
'method' => 'putObject',
|
||||||
));
|
));
|
||||||
$s3->putObject(
|
|
||||||
$data,
|
$s3
|
||||||
$this->getBucketName(),
|
->setParametersForPutObject($name, $data)
|
||||||
$name,
|
->resolve();
|
||||||
$acl = 'private');
|
|
||||||
$profiler->endServiceCall($call_id, array());
|
$profiler->endServiceCall($call_id, array());
|
||||||
|
|
||||||
return $name;
|
return $name;
|
||||||
|
@ -84,24 +90,21 @@ final class PhabricatorS3FileStorageEngine
|
||||||
*/
|
*/
|
||||||
public function readFile($handle) {
|
public function readFile($handle) {
|
||||||
$s3 = $this->newS3API();
|
$s3 = $this->newS3API();
|
||||||
|
|
||||||
$profiler = PhutilServiceProfiler::getInstance();
|
$profiler = PhutilServiceProfiler::getInstance();
|
||||||
$call_id = $profiler->beginServiceCall(
|
$call_id = $profiler->beginServiceCall(
|
||||||
array(
|
array(
|
||||||
'type' => 's3',
|
'type' => 's3',
|
||||||
'method' => 'getObject',
|
'method' => 'getObject',
|
||||||
));
|
));
|
||||||
$result = $s3->getObject(
|
|
||||||
$this->getBucketName(),
|
$result = $s3
|
||||||
$handle);
|
->setParametersForGetObject($handle)
|
||||||
|
->resolve();
|
||||||
|
|
||||||
$profiler->endServiceCall($call_id, array());
|
$profiler->endServiceCall($call_id, array());
|
||||||
|
|
||||||
// NOTE: The implementation of the API that we're using may respond with
|
return $result;
|
||||||
// a successful result that has length 0 and no body property.
|
|
||||||
if (isset($result->body)) {
|
|
||||||
return $result->body;
|
|
||||||
} else {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -109,17 +112,20 @@ final class PhabricatorS3FileStorageEngine
|
||||||
* Delete a blob from Amazon S3.
|
* Delete a blob from Amazon S3.
|
||||||
*/
|
*/
|
||||||
public function deleteFile($handle) {
|
public function deleteFile($handle) {
|
||||||
AphrontWriteGuard::willWrite();
|
|
||||||
$s3 = $this->newS3API();
|
$s3 = $this->newS3API();
|
||||||
|
|
||||||
|
AphrontWriteGuard::willWrite();
|
||||||
$profiler = PhutilServiceProfiler::getInstance();
|
$profiler = PhutilServiceProfiler::getInstance();
|
||||||
$call_id = $profiler->beginServiceCall(
|
$call_id = $profiler->beginServiceCall(
|
||||||
array(
|
array(
|
||||||
'type' => 's3',
|
'type' => 's3',
|
||||||
'method' => 'deleteObject',
|
'method' => 'deleteObject',
|
||||||
));
|
));
|
||||||
$s3->deleteObject(
|
|
||||||
$this->getBucketName(),
|
$s3
|
||||||
$handle);
|
->setParametersForDeleteObject($handle)
|
||||||
|
->resolve();
|
||||||
|
|
||||||
$profiler->endServiceCall($call_id, array());
|
$profiler->endServiceCall($call_id, array());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,33 +153,19 @@ final class PhabricatorS3FileStorageEngine
|
||||||
* Create a new S3 API object.
|
* Create a new S3 API object.
|
||||||
*
|
*
|
||||||
* @task internal
|
* @task internal
|
||||||
* @phutil-external-symbol class S3
|
|
||||||
*/
|
*/
|
||||||
private function newS3API() {
|
private function newS3API() {
|
||||||
$libroot = dirname(phutil_get_library_root('phabricator'));
|
|
||||||
require_once $libroot.'/externals/s3/S3.php';
|
|
||||||
|
|
||||||
$access_key = PhabricatorEnv::getEnvConfig('amazon-s3.access-key');
|
$access_key = PhabricatorEnv::getEnvConfig('amazon-s3.access-key');
|
||||||
$secret_key = PhabricatorEnv::getEnvConfig('amazon-s3.secret-key');
|
$secret_key = PhabricatorEnv::getEnvConfig('amazon-s3.secret-key');
|
||||||
|
$region = PhabricatorEnv::getEnvConfig('amazon-s3.region');
|
||||||
$endpoint = PhabricatorEnv::getEnvConfig('amazon-s3.endpoint');
|
$endpoint = PhabricatorEnv::getEnvConfig('amazon-s3.endpoint');
|
||||||
|
|
||||||
if (!$access_key || !$secret_key) {
|
return id(new PhutilAWSS3Future())
|
||||||
throw new PhabricatorFileStorageConfigurationException(
|
->setAccessKey($access_key)
|
||||||
pht(
|
->setSecretKey(new PhutilOpaqueEnvelope($secret_key))
|
||||||
"Specify '%s' and '%s'!",
|
->setRegion($region)
|
||||||
'amazon-s3.access-key',
|
->setEndpoint($endpoint)
|
||||||
'amazon-s3.secret-key'));
|
->setBucket($this->getBucketName());
|
||||||
}
|
|
||||||
|
|
||||||
if ($endpoint !== null) {
|
|
||||||
$s3 = new S3($access_key, $secret_key, $use_ssl = true, $endpoint);
|
|
||||||
} else {
|
|
||||||
$s3 = new S3($access_key, $secret_key, $use_ssl = true);
|
|
||||||
}
|
|
||||||
|
|
||||||
$s3->setExceptions(true);
|
|
||||||
|
|
||||||
return $s3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,26 +4,29 @@ final class PhabricatorFileUploadException extends Exception {
|
||||||
|
|
||||||
public function __construct($code) {
|
public function __construct($code) {
|
||||||
$map = array(
|
$map = array(
|
||||||
'UPLOAD_ERR_INI_SIZE' => pht(
|
UPLOAD_ERR_INI_SIZE => pht(
|
||||||
"Uploaded file is too large: current limit is %s. To adjust ".
|
"Uploaded file is too large: current limit is %s. To adjust ".
|
||||||
"this limit change '%s' in php.ini.",
|
"this limit change '%s' in php.ini.",
|
||||||
ini_get('upload_max_filesize'),
|
ini_get('upload_max_filesize'),
|
||||||
'upload_max_filesize'),
|
'upload_max_filesize'),
|
||||||
'UPLOAD_ERR_FORM_SIZE' => pht(
|
UPLOAD_ERR_FORM_SIZE => pht(
|
||||||
'File is too large.'),
|
'File is too large.'),
|
||||||
'UPLOAD_ERR_PARTIAL' => pht(
|
UPLOAD_ERR_PARTIAL => pht(
|
||||||
'File was only partially transferred, upload did not complete.'),
|
'File was only partially transferred, upload did not complete.'),
|
||||||
'UPLOAD_ERR_NO_FILE' => pht(
|
UPLOAD_ERR_NO_FILE => pht(
|
||||||
'No file was uploaded.'),
|
'No file was uploaded.'),
|
||||||
'UPLOAD_ERR_NO_TMP_DIR' => pht(
|
UPLOAD_ERR_NO_TMP_DIR => pht(
|
||||||
'Unable to write file: temporary directory does not exist.'),
|
'Unable to write file: temporary directory does not exist.'),
|
||||||
'UPLOAD_ERR_CANT_WRITE' => pht(
|
UPLOAD_ERR_CANT_WRITE => pht(
|
||||||
'Unable to write file: failed to write to temporary directory.'),
|
'Unable to write file: failed to write to temporary directory.'),
|
||||||
'UPLOAD_ERR_EXTENSION' => pht(
|
UPLOAD_ERR_EXTENSION => pht(
|
||||||
'Unable to upload: a PHP extension stopped the upload.'),
|
'Unable to upload: a PHP extension stopped the upload.'),
|
||||||
);
|
);
|
||||||
|
|
||||||
$message = idx($map, $code, pht('Upload failed: unknown error.'));
|
$message = idx(
|
||||||
|
$map,
|
||||||
|
$code,
|
||||||
|
pht('Upload failed: unknown error (%s).', $code));
|
||||||
parent::__construct($message, $code);
|
parent::__construct($message, $code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,20 @@ final class PhabricatorFilesManagementMigrateWorkflow
|
||||||
'name' => 'dry-run',
|
'name' => 'dry-run',
|
||||||
'help' => pht('Show what would be migrated.'),
|
'help' => pht('Show what would be migrated.'),
|
||||||
),
|
),
|
||||||
|
array(
|
||||||
|
'name' => 'min-size',
|
||||||
|
'param' => 'bytes',
|
||||||
|
'help' => pht(
|
||||||
|
'Do not migrate data for files which are smaller than a given '.
|
||||||
|
'filesize.'),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'name' => 'max-size',
|
||||||
|
'param' => 'bytes',
|
||||||
|
'help' => pht(
|
||||||
|
'Do not migrate data for files which are larger than a given '.
|
||||||
|
'filesize.'),
|
||||||
|
),
|
||||||
array(
|
array(
|
||||||
'name' => 'all',
|
'name' => 'all',
|
||||||
'help' => pht('Migrate all files.'),
|
'help' => pht('Migrate all files.'),
|
||||||
|
@ -30,10 +44,8 @@ final class PhabricatorFilesManagementMigrateWorkflow
|
||||||
}
|
}
|
||||||
|
|
||||||
public function execute(PhutilArgumentParser $args) {
|
public function execute(PhutilArgumentParser $args) {
|
||||||
$console = PhutilConsole::getConsole();
|
$target_key = $args->getArg('engine');
|
||||||
|
if (!$target_key) {
|
||||||
$engine_id = $args->getArg('engine');
|
|
||||||
if (!$engine_id) {
|
|
||||||
throw new PhutilArgumentUsageException(
|
throw new PhutilArgumentUsageException(
|
||||||
pht(
|
pht(
|
||||||
'Specify an engine to migrate to with `%s`. '.
|
'Specify an engine to migrate to with `%s`. '.
|
||||||
|
@ -42,7 +54,7 @@ final class PhabricatorFilesManagementMigrateWorkflow
|
||||||
'files engines'));
|
'files engines'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$engine = PhabricatorFile::buildEngine($engine_id);
|
$target_engine = PhabricatorFile::buildEngine($target_key);
|
||||||
|
|
||||||
$iterator = $this->buildIterator($args);
|
$iterator = $this->buildIterator($args);
|
||||||
if (!$iterator) {
|
if (!$iterator) {
|
||||||
|
@ -55,63 +67,147 @@ final class PhabricatorFilesManagementMigrateWorkflow
|
||||||
|
|
||||||
$is_dry_run = $args->getArg('dry-run');
|
$is_dry_run = $args->getArg('dry-run');
|
||||||
|
|
||||||
|
$min_size = (int)$args->getArg('min-size');
|
||||||
|
$max_size = (int)$args->getArg('max-size');
|
||||||
|
|
||||||
$failed = array();
|
$failed = array();
|
||||||
|
$engines = PhabricatorFileStorageEngine::loadAllEngines();
|
||||||
|
$total_bytes = 0;
|
||||||
|
$total_files = 0;
|
||||||
foreach ($iterator as $file) {
|
foreach ($iterator as $file) {
|
||||||
$fid = 'F'.$file->getID();
|
$monogram = $file->getMonogram();
|
||||||
|
|
||||||
if ($file->getStorageEngine() == $engine_id) {
|
$engine_key = $file->getStorageEngine();
|
||||||
$console->writeOut(
|
$engine = idx($engines, $engine_key);
|
||||||
|
|
||||||
|
if (!$engine) {
|
||||||
|
echo tsprintf(
|
||||||
"%s\n",
|
"%s\n",
|
||||||
pht(
|
pht(
|
||||||
"%s: Already stored on '%s'",
|
'%s: Uses unknown storage engine "%s".',
|
||||||
$fid,
|
$monogram,
|
||||||
$engine_id));
|
$engine_key));
|
||||||
|
$failed[] = $file;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($engine->isChunkEngine()) {
|
||||||
|
echo tsprintf(
|
||||||
|
"%s\n",
|
||||||
|
pht(
|
||||||
|
'%s: Stored as chunks, no data to migrate directly.',
|
||||||
|
$monogram));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($engine_key === $target_key) {
|
||||||
|
echo tsprintf(
|
||||||
|
"%s\n",
|
||||||
|
pht(
|
||||||
|
'%s: Already stored in engine "%s".',
|
||||||
|
$monogram,
|
||||||
|
$target_key));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$byte_size = $file->getByteSize();
|
||||||
|
|
||||||
|
if ($min_size && ($byte_size < $min_size)) {
|
||||||
|
echo tsprintf(
|
||||||
|
"%s\n",
|
||||||
|
pht(
|
||||||
|
'%s: File size (%s) is smaller than minimum size (%s).',
|
||||||
|
$monogram,
|
||||||
|
phutil_format_bytes($byte_size),
|
||||||
|
phutil_format_bytes($min_size)));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($max_size && ($byte_size > $max_size)) {
|
||||||
|
echo tsprintf(
|
||||||
|
"%s\n",
|
||||||
|
pht(
|
||||||
|
'%s: File size (%s) is larger than maximum size (%s).',
|
||||||
|
$monogram,
|
||||||
|
phutil_format_bytes($byte_size),
|
||||||
|
phutil_format_bytes($max_size)));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($is_dry_run) {
|
if ($is_dry_run) {
|
||||||
$console->writeOut(
|
echo tsprintf(
|
||||||
"%s\n",
|
"%s\n",
|
||||||
pht(
|
pht(
|
||||||
"%s: Would migrate from '%s' to '%s' (dry run)",
|
'%s: (%s) Would migrate from "%s" to "%s" (dry run)...',
|
||||||
$fid,
|
$monogram,
|
||||||
$file->getStorageEngine(),
|
phutil_format_bytes($byte_size),
|
||||||
$engine_id));
|
$engine_key,
|
||||||
continue;
|
$target_key));
|
||||||
|
} else {
|
||||||
|
echo tsprintf(
|
||||||
|
"%s\n",
|
||||||
|
pht(
|
||||||
|
'%s: (%s) Migrating from "%s" to "%s"...',
|
||||||
|
$monogram,
|
||||||
|
phutil_format_bytes($byte_size),
|
||||||
|
$engine_key,
|
||||||
|
$target_key));
|
||||||
}
|
}
|
||||||
|
|
||||||
$console->writeOut(
|
|
||||||
"%s\n",
|
|
||||||
pht(
|
|
||||||
"%s: Migrating from '%s' to '%s'...",
|
|
||||||
$fid,
|
|
||||||
$file->getStorageEngine(),
|
|
||||||
$engine_id));
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$file->migrateToEngine($engine);
|
if ($is_dry_run) {
|
||||||
$console->writeOut("%s\n", pht('Done.'));
|
// Do nothing, this is a dry run.
|
||||||
|
} else {
|
||||||
|
$file->migrateToEngine($target_engine);
|
||||||
|
}
|
||||||
|
|
||||||
|
$total_files += 1;
|
||||||
|
$total_bytes += $byte_size;
|
||||||
|
|
||||||
|
echo tsprintf(
|
||||||
|
"%s\n",
|
||||||
|
pht('Done.'));
|
||||||
|
|
||||||
} catch (Exception $ex) {
|
} catch (Exception $ex) {
|
||||||
$console->writeOut("%s\n", pht('Failed!'));
|
echo tsprintf(
|
||||||
$console->writeErr("%s\n", (string)$ex);
|
"%s\n",
|
||||||
|
pht('Failed! %s', (string)$ex));
|
||||||
$failed[] = $file;
|
$failed[] = $file;
|
||||||
|
|
||||||
|
throw $ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
echo tsprintf(
|
||||||
|
"%s\n",
|
||||||
|
pht(
|
||||||
|
'Total Migrated Files: %s',
|
||||||
|
new PhutilNumber($total_files)));
|
||||||
|
|
||||||
|
echo tsprintf(
|
||||||
|
"%s\n",
|
||||||
|
pht(
|
||||||
|
'Total Migrated Bytes: %s',
|
||||||
|
phutil_format_bytes($total_bytes)));
|
||||||
|
|
||||||
|
if ($is_dry_run) {
|
||||||
|
echo tsprintf(
|
||||||
|
"%s\n",
|
||||||
|
pht(
|
||||||
|
'This was a dry run, so no real migrations were performed.'));
|
||||||
|
}
|
||||||
|
|
||||||
if ($failed) {
|
if ($failed) {
|
||||||
$console->writeOut("**%s**\n", pht('Failures!'));
|
$monograms = mpull($failed, 'getMonogram');
|
||||||
$ids = array();
|
|
||||||
foreach ($failed as $file) {
|
echo tsprintf(
|
||||||
$ids[] = 'F'.$file->getID();
|
"%s\n",
|
||||||
}
|
pht('Failures: %s.', implode(', ', $monograms)));
|
||||||
$console->writeOut("%s\n", implode(', ', $ids));
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
|
||||||
$console->writeOut("**%s**\n", pht('Success!'));
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,7 +79,7 @@ final class PhabricatorEmbedFileRemarkupRule
|
||||||
require_celerity_resource('lightbox-attachment-css');
|
require_celerity_resource('lightbox-attachment-css');
|
||||||
|
|
||||||
$attrs = array();
|
$attrs = array();
|
||||||
$image_class = null;
|
$image_class = 'phabricator-remarkup-embed-image';
|
||||||
|
|
||||||
$use_size = true;
|
$use_size = true;
|
||||||
if (!$options['size']) {
|
if (!$options['size']) {
|
||||||
|
@ -117,8 +117,6 @@ final class PhabricatorEmbedFileRemarkupRule
|
||||||
$attrs['width'] = $x;
|
$attrs['width'] = $x;
|
||||||
$attrs['height'] = $y;
|
$attrs['height'] = $y;
|
||||||
}
|
}
|
||||||
|
|
||||||
$image_class = 'phabricator-remarkup-embed-image';
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
42
src/applications/herald/phid/HeraldTranscriptPHIDType.php
Normal file
42
src/applications/herald/phid/HeraldTranscriptPHIDType.php
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class HeraldTranscriptPHIDType extends PhabricatorPHIDType {
|
||||||
|
|
||||||
|
const TYPECONST = 'HLXS';
|
||||||
|
|
||||||
|
public function getTypeName() {
|
||||||
|
return pht('Herald Transcript');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newObject() {
|
||||||
|
return new HeraldTranscript();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPHIDTypeApplicationClass() {
|
||||||
|
return 'PhabricatorHeraldApplication';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildQueryForObjects(
|
||||||
|
PhabricatorObjectQuery $query,
|
||||||
|
array $phids) {
|
||||||
|
|
||||||
|
return id(new HeraldTranscriptQuery())
|
||||||
|
->withPHIDs($phids);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadHandles(
|
||||||
|
PhabricatorHandleQuery $query,
|
||||||
|
array $handles,
|
||||||
|
array $objects) {
|
||||||
|
|
||||||
|
foreach ($handles as $phid => $handle) {
|
||||||
|
$xscript = $objects[$phid];
|
||||||
|
|
||||||
|
$id = $xscript->getID();
|
||||||
|
|
||||||
|
$handle->setName(pht('Transcript %s', $id));
|
||||||
|
$handle->setURI("/herald/transcript/${id}/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ final class HeraldTranscriptQuery
|
||||||
extends PhabricatorCursorPagedPolicyAwareQuery {
|
extends PhabricatorCursorPagedPolicyAwareQuery {
|
||||||
|
|
||||||
private $ids;
|
private $ids;
|
||||||
|
private $phids;
|
||||||
private $objectPHIDs;
|
private $objectPHIDs;
|
||||||
private $needPartialRecords;
|
private $needPartialRecords;
|
||||||
|
|
||||||
|
@ -12,6 +13,11 @@ final class HeraldTranscriptQuery
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function withPHIDs(array $phids) {
|
||||||
|
$this->phids = $phids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function withObjectPHIDs(array $phids) {
|
public function withObjectPHIDs(array $phids) {
|
||||||
$this->objectPHIDs = $phids;
|
$this->objectPHIDs = $phids;
|
||||||
return $this;
|
return $this;
|
||||||
|
@ -95,6 +101,13 @@ final class HeraldTranscriptQuery
|
||||||
$this->ids);
|
$this->ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->phids) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn_r,
|
||||||
|
'phid IN (%Ls)',
|
||||||
|
$this->phids);
|
||||||
|
}
|
||||||
|
|
||||||
if ($this->objectPHIDs) {
|
if ($this->objectPHIDs) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn_r,
|
||||||
|
|
|
@ -190,7 +190,8 @@ final class HeraldTranscript extends HeraldDAO
|
||||||
}
|
}
|
||||||
|
|
||||||
public function generatePHID() {
|
public function generatePHID() {
|
||||||
return PhabricatorPHID::generateNewPHID('HLXS');
|
return PhabricatorPHID::generateNewPHID(
|
||||||
|
HeraldTranscriptPHIDType::TYPECONST);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||||
|
|
|
@ -116,7 +116,15 @@ final class ManiphestTaskPriority extends ManiphestConstants {
|
||||||
return $config;
|
return $config;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function validateConfiguration(array $config) {
|
public static function validateConfiguration($config) {
|
||||||
|
if (!is_array($config)) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Configuration is not valid. Maniphest priority configurations '.
|
||||||
|
'must be dictionaries.',
|
||||||
|
$config));
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($config as $key => $value) {
|
foreach ($config as $key => $value) {
|
||||||
if (!ctype_digit((string)$key)) {
|
if (!ctype_digit((string)$key)) {
|
||||||
throw new Exception(
|
throw new Exception(
|
||||||
|
|
|
@ -829,6 +829,33 @@ final class ManiphestTransactionEditor
|
||||||
last($with_effect));
|
last($with_effect));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case ManiphestTransaction::TYPE_OWNER:
|
||||||
|
foreach ($xactions as $xaction) {
|
||||||
|
$old = $xaction->getOldValue();
|
||||||
|
$new = $xaction->getNewValue();
|
||||||
|
if (!strlen($new)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($new === $old) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$assignee_list = id(new PhabricatorPeopleQuery())
|
||||||
|
->setViewer($this->getActor())
|
||||||
|
->withPHIDs(array($new))
|
||||||
|
->execute();
|
||||||
|
if (!$assignee_list) {
|
||||||
|
$errors[] = new PhabricatorApplicationTransactionValidationError(
|
||||||
|
$type,
|
||||||
|
pht('Invalid'),
|
||||||
|
pht(
|
||||||
|
'User "%s" is not a valid user.',
|
||||||
|
$new),
|
||||||
|
$xaction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $errors;
|
return $errors;
|
||||||
|
|
|
@ -327,9 +327,18 @@ final class PhabricatorMetaMTAReceivedMail extends PhabricatorMetaMTADAO {
|
||||||
// really be all the headers. It would be nice to pass the raw headers
|
// really be all the headers. It would be nice to pass the raw headers
|
||||||
// through from the upper layers where possible.
|
// through from the upper layers where possible.
|
||||||
|
|
||||||
|
// On the MimeMailParser pathway, we arrive here with a list value for
|
||||||
|
// headers that appeared multiple times in the original mail. Be
|
||||||
|
// accommodating until header handling gets straightened out.
|
||||||
|
|
||||||
$headers = array();
|
$headers = array();
|
||||||
foreach ($this->headers as $key => $value) {
|
foreach ($this->headers as $key => $values) {
|
||||||
$headers[] = pht('%s: %s', $key, $value);
|
if (!is_array($values)) {
|
||||||
|
$values = array($values);
|
||||||
|
}
|
||||||
|
foreach ($values as $value) {
|
||||||
|
$headers[] = pht('%s: %s', $key, $value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$headers = implode("\n", $headers);
|
$headers = implode("\n", $headers);
|
||||||
|
|
||||||
|
|
|
@ -285,6 +285,76 @@ final class PhabricatorPolicyTestCase extends PhabricatorTestCase {
|
||||||
pht('Extended Policy with Cycle'));
|
pht('Extended Policy with Cycle'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test bulk checks of extended policies.
|
||||||
|
*
|
||||||
|
* This is testing an issue with extended policy filtering which allowed
|
||||||
|
* unusual inputs to slip objects through the filter. See D14993.
|
||||||
|
*/
|
||||||
|
public function testBulkExtendedPolicies() {
|
||||||
|
$object1 = $this->buildObject(PhabricatorPolicies::POLICY_USER)
|
||||||
|
->setPHID('PHID-TEST-1');
|
||||||
|
$object2 = $this->buildObject(PhabricatorPolicies::POLICY_USER)
|
||||||
|
->setPHID('PHID-TEST-2');
|
||||||
|
$object3 = $this->buildObject(PhabricatorPolicies::POLICY_USER)
|
||||||
|
->setPHID('PHID-TEST-3');
|
||||||
|
|
||||||
|
$extended = $this->buildObject(PhabricatorPolicies::POLICY_ADMIN)
|
||||||
|
->setPHID('PHID-TEST-999');
|
||||||
|
|
||||||
|
$object1->setExtendedPolicies(
|
||||||
|
array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW => array(
|
||||||
|
array(
|
||||||
|
$extended,
|
||||||
|
array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
$object2->setExtendedPolicies(
|
||||||
|
array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW => array(
|
||||||
|
array($extended, PhabricatorPolicyCapability::CAN_VIEW),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
$object3->setExtendedPolicies(
|
||||||
|
array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW => array(
|
||||||
|
array(
|
||||||
|
$extended,
|
||||||
|
array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
$user = $this->buildUser('user');
|
||||||
|
|
||||||
|
$visible = id(new PhabricatorPolicyFilter())
|
||||||
|
->setViewer($user)
|
||||||
|
->requireCapabilities(
|
||||||
|
array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
))
|
||||||
|
->apply(
|
||||||
|
array(
|
||||||
|
$object1,
|
||||||
|
$object2,
|
||||||
|
$object3,
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->assertEqual(array(), $visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An omnipotent user should be able to see even objects with invalid
|
* An omnipotent user should be able to see even objects with invalid
|
||||||
* policies.
|
* policies.
|
||||||
|
@ -430,10 +500,12 @@ final class PhabricatorPolicyTestCase extends PhabricatorTestCase {
|
||||||
$object->setCapabilities(
|
$object->setCapabilities(
|
||||||
array(
|
array(
|
||||||
PhabricatorPolicyCapability::CAN_VIEW,
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
));
|
));
|
||||||
$object->setPolicies(
|
$object->setPolicies(
|
||||||
array(
|
array(
|
||||||
PhabricatorPolicyCapability::CAN_VIEW => $policy,
|
PhabricatorPolicyCapability::CAN_VIEW => $policy,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT => $policy,
|
||||||
));
|
));
|
||||||
|
|
||||||
return $object;
|
return $object;
|
||||||
|
|
|
@ -321,7 +321,7 @@ final class PhabricatorPolicyFilter extends Phobject {
|
||||||
$objects_in = array();
|
$objects_in = array();
|
||||||
foreach ($structs as $struct) {
|
foreach ($structs as $struct) {
|
||||||
$extended_key = $struct['key'];
|
$extended_key = $struct['key'];
|
||||||
if (empty($extended_objects[$key])) {
|
if (empty($extended_objects[$extended_key])) {
|
||||||
// If this object has already been rejected by an earlier filtering
|
// If this object has already been rejected by an earlier filtering
|
||||||
// pass, we don't need to do any tests on it.
|
// pass, we don't need to do any tests on it.
|
||||||
continue;
|
continue;
|
||||||
|
@ -335,8 +335,8 @@ final class PhabricatorPolicyFilter extends Phobject {
|
||||||
// We weren't able to load the corresponding object, so just
|
// We weren't able to load the corresponding object, so just
|
||||||
// reject this result outright.
|
// reject this result outright.
|
||||||
|
|
||||||
$reject = $extended_objects[$key];
|
$reject = $extended_objects[$extended_key];
|
||||||
unset($extended_objects[$key]);
|
unset($extended_objects[$extended_key]);
|
||||||
|
|
||||||
// TODO: This could be friendlier.
|
// TODO: This could be friendlier.
|
||||||
$this->rejectObject($reject, false, '<bad-ref>');
|
$this->rejectObject($reject, false, '<bad-ref>');
|
||||||
|
|
|
@ -61,6 +61,8 @@ final class PhabricatorProjectApplication extends PhabricatorApplication {
|
||||||
=> 'PhabricatorProjectEditPictureController',
|
=> 'PhabricatorProjectEditPictureController',
|
||||||
$this->getEditRoutePattern('edit/')
|
$this->getEditRoutePattern('edit/')
|
||||||
=> 'PhabricatorProjectEditController',
|
=> 'PhabricatorProjectEditController',
|
||||||
|
'(?P<projectID>[1-9]\d*)/panel/'
|
||||||
|
=> $this->getPanelRouting('PhabricatorProjectPanelController'),
|
||||||
'subprojects/(?P<id>[1-9]\d*)/'
|
'subprojects/(?P<id>[1-9]\d*)/'
|
||||||
=> 'PhabricatorProjectSubprojectsController',
|
=> 'PhabricatorProjectSubprojectsController',
|
||||||
'milestones/(?P<id>[1-9]\d*)/'
|
'milestones/(?P<id>[1-9]\d*)/'
|
||||||
|
|
|
@ -3,11 +3,12 @@
|
||||||
abstract class PhabricatorProjectBoardController
|
abstract class PhabricatorProjectBoardController
|
||||||
extends PhabricatorProjectController {
|
extends PhabricatorProjectController {
|
||||||
|
|
||||||
public function buildIconNavView(PhabricatorProject $project) {
|
protected function getProfileMenu() {
|
||||||
$id = $project->getID();
|
$menu = parent::getProfileMenu();
|
||||||
$nav = parent::buildIconNavView($project);
|
|
||||||
$nav->selectFilter("board/{$id}/");
|
$menu->selectFilter(PhabricatorProject::PANEL_WORKBOARD);
|
||||||
$nav->addClass('project-board-nav');
|
$menu->addClass('project-board-nav');
|
||||||
return $nav;
|
|
||||||
|
return $menu;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -384,7 +384,7 @@ final class PhabricatorProjectBoardViewController
|
||||||
->appendChild($board)
|
->appendChild($board)
|
||||||
->addClass('project-board-wrapper');
|
->addClass('project-board-wrapper');
|
||||||
|
|
||||||
$nav = $this->buildIconNavView($project);
|
$nav = $this->getProfileMenu();
|
||||||
|
|
||||||
return $this->newPage()
|
return $this->newPage()
|
||||||
->setTitle(pht('%s Board', $project->getName()))
|
->setTitle(pht('%s Board', $project->getName()))
|
||||||
|
|
|
@ -49,15 +49,16 @@ final class PhabricatorProjectColumnDetailController
|
||||||
->setHeader($header)
|
->setHeader($header)
|
||||||
->addPropertyList($properties);
|
->addPropertyList($properties);
|
||||||
|
|
||||||
$nav = $this->buildIconNavView($project);
|
$nav = $this->getProfileMenu();
|
||||||
$nav->appendChild($box);
|
|
||||||
$nav->appendChild($timeline);
|
|
||||||
|
|
||||||
return $this->buildApplicationPage(
|
return $this->newPage()
|
||||||
$nav,
|
->setTitle($title)
|
||||||
array(
|
->setNavigation($nav)
|
||||||
'title' => $title,
|
->appendChild(
|
||||||
));
|
array(
|
||||||
|
$box,
|
||||||
|
$timeline,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function buildHeaderView(PhabricatorProjectColumn $column) {
|
private function buildHeaderView(PhabricatorProjectColumn $column) {
|
||||||
|
|
|
@ -144,13 +144,11 @@ final class PhabricatorProjectColumnEditController
|
||||||
->setValidationException($validation_exception)
|
->setValidationException($validation_exception)
|
||||||
->setForm($form);
|
->setForm($form);
|
||||||
|
|
||||||
$nav = $this->buildIconNavView($project);
|
$nav = $this->getProfileMenu();
|
||||||
$nav->appendChild($form_box);
|
|
||||||
|
|
||||||
return $this->buildApplicationPage(
|
return $this->newPage()
|
||||||
$nav,
|
->setTitle($title)
|
||||||
array(
|
->setNavigation($nav)
|
||||||
'title' => $title,
|
->appendChild($form_box);
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
abstract class PhabricatorProjectController extends PhabricatorController {
|
abstract class PhabricatorProjectController extends PhabricatorController {
|
||||||
|
|
||||||
private $project;
|
private $project;
|
||||||
|
private $profileMenu;
|
||||||
|
|
||||||
protected function setProject(PhabricatorProject $project) {
|
protected function setProject(PhabricatorProject $project) {
|
||||||
$this->project = $project;
|
$this->project = $project;
|
||||||
|
@ -17,7 +18,10 @@ abstract class PhabricatorProjectController extends PhabricatorController {
|
||||||
$viewer = $this->getViewer();
|
$viewer = $this->getViewer();
|
||||||
$request = $this->getRequest();
|
$request = $this->getRequest();
|
||||||
|
|
||||||
$id = $request->getURIData('id');
|
$id = nonempty(
|
||||||
|
$request->getURIData('projectID'),
|
||||||
|
$request->getURIData('id'));
|
||||||
|
|
||||||
$slug = $request->getURIData('slug');
|
$slug = $request->getURIData('slug');
|
||||||
|
|
||||||
if ($slug) {
|
if ($slug) {
|
||||||
|
@ -80,101 +84,33 @@ abstract class PhabricatorProjectController extends PhabricatorController {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildApplicationMenu() {
|
public function buildApplicationMenu() {
|
||||||
return $this->buildSideNavView(true)->getMenu();
|
$menu = $this->newApplicationMenu();
|
||||||
|
|
||||||
|
$profile_menu = $this->getProfileMenu();
|
||||||
|
if ($profile_menu) {
|
||||||
|
$menu->setProfileMenu($profile_menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
$menu->setSearchEngine(new PhabricatorProjectSearchEngine());
|
||||||
|
|
||||||
|
return $menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildSideNavView($for_app = false) {
|
protected function getProfileMenu() {
|
||||||
$project = $this->getProject();
|
if (!$this->profileMenu) {
|
||||||
|
$project = $this->getProject();
|
||||||
$nav = new AphrontSideNavFilterView();
|
|
||||||
$nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
|
|
||||||
|
|
||||||
$viewer = $this->getViewer();
|
|
||||||
|
|
||||||
$id = null;
|
|
||||||
if ($for_app) {
|
|
||||||
if ($project) {
|
if ($project) {
|
||||||
$id = $project->getID();
|
$viewer = $this->getViewer();
|
||||||
$nav->addFilter("profile/{$id}/", pht('Profile'));
|
|
||||||
$nav->addFilter("board/{$id}/", pht('Workboard'));
|
$engine = id(new PhabricatorProfilePanelEngine())
|
||||||
$nav->addFilter("members/{$id}/", pht('Members'));
|
->setViewer($viewer)
|
||||||
$nav->addFilter("feed/{$id}/", pht('Feed'));
|
->setProfileObject($project);
|
||||||
|
|
||||||
|
$this->profileMenu = $engine->buildNavigation();
|
||||||
}
|
}
|
||||||
$nav->addFilter('create', pht('Create Project'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$id) {
|
return $this->profileMenu;
|
||||||
id(new PhabricatorProjectSearchEngine())
|
|
||||||
->setViewer($viewer)
|
|
||||||
->addNavigationItems($nav->getMenu());
|
|
||||||
}
|
|
||||||
|
|
||||||
$nav->selectFilter(null);
|
|
||||||
|
|
||||||
return $nav;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function buildIconNavView(PhabricatorProject $project) {
|
|
||||||
$this->setProject($project);
|
|
||||||
$viewer = $this->getViewer();
|
|
||||||
$id = $project->getID();
|
|
||||||
$picture = $project->getProfileImageURI();
|
|
||||||
$name = $project->getName();
|
|
||||||
|
|
||||||
$columns = id(new PhabricatorProjectColumnQuery())
|
|
||||||
->setViewer($viewer)
|
|
||||||
->withProjectPHIDs(array($project->getPHID()))
|
|
||||||
->execute();
|
|
||||||
if ($columns) {
|
|
||||||
$board_icon = 'fa-columns';
|
|
||||||
} else {
|
|
||||||
$board_icon = 'fa-columns grey';
|
|
||||||
}
|
|
||||||
|
|
||||||
$nav = new AphrontSideNavFilterView();
|
|
||||||
$nav->setIconNav(true);
|
|
||||||
$nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
|
|
||||||
$nav->addIcon("profile/{$id}/", $name, null, $picture);
|
|
||||||
|
|
||||||
$class = 'PhabricatorManiphestApplication';
|
|
||||||
if (PhabricatorApplication::isClassInstalledForViewer($class, $viewer)) {
|
|
||||||
$phid = $project->getPHID();
|
|
||||||
$nav->addIcon("board/{$id}/", pht('Workboard'), $board_icon);
|
|
||||||
$query_uri = urisprintf(
|
|
||||||
'/maniphest/?statuses=open()&projects=%s#R',
|
|
||||||
$phid);
|
|
||||||
$nav->addIcon(null, pht('Open Tasks'), 'fa-anchor', null, $query_uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
$nav->addIcon("feed/{$id}/", pht('Feed'), 'fa-newspaper-o');
|
|
||||||
$nav->addIcon("members/{$id}/", pht('Members'), 'fa-group');
|
|
||||||
|
|
||||||
if (PhabricatorEnv::getEnvConfig('phabricator.show-prototypes')) {
|
|
||||||
if ($project->supportsSubprojects()) {
|
|
||||||
$subprojects_icon = 'fa-sitemap';
|
|
||||||
} else {
|
|
||||||
$subprojects_icon = 'fa-sitemap grey';
|
|
||||||
}
|
|
||||||
|
|
||||||
$key = PhabricatorProjectIconSet::getMilestoneIconKey();
|
|
||||||
$milestones_icon = PhabricatorProjectIconSet::getIconIcon($key);
|
|
||||||
if (!$project->supportsMilestones()) {
|
|
||||||
$milestones_icon = "{$milestones_icon} grey";
|
|
||||||
}
|
|
||||||
|
|
||||||
$nav->addIcon(
|
|
||||||
"subprojects/{$id}/",
|
|
||||||
pht('Subprojects'),
|
|
||||||
$subprojects_icon);
|
|
||||||
|
|
||||||
$nav->addIcon(
|
|
||||||
"milestones/{$id}/",
|
|
||||||
pht('Milestones'),
|
|
||||||
$milestones_icon);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return $nav;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildApplicationCrumbs() {
|
protected function buildApplicationCrumbs() {
|
||||||
|
|
|
@ -21,6 +21,8 @@ final class PhabricatorProjectEditPictureController
|
||||||
return new Aphront404Response();
|
return new Aphront404Response();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->setProject($project);
|
||||||
|
|
||||||
$edit_uri = $this->getApplicationURI('profile/'.$project->getID().'/');
|
$edit_uri = $this->getApplicationURI('profile/'.$project->getID().'/');
|
||||||
$view_uri = $this->getApplicationURI('profile/'.$project->getID().'/');
|
$view_uri = $this->getApplicationURI('profile/'.$project->getID().'/');
|
||||||
|
|
||||||
|
@ -280,15 +282,16 @@ final class PhabricatorProjectEditPictureController
|
||||||
->setHeaderText(pht('Upload New Picture'))
|
->setHeaderText(pht('Upload New Picture'))
|
||||||
->setForm($upload_form);
|
->setForm($upload_form);
|
||||||
|
|
||||||
$nav = $this->buildIconNavView($project);
|
$nav = $this->getProfileMenu();
|
||||||
$nav->selectFilter("edit/{$id}/");
|
$nav->selectFilter(PhabricatorProject::PANEL_PROFILE);
|
||||||
$nav->appendChild($form_box);
|
|
||||||
$nav->appendChild($upload_box);
|
|
||||||
|
|
||||||
return $this->buildApplicationPage(
|
return $this->newPage()
|
||||||
$nav,
|
->setTitle($title)
|
||||||
array(
|
->setNavigation($nav)
|
||||||
'title' => $title,
|
->appendChild(
|
||||||
));
|
array(
|
||||||
|
$form_box,
|
||||||
|
$upload_box,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,8 +33,8 @@ final class PhabricatorProjectFeedController
|
||||||
->setHeaderText(pht('Project Activity'))
|
->setHeaderText(pht('Project Activity'))
|
||||||
->appendChild($feed);
|
->appendChild($feed);
|
||||||
|
|
||||||
$nav = $this->buildIconNavView($project);
|
$nav = $this->getProfileMenu();
|
||||||
$nav->selectFilter("feed/{$id}/");
|
$nav->selectFilter('feed');
|
||||||
|
|
||||||
$crumbs = $this->buildApplicationCrumbs();
|
$crumbs = $this->buildApplicationCrumbs();
|
||||||
$crumbs->addTextCrumb(pht('Feed'));
|
$crumbs->addTextCrumb(pht('Feed'));
|
||||||
|
|
|
@ -8,19 +8,9 @@ final class PhabricatorProjectListController
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleRequest(AphrontRequest $request) {
|
public function handleRequest(AphrontRequest $request) {
|
||||||
$viewer = $request->getViewer();
|
return id(new PhabricatorProjectSearchEngine())
|
||||||
$query_key = $request->getURIData('queryKey');
|
->setController($this)
|
||||||
|
->buildResponse();
|
||||||
$controller = id(new PhabricatorApplicationSearchController())
|
|
||||||
->setQueryKey($query_key)
|
|
||||||
->setSearchEngine(new PhabricatorProjectSearchEngine())
|
|
||||||
->setNavigation($this->buildSideNavView());
|
|
||||||
|
|
||||||
return $this->delegateToController($controller);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function buildApplicationMenu() {
|
|
||||||
return $this->buildSideNavView(true)->getMenu();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildApplicationCrumbs() {
|
protected function buildApplicationCrumbs() {
|
||||||
|
|
|
@ -17,6 +17,8 @@ final class PhabricatorProjectMembersEditController
|
||||||
return new Aphront404Response();
|
return new Aphront404Response();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->setProject($project);
|
||||||
|
|
||||||
$member_phids = $project->getMemberPHIDs();
|
$member_phids = $project->getMemberPHIDs();
|
||||||
|
|
||||||
if ($request->isFormPost()) {
|
if ($request->isFormPost()) {
|
||||||
|
@ -95,8 +97,8 @@ final class PhabricatorProjectMembersEditController
|
||||||
|
|
||||||
$member_list = $this->renderMemberList($project, $handles);
|
$member_list = $this->renderMemberList($project, $handles);
|
||||||
|
|
||||||
$nav = $this->buildIconNavView($project);
|
$nav = $this->getProfileMenu();
|
||||||
$nav->selectFilter("members/{$id}/");
|
$nav->selectFilter(PhabricatorProject::PANEL_MEMBERS);
|
||||||
|
|
||||||
$crumbs = $this->buildApplicationCrumbs();
|
$crumbs = $this->buildApplicationCrumbs();
|
||||||
$crumbs->addTextCrumb(pht('Members'));
|
$crumbs->addTextCrumb(pht('Members'));
|
||||||
|
|
|
@ -76,8 +76,8 @@ final class PhabricatorProjectMilestonesController
|
||||||
->setProjects($milestones)
|
->setProjects($milestones)
|
||||||
->renderList());
|
->renderList());
|
||||||
|
|
||||||
$nav = $this->buildIconNavView($project);
|
$nav = $this->getProfileMenu();
|
||||||
$nav->selectFilter("milestones/{$id}/");
|
$nav->selectFilter(PhabricatorProject::PANEL_MILESTONES);
|
||||||
|
|
||||||
$crumbs = $this->buildApplicationCrumbs();
|
$crumbs = $this->buildApplicationCrumbs();
|
||||||
$crumbs->addTextCrumb(pht('Milestones'));
|
$crumbs->addTextCrumb(pht('Milestones'));
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorProjectPanelController
|
||||||
|
extends PhabricatorProjectController {
|
||||||
|
|
||||||
|
public function handleRequest(AphrontRequest $request) {
|
||||||
|
$response = $this->loadProject();
|
||||||
|
if ($response) {
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$project = $this->getProject();
|
||||||
|
|
||||||
|
return id(new PhabricatorProfilePanelEngine())
|
||||||
|
->setProfileObject($project)
|
||||||
|
->setController($this)
|
||||||
|
->buildResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -43,8 +43,8 @@ final class PhabricatorProjectProfileController
|
||||||
new PhabricatorProjectTransactionQuery());
|
new PhabricatorProjectTransactionQuery());
|
||||||
$timeline->setShouldTerminate(true);
|
$timeline->setShouldTerminate(true);
|
||||||
|
|
||||||
$nav = $this->buildIconNavView($project);
|
$nav = $this->getProfileMenu();
|
||||||
$nav->selectFilter("profile/{$id}/");
|
$nav->selectFilter(PhabricatorProject::PANEL_PROFILE);
|
||||||
|
|
||||||
$crumbs = $this->buildApplicationCrumbs();
|
$crumbs = $this->buildApplicationCrumbs();
|
||||||
|
|
||||||
|
|
|
@ -75,8 +75,8 @@ final class PhabricatorProjectSubprojectsController
|
||||||
->setProjects($subprojects)
|
->setProjects($subprojects)
|
||||||
->renderList());
|
->renderList());
|
||||||
|
|
||||||
$nav = $this->buildIconNavView($project);
|
$nav = $this->getProfileMenu();
|
||||||
$nav->selectFilter("subprojects/{$id}/");
|
$nav->selectFilter(PhabricatorProject::PANEL_SUBPROJECTS);
|
||||||
|
|
||||||
$crumbs = $this->buildApplicationCrumbs();
|
$crumbs = $this->buildApplicationCrumbs();
|
||||||
$crumbs->addTextCrumb(pht('Subprojects'));
|
$crumbs->addTextCrumb(pht('Subprojects'));
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorProjectDetailsProfilePanel
|
||||||
|
extends PhabricatorProfilePanel {
|
||||||
|
|
||||||
|
const PANELKEY = 'project.details';
|
||||||
|
|
||||||
|
public function getPanelTypeName() {
|
||||||
|
return pht('Project Details');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getDefaultName() {
|
||||||
|
return pht('Project Details');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDisplayName(
|
||||||
|
PhabricatorProfilePanelConfiguration $config) {
|
||||||
|
$name = $config->getPanelProperty('name');
|
||||||
|
|
||||||
|
if (strlen($name)) {
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->getDefaultName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildEditEngineFields(
|
||||||
|
PhabricatorProfilePanelConfiguration $config) {
|
||||||
|
return array(
|
||||||
|
id(new PhabricatorTextEditField())
|
||||||
|
->setKey('name')
|
||||||
|
->setLabel(pht('Name'))
|
||||||
|
->setPlaceholder($this->getDefaultName())
|
||||||
|
->setValue($config->getPanelProperty('name')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function newNavigationMenuItems(
|
||||||
|
PhabricatorProfilePanelConfiguration $config) {
|
||||||
|
|
||||||
|
$project = $config->getProfileObject();
|
||||||
|
|
||||||
|
$id = $project->getID();
|
||||||
|
$picture = $project->getProfileImageURI();
|
||||||
|
$name = $project->getName();
|
||||||
|
|
||||||
|
$href = "/project/profile/{$id}/";
|
||||||
|
|
||||||
|
$item = id(new PHUIListItemView())
|
||||||
|
->setRenderNameAsTooltip(true)
|
||||||
|
->setType(PHUIListItemView::TYPE_ICON_NAV)
|
||||||
|
->setHref($href)
|
||||||
|
->setName($name)
|
||||||
|
->setProfileImage($picture);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
$item,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorProjectMembersProfilePanel
|
||||||
|
extends PhabricatorProfilePanel {
|
||||||
|
|
||||||
|
const PANELKEY = 'project.members';
|
||||||
|
|
||||||
|
public function getPanelTypeName() {
|
||||||
|
return pht('Project Members');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getDefaultName() {
|
||||||
|
return pht('Members');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDisplayName(
|
||||||
|
PhabricatorProfilePanelConfiguration $config) {
|
||||||
|
$name = $config->getPanelProperty('name');
|
||||||
|
|
||||||
|
if (strlen($name)) {
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->getDefaultName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildEditEngineFields(
|
||||||
|
PhabricatorProfilePanelConfiguration $config) {
|
||||||
|
return array(
|
||||||
|
id(new PhabricatorTextEditField())
|
||||||
|
->setKey('name')
|
||||||
|
->setLabel(pht('Name'))
|
||||||
|
->setPlaceholder($this->getDefaultName())
|
||||||
|
->setValue($config->getPanelProperty('name')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function newNavigationMenuItems(
|
||||||
|
PhabricatorProfilePanelConfiguration $config) {
|
||||||
|
|
||||||
|
$project = $config->getProfileObject();
|
||||||
|
|
||||||
|
$id = $project->getID();
|
||||||
|
|
||||||
|
$name = $this->getDisplayName($config);
|
||||||
|
$icon = 'fa-group';
|
||||||
|
$href = "/project/members/{$id}/";
|
||||||
|
|
||||||
|
$item = id(new PHUIListItemView())
|
||||||
|
->setRenderNameAsTooltip(true)
|
||||||
|
->setType(PHUIListItemView::TYPE_ICON_NAV)
|
||||||
|
->setHref($href)
|
||||||
|
->setName($name)
|
||||||
|
->setIcon($icon);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
$item,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorProjectWorkboardProfilePanel
|
||||||
|
extends PhabricatorProfilePanel {
|
||||||
|
|
||||||
|
const PANELKEY = 'project.workboard';
|
||||||
|
|
||||||
|
public function getPanelTypeName() {
|
||||||
|
return pht('Project Workboard');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getDefaultName() {
|
||||||
|
return pht('Workboard');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDisplayName(
|
||||||
|
PhabricatorProfilePanelConfiguration $config) {
|
||||||
|
$name = $config->getPanelProperty('name');
|
||||||
|
|
||||||
|
if (strlen($name)) {
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->getDefaultName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildEditEngineFields(
|
||||||
|
PhabricatorProfilePanelConfiguration $config) {
|
||||||
|
return array(
|
||||||
|
id(new PhabricatorTextEditField())
|
||||||
|
->setKey('name')
|
||||||
|
->setLabel(pht('Name'))
|
||||||
|
->setPlaceholder($this->getDefaultName())
|
||||||
|
->setValue($config->getPanelProperty('name')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function newNavigationMenuItems(
|
||||||
|
PhabricatorProfilePanelConfiguration $config) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
// Workboards are only available if Maniphest is installed.
|
||||||
|
$class = 'PhabricatorManiphestApplication';
|
||||||
|
if (!PhabricatorApplication::isClassInstalledForViewer($class, $viewer)) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$project = $config->getProfileObject();
|
||||||
|
|
||||||
|
$columns = id(new PhabricatorProjectColumnQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withProjectPHIDs(array($project->getPHID()))
|
||||||
|
->execute();
|
||||||
|
if ($columns) {
|
||||||
|
$icon = 'fa-columns';
|
||||||
|
} else {
|
||||||
|
$icon = 'fa-columns grey';
|
||||||
|
}
|
||||||
|
|
||||||
|
$id = $project->getID();
|
||||||
|
$href = "/project/board/{$id}/";
|
||||||
|
$name = $this->getDisplayName($config);
|
||||||
|
|
||||||
|
$item = id(new PHUIListItemView())
|
||||||
|
->setRenderNameAsTooltip(true)
|
||||||
|
->setType(PHUIListItemView::TYPE_ICON_NAV)
|
||||||
|
->setHref($href)
|
||||||
|
->setName($name)
|
||||||
|
->setIcon($icon);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
$item,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -32,7 +32,7 @@ final class ProjectRemarkupRule extends PhabricatorObjectRemarkupRule {
|
||||||
// controlling and these names should parse correctly.
|
// controlling and these names should parse correctly.
|
||||||
|
|
||||||
// These characters may never appear anywhere in a hashtag.
|
// These characters may never appear anywhere in a hashtag.
|
||||||
$never = '\s?!,:;{}#\\(\\)"\'';
|
$never = '\s?!,:;{}#\\(\\)"\'\\*/~';
|
||||||
|
|
||||||
// These characters may not appear at the edge of the string.
|
// These characters may not appear at the edge of the string.
|
||||||
$never_edge = '.';
|
$never_edge = '.';
|
||||||
|
|
|
@ -125,6 +125,16 @@ final class ProjectRemarkupRuleTestCase extends PhabricatorTestCase {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
'**#orbital**' => array(
|
||||||
|
'embed' => array(),
|
||||||
|
'ref' => array(
|
||||||
|
array(
|
||||||
|
'offset' => 3,
|
||||||
|
'id' => 'orbital',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
foreach ($cases as $input => $expect) {
|
foreach ($cases as $input => $expect) {
|
||||||
|
|
|
@ -10,7 +10,8 @@ final class PhabricatorProject extends PhabricatorProjectDAO
|
||||||
PhabricatorCustomFieldInterface,
|
PhabricatorCustomFieldInterface,
|
||||||
PhabricatorDestructibleInterface,
|
PhabricatorDestructibleInterface,
|
||||||
PhabricatorFulltextInterface,
|
PhabricatorFulltextInterface,
|
||||||
PhabricatorConduitResultInterface {
|
PhabricatorConduitResultInterface,
|
||||||
|
PhabricatorProfilePanelInterface {
|
||||||
|
|
||||||
protected $name;
|
protected $name;
|
||||||
protected $status = PhabricatorProjectStatus::STATUS_ACTIVE;
|
protected $status = PhabricatorProjectStatus::STATUS_ACTIVE;
|
||||||
|
@ -49,6 +50,12 @@ final class PhabricatorProject extends PhabricatorProjectDAO
|
||||||
|
|
||||||
const TABLE_DATASOURCE_TOKEN = 'project_datasourcetoken';
|
const TABLE_DATASOURCE_TOKEN = 'project_datasourcetoken';
|
||||||
|
|
||||||
|
const PANEL_PROFILE = 'project.profile';
|
||||||
|
const PANEL_WORKBOARD = 'project.workboard';
|
||||||
|
const PANEL_MEMBERS = 'project.members';
|
||||||
|
const PANEL_MILESTONES = 'project.milestones';
|
||||||
|
const PANEL_SUBPROJECTS = 'project.subprojects';
|
||||||
|
|
||||||
public static function initializeNewProject(PhabricatorUser $actor) {
|
public static function initializeNewProject(PhabricatorUser $actor) {
|
||||||
$app = id(new PhabricatorApplicationQuery())
|
$app = id(new PhabricatorApplicationQuery())
|
||||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||||
|
@ -644,4 +651,47 @@ final class PhabricatorProject extends PhabricatorProjectDAO
|
||||||
return array();
|
return array();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( PhabricatorProfilePanelInterface )----------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function getBuiltinProfilePanels() {
|
||||||
|
$panels = array();
|
||||||
|
|
||||||
|
$panels[] = PhabricatorProfilePanelConfiguration::initializeNewBuiltin()
|
||||||
|
->setBuiltinKey(self::PANEL_PROFILE)
|
||||||
|
->setPanelKey(PhabricatorProjectDetailsProfilePanel::PANELKEY);
|
||||||
|
|
||||||
|
$panels[] = PhabricatorProfilePanelConfiguration::initializeNewBuiltin()
|
||||||
|
->setBuiltinKey(self::PANEL_WORKBOARD)
|
||||||
|
->setPanelKey(PhabricatorProjectWorkboardProfilePanel::PANELKEY);
|
||||||
|
|
||||||
|
// TODO: This is temporary.
|
||||||
|
$uri = urisprintf(
|
||||||
|
'/maniphest/?statuses=open()&projects=%s#R',
|
||||||
|
$this->getPHID());
|
||||||
|
|
||||||
|
$panels[] = PhabricatorProfilePanelConfiguration::initializeNewBuiltin()
|
||||||
|
->setBuiltinKey('tasks')
|
||||||
|
->setPanelKey(PhabricatorLinkProfilePanel::PANELKEY)
|
||||||
|
->setPanelProperty('icon', 'maniphest')
|
||||||
|
->setPanelProperty('name', pht('Open Tasks'))
|
||||||
|
->setPanelProperty('uri', $uri);
|
||||||
|
|
||||||
|
// TODO: This is temporary.
|
||||||
|
$id = $this->getID();
|
||||||
|
$panels[] = PhabricatorProfilePanelConfiguration::initializeNewBuiltin()
|
||||||
|
->setBuiltinKey('feed')
|
||||||
|
->setPanelKey(PhabricatorLinkProfilePanel::PANELKEY)
|
||||||
|
->setPanelProperty('icon', 'feed')
|
||||||
|
->setPanelProperty('name', pht('Feed'))
|
||||||
|
->setPanelProperty('uri', "/project/feed/{$id}/");
|
||||||
|
|
||||||
|
$panels[] = PhabricatorProfilePanelConfiguration::initializeNewBuiltin()
|
||||||
|
->setBuiltinKey(self::PANEL_MEMBERS)
|
||||||
|
->setPanelKey(PhabricatorProjectMembersProfilePanel::PANELKEY);
|
||||||
|
|
||||||
|
return $panels;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,10 +63,16 @@ final class PhabricatorProjectLogicalViewerDatasource
|
||||||
$phids = mpull($projects, 'getPHID');
|
$phids = mpull($projects, 'getPHID');
|
||||||
|
|
||||||
$results = array();
|
$results = array();
|
||||||
foreach ($phids as $phid) {
|
if ($phids) {
|
||||||
|
foreach ($phids as $phid) {
|
||||||
|
$results[] = new PhabricatorQueryConstraint(
|
||||||
|
PhabricatorQueryConstraint::OPERATOR_OR,
|
||||||
|
$phid);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
$results[] = new PhabricatorQueryConstraint(
|
$results[] = new PhabricatorQueryConstraint(
|
||||||
PhabricatorQueryConstraint::OPERATOR_OR,
|
PhabricatorQueryConstraint::OPERATOR_EMPTY,
|
||||||
$phid);
|
null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $results;
|
return $results;
|
||||||
|
|
|
@ -10,12 +10,7 @@ final class ReleephDefaultFieldSelector extends ReleephFieldSelector {
|
||||||
* as possible. This obivously is an abomination. -epriestley
|
* as possible. This obivously is an abomination. -epriestley
|
||||||
*/
|
*/
|
||||||
public static function isFacebook() {
|
public static function isFacebook() {
|
||||||
try {
|
return class_exists('ReleephFacebookKarmaFieldSpecification');
|
||||||
class_exists('ReleephFacebookKarmaFieldSpecification');
|
|
||||||
return true;
|
|
||||||
} catch (Exception $ex) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -63,7 +63,7 @@ final class RepositoryQueryConduitAPIMethod
|
||||||
|
|
||||||
$remote_uris = $request->getValue('remoteURIs', array());
|
$remote_uris = $request->getValue('remoteURIs', array());
|
||||||
if ($remote_uris) {
|
if ($remote_uris) {
|
||||||
$query->withRemoteURIs($remote_uris);
|
$query->withURIs($remote_uris);
|
||||||
}
|
}
|
||||||
|
|
||||||
$uuids = $request->getValue('uuids', array());
|
$uuids = $request->getValue('uuids', array());
|
||||||
|
|
|
@ -39,7 +39,7 @@ final class PhabricatorRepositoryEditor
|
||||||
$types[] = PhabricatorRepositoryTransaction::TYPE_PUSH_POLICY;
|
$types[] = PhabricatorRepositoryTransaction::TYPE_PUSH_POLICY;
|
||||||
$types[] = PhabricatorRepositoryTransaction::TYPE_CREDENTIAL;
|
$types[] = PhabricatorRepositoryTransaction::TYPE_CREDENTIAL;
|
||||||
$types[] = PhabricatorRepositoryTransaction::TYPE_DANGEROUS;
|
$types[] = PhabricatorRepositoryTransaction::TYPE_DANGEROUS;
|
||||||
$types[] = PhabricatorRepositoryTransaction::TYPE_CLONE_NAME;
|
$types[] = PhabricatorRepositoryTransaction::TYPE_SLUG;
|
||||||
$types[] = PhabricatorRepositoryTransaction::TYPE_SERVICE;
|
$types[] = PhabricatorRepositoryTransaction::TYPE_SERVICE;
|
||||||
$types[] = PhabricatorRepositoryTransaction::TYPE_SYMBOLS_LANGUAGE;
|
$types[] = PhabricatorRepositoryTransaction::TYPE_SYMBOLS_LANGUAGE;
|
||||||
$types[] = PhabricatorRepositoryTransaction::TYPE_SYMBOLS_SOURCES;
|
$types[] = PhabricatorRepositoryTransaction::TYPE_SYMBOLS_SOURCES;
|
||||||
|
@ -98,8 +98,8 @@ final class PhabricatorRepositoryEditor
|
||||||
return $object->getCredentialPHID();
|
return $object->getCredentialPHID();
|
||||||
case PhabricatorRepositoryTransaction::TYPE_DANGEROUS:
|
case PhabricatorRepositoryTransaction::TYPE_DANGEROUS:
|
||||||
return $object->shouldAllowDangerousChanges();
|
return $object->shouldAllowDangerousChanges();
|
||||||
case PhabricatorRepositoryTransaction::TYPE_CLONE_NAME:
|
case PhabricatorRepositoryTransaction::TYPE_SLUG:
|
||||||
return $object->getDetail('clone-name');
|
return $object->getRepositorySlug();
|
||||||
case PhabricatorRepositoryTransaction::TYPE_SERVICE:
|
case PhabricatorRepositoryTransaction::TYPE_SERVICE:
|
||||||
return $object->getAlmanacServicePHID();
|
return $object->getAlmanacServicePHID();
|
||||||
case PhabricatorRepositoryTransaction::TYPE_SYMBOLS_LANGUAGE:
|
case PhabricatorRepositoryTransaction::TYPE_SYMBOLS_LANGUAGE:
|
||||||
|
@ -141,13 +141,18 @@ final class PhabricatorRepositoryEditor
|
||||||
case PhabricatorRepositoryTransaction::TYPE_PUSH_POLICY:
|
case PhabricatorRepositoryTransaction::TYPE_PUSH_POLICY:
|
||||||
case PhabricatorRepositoryTransaction::TYPE_CREDENTIAL:
|
case PhabricatorRepositoryTransaction::TYPE_CREDENTIAL:
|
||||||
case PhabricatorRepositoryTransaction::TYPE_DANGEROUS:
|
case PhabricatorRepositoryTransaction::TYPE_DANGEROUS:
|
||||||
case PhabricatorRepositoryTransaction::TYPE_CLONE_NAME:
|
|
||||||
case PhabricatorRepositoryTransaction::TYPE_SERVICE:
|
case PhabricatorRepositoryTransaction::TYPE_SERVICE:
|
||||||
case PhabricatorRepositoryTransaction::TYPE_SYMBOLS_LANGUAGE:
|
case PhabricatorRepositoryTransaction::TYPE_SYMBOLS_LANGUAGE:
|
||||||
case PhabricatorRepositoryTransaction::TYPE_SYMBOLS_SOURCES:
|
case PhabricatorRepositoryTransaction::TYPE_SYMBOLS_SOURCES:
|
||||||
case PhabricatorRepositoryTransaction::TYPE_STAGING_URI:
|
case PhabricatorRepositoryTransaction::TYPE_STAGING_URI:
|
||||||
case PhabricatorRepositoryTransaction::TYPE_AUTOMATION_BLUEPRINTS:
|
case PhabricatorRepositoryTransaction::TYPE_AUTOMATION_BLUEPRINTS:
|
||||||
return $xaction->getNewValue();
|
return $xaction->getNewValue();
|
||||||
|
case PhabricatorRepositoryTransaction::TYPE_SLUG:
|
||||||
|
$name = $xaction->getNewValue();
|
||||||
|
if (strlen($name)) {
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
case PhabricatorRepositoryTransaction::TYPE_NOTIFY:
|
case PhabricatorRepositoryTransaction::TYPE_NOTIFY:
|
||||||
case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE:
|
case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE:
|
||||||
return (int)$xaction->getNewValue();
|
return (int)$xaction->getNewValue();
|
||||||
|
@ -215,8 +220,8 @@ final class PhabricatorRepositoryEditor
|
||||||
case PhabricatorRepositoryTransaction::TYPE_DANGEROUS:
|
case PhabricatorRepositoryTransaction::TYPE_DANGEROUS:
|
||||||
$object->setDetail('allow-dangerous-changes', $xaction->getNewValue());
|
$object->setDetail('allow-dangerous-changes', $xaction->getNewValue());
|
||||||
return;
|
return;
|
||||||
case PhabricatorRepositoryTransaction::TYPE_CLONE_NAME:
|
case PhabricatorRepositoryTransaction::TYPE_SLUG:
|
||||||
$object->setDetail('clone-name', $xaction->getNewValue());
|
$object->setRepositorySlug($xaction->getNewValue());
|
||||||
return;
|
return;
|
||||||
case PhabricatorRepositoryTransaction::TYPE_SERVICE:
|
case PhabricatorRepositoryTransaction::TYPE_SERVICE:
|
||||||
$object->setAlmanacServicePHID($xaction->getNewValue());
|
$object->setAlmanacServicePHID($xaction->getNewValue());
|
||||||
|
@ -326,7 +331,7 @@ final class PhabricatorRepositoryEditor
|
||||||
case PhabricatorRepositoryTransaction::TYPE_PUSH_POLICY:
|
case PhabricatorRepositoryTransaction::TYPE_PUSH_POLICY:
|
||||||
case PhabricatorRepositoryTransaction::TYPE_CREDENTIAL:
|
case PhabricatorRepositoryTransaction::TYPE_CREDENTIAL:
|
||||||
case PhabricatorRepositoryTransaction::TYPE_DANGEROUS:
|
case PhabricatorRepositoryTransaction::TYPE_DANGEROUS:
|
||||||
case PhabricatorRepositoryTransaction::TYPE_CLONE_NAME:
|
case PhabricatorRepositoryTransaction::TYPE_SLUG:
|
||||||
case PhabricatorRepositoryTransaction::TYPE_SERVICE:
|
case PhabricatorRepositoryTransaction::TYPE_SERVICE:
|
||||||
case PhabricatorRepositoryTransaction::TYPE_SYMBOLS_SOURCES:
|
case PhabricatorRepositoryTransaction::TYPE_SYMBOLS_SOURCES:
|
||||||
case PhabricatorRepositoryTransaction::TYPE_SYMBOLS_LANGUAGE:
|
case PhabricatorRepositoryTransaction::TYPE_SYMBOLS_LANGUAGE:
|
||||||
|
@ -448,9 +453,73 @@ final class PhabricatorRepositoryEditor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PhabricatorRepositoryTransaction::TYPE_SLUG:
|
||||||
|
foreach ($xactions as $xaction) {
|
||||||
|
$old = $xaction->getOldValue();
|
||||||
|
$new = $xaction->getNewValue();
|
||||||
|
|
||||||
|
if (!strlen($new)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($new === $old) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
PhabricatorRepository::asssertValidRepositorySlug($new);
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
$errors[] = new PhabricatorApplicationTransactionValidationError(
|
||||||
|
$type,
|
||||||
|
pht('Invalid'),
|
||||||
|
$ex->getMessage(),
|
||||||
|
$xaction);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$other = id(new PhabricatorRepositoryQuery())
|
||||||
|
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||||
|
->withSlugs(array($new))
|
||||||
|
->executeOne();
|
||||||
|
if ($other && ($other->getID() !== $object->getID())) {
|
||||||
|
$errors[] = new PhabricatorApplicationTransactionValidationError(
|
||||||
|
$type,
|
||||||
|
pht('Duplicate'),
|
||||||
|
pht(
|
||||||
|
'The selected repository short name is already in use by '.
|
||||||
|
'another repository. Choose a unique short name.'),
|
||||||
|
$xaction);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $errors;
|
return $errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function didCatchDuplicateKeyException(
|
||||||
|
PhabricatorLiskDAO $object,
|
||||||
|
array $xactions,
|
||||||
|
Exception $ex) {
|
||||||
|
|
||||||
|
$errors = array();
|
||||||
|
|
||||||
|
$errors[] = new PhabricatorApplicationTransactionValidationError(
|
||||||
|
null,
|
||||||
|
pht('Invalid'),
|
||||||
|
pht(
|
||||||
|
'The chosen callsign or repository short name is already in '.
|
||||||
|
'use by another repository.'),
|
||||||
|
null);
|
||||||
|
|
||||||
|
throw new PhabricatorApplicationTransactionValidationException($errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function supportsSearch() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ final class PhabricatorRepositoryRepositoryPHIDType
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTypeIcon() {
|
public function getTypeIcon() {
|
||||||
return 'fa-database';
|
return 'fa-code';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function newObject() {
|
public function newObject() {
|
||||||
|
|
|
@ -9,13 +9,15 @@ final class PhabricatorRepositoryQuery
|
||||||
private $types;
|
private $types;
|
||||||
private $uuids;
|
private $uuids;
|
||||||
private $nameContains;
|
private $nameContains;
|
||||||
private $remoteURIs;
|
private $uris;
|
||||||
private $datasourceQuery;
|
private $datasourceQuery;
|
||||||
|
private $slugs;
|
||||||
|
|
||||||
private $numericIdentifiers;
|
private $numericIdentifiers;
|
||||||
private $callsignIdentifiers;
|
private $callsignIdentifiers;
|
||||||
private $phidIdentifiers;
|
private $phidIdentifiers;
|
||||||
private $monogramIdentifiers;
|
private $monogramIdentifiers;
|
||||||
|
private $slugIdentifiers;
|
||||||
|
|
||||||
private $identifierMap;
|
private $identifierMap;
|
||||||
|
|
||||||
|
@ -55,26 +57,38 @@ final class PhabricatorRepositoryQuery
|
||||||
$callsigns = array();
|
$callsigns = array();
|
||||||
$phids = array();
|
$phids = array();
|
||||||
$monograms = array();
|
$monograms = array();
|
||||||
|
$slugs = array();
|
||||||
|
|
||||||
foreach ($identifiers as $identifier) {
|
foreach ($identifiers as $identifier) {
|
||||||
if (ctype_digit((string)$identifier)) {
|
if (ctype_digit((string)$identifier)) {
|
||||||
$ids[$identifier] = $identifier;
|
$ids[$identifier] = $identifier;
|
||||||
} else if (preg_match('/^(r[A-Z]+)|(R[1-9]\d*)\z/', $identifier)) {
|
continue;
|
||||||
$monograms[$identifier] = $identifier;
|
|
||||||
} else {
|
|
||||||
$repository_type = PhabricatorRepositoryRepositoryPHIDType::TYPECONST;
|
|
||||||
if (phid_get_type($identifier) === $repository_type) {
|
|
||||||
$phids[$identifier] = $identifier;
|
|
||||||
} else {
|
|
||||||
$callsigns[$identifier] = $identifier;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (preg_match('/^(r[A-Z]+)|(R[1-9]\d*)\z/', $identifier)) {
|
||||||
|
$monograms[$identifier] = $identifier;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$repository_type = PhabricatorRepositoryRepositoryPHIDType::TYPECONST;
|
||||||
|
if (phid_get_type($identifier) === $repository_type) {
|
||||||
|
$phids[$identifier] = $identifier;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preg_match('/^[A-Z]+\z/', $identifier)) {
|
||||||
|
$callsigns[$identifier] = $identifier;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$slugs[$identifier] = $identifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->numericIdentifiers = $ids;
|
$this->numericIdentifiers = $ids;
|
||||||
$this->callsignIdentifiers = $callsigns;
|
$this->callsignIdentifiers = $callsigns;
|
||||||
$this->phidIdentifiers = $phids;
|
$this->phidIdentifiers = $phids;
|
||||||
$this->monogramIdentifiers = $monograms;
|
$this->monogramIdentifiers = $monograms;
|
||||||
|
$this->slugIdentifiers = $slugs;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
@ -104,8 +118,8 @@ final class PhabricatorRepositoryQuery
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function withRemoteURIs(array $uris) {
|
public function withURIs(array $uris) {
|
||||||
$this->remoteURIs = $uris;
|
$this->uris = $uris;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,6 +128,11 @@ final class PhabricatorRepositoryQuery
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function withSlugs(array $slugs) {
|
||||||
|
$this->slugs = $slugs;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function needCommitCounts($need_counts) {
|
public function needCommitCounts($need_counts) {
|
||||||
$this->needCommitCounts = $need_counts;
|
$this->needCommitCounts = $need_counts;
|
||||||
return $this;
|
return $this;
|
||||||
|
@ -244,17 +263,6 @@ final class PhabricatorRepositoryQuery
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Denormalize this, too.
|
|
||||||
if ($this->remoteURIs) {
|
|
||||||
$try_uris = $this->getNormalizedPaths();
|
|
||||||
$try_uris = array_fuse($try_uris);
|
|
||||||
foreach ($repositories as $key => $repository) {
|
|
||||||
if (!isset($try_uris[$repository->getNormalizedPath()])) {
|
|
||||||
unset($repositories[$key]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the identifierMap
|
// Build the identifierMap
|
||||||
if ($this->numericIdentifiers) {
|
if ($this->numericIdentifiers) {
|
||||||
foreach ($this->numericIdentifiers as $id) {
|
foreach ($this->numericIdentifiers as $id) {
|
||||||
|
@ -299,6 +307,26 @@ final class PhabricatorRepositoryQuery
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->slugIdentifiers) {
|
||||||
|
$slug_map = array();
|
||||||
|
foreach ($repositories as $repository) {
|
||||||
|
$slug = $repository->getRepositorySlug();
|
||||||
|
if ($slug === null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$normal = phutil_utf8_strtolower($slug);
|
||||||
|
$slug_map[$normal] = $repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->slugIdentifiers as $slug) {
|
||||||
|
$normal = phutil_utf8_strtolower($slug);
|
||||||
|
if (isset($slug_map[$normal])) {
|
||||||
|
$this->identifierMap[$slug] = $slug_map[$normal];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $repositories;
|
return $repositories;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,6 +434,8 @@ final class PhabricatorRepositoryQuery
|
||||||
protected function buildSelectClauseParts(AphrontDatabaseConnection $conn) {
|
protected function buildSelectClauseParts(AphrontDatabaseConnection $conn) {
|
||||||
$parts = parent::buildSelectClauseParts($conn);
|
$parts = parent::buildSelectClauseParts($conn);
|
||||||
|
|
||||||
|
$parts[] = 'r.*';
|
||||||
|
|
||||||
if ($this->shouldJoinSummaryTable()) {
|
if ($this->shouldJoinSummaryTable()) {
|
||||||
$parts[] = 's.*';
|
$parts[] = 's.*';
|
||||||
}
|
}
|
||||||
|
@ -423,9 +453,28 @@ final class PhabricatorRepositoryQuery
|
||||||
PhabricatorRepository::TABLE_SUMMARY);
|
PhabricatorRepository::TABLE_SUMMARY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->shouldJoinURITable()) {
|
||||||
|
$joins[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'LEFT JOIN %T uri ON r.phid = uri.repositoryPHID',
|
||||||
|
id(new PhabricatorRepositoryURIIndex())->getTableName());
|
||||||
|
}
|
||||||
|
|
||||||
return $joins;
|
return $joins;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function shouldGroupQueryResultRows() {
|
||||||
|
if ($this->shouldJoinURITable()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::shouldGroupQueryResultRows();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function shouldJoinURITable() {
|
||||||
|
return ($this->uris !== null);
|
||||||
|
}
|
||||||
|
|
||||||
private function shouldJoinSummaryTable() {
|
private function shouldJoinSummaryTable() {
|
||||||
if ($this->needCommitCounts) {
|
if ($this->needCommitCounts) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -474,7 +523,8 @@ final class PhabricatorRepositoryQuery
|
||||||
if ($this->numericIdentifiers ||
|
if ($this->numericIdentifiers ||
|
||||||
$this->callsignIdentifiers ||
|
$this->callsignIdentifiers ||
|
||||||
$this->phidIdentifiers ||
|
$this->phidIdentifiers ||
|
||||||
$this->monogramIdentifiers) {
|
$this->monogramIdentifiers ||
|
||||||
|
$this->slugIdentifiers) {
|
||||||
$identifier_clause = array();
|
$identifier_clause = array();
|
||||||
|
|
||||||
if ($this->numericIdentifiers) {
|
if ($this->numericIdentifiers) {
|
||||||
|
@ -525,6 +575,13 @@ final class PhabricatorRepositoryQuery
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->slugIdentifiers) {
|
||||||
|
$identifier_clause[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'r.repositorySlug IN (%Ls)',
|
||||||
|
$this->slugIdentifiers);
|
||||||
|
}
|
||||||
|
|
||||||
$where = array('('.implode(' OR ', $identifier_clause).')');
|
$where = array('('.implode(' OR ', $identifier_clause).')');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -545,7 +602,7 @@ final class PhabricatorRepositoryQuery
|
||||||
if (strlen($this->nameContains)) {
|
if (strlen($this->nameContains)) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn,
|
$conn,
|
||||||
'name LIKE %~',
|
'r.name LIKE %~',
|
||||||
$this->nameContains);
|
$this->nameContains);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -559,9 +616,27 @@ final class PhabricatorRepositoryQuery
|
||||||
}
|
}
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn,
|
$conn,
|
||||||
'r.name LIKE %> OR r.callsign LIKE %>',
|
'r.name LIKE %> OR r.callsign LIKE %> OR r.repositorySlug LIKE %>',
|
||||||
$query,
|
$query,
|
||||||
$callsign);
|
$callsign,
|
||||||
|
$query);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->slugs !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'r.repositorySlug IN (%Ls)',
|
||||||
|
$this->slugs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->uris !== null) {
|
||||||
|
$try_uris = $this->getNormalizedPaths();
|
||||||
|
$try_uris = array_fuse($try_uris);
|
||||||
|
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'uri.repositoryURI IN (%Ls)',
|
||||||
|
$try_uris);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $where;
|
return $where;
|
||||||
|
@ -580,7 +655,7 @@ final class PhabricatorRepositoryQuery
|
||||||
// or an `svn+ssh` URI, we could deduce how to normalize it. However, this
|
// or an `svn+ssh` URI, we could deduce how to normalize it. However, this
|
||||||
// would be more complicated and it's not clear if it matters in practice.
|
// would be more complicated and it's not clear if it matters in practice.
|
||||||
|
|
||||||
foreach ($this->remoteURIs as $uri) {
|
foreach ($this->uris as $uri) {
|
||||||
$normalized_uris[] = new PhabricatorRepositoryURINormalizer(
|
$normalized_uris[] = new PhabricatorRepositoryURINormalizer(
|
||||||
PhabricatorRepositoryURINormalizer::TYPE_GIT,
|
PhabricatorRepositoryURINormalizer::TYPE_GIT,
|
||||||
$uri);
|
$uri);
|
||||||
|
|
|
@ -160,10 +160,16 @@ final class PhabricatorRepositorySearchEngine
|
||||||
|
|
||||||
$commit = $repository->getMostRecentCommit();
|
$commit = $repository->getMostRecentCommit();
|
||||||
if ($commit) {
|
if ($commit) {
|
||||||
$commit_link = DiffusionView::linkCommit(
|
$commit_link = phutil_tag(
|
||||||
$repository,
|
'a',
|
||||||
$commit->getCommitIdentifier(),
|
array(
|
||||||
$commit->getSummary());
|
'href' => $commit->getURI(),
|
||||||
|
),
|
||||||
|
pht(
|
||||||
|
'%s: %s',
|
||||||
|
$commit->getLocalName(),
|
||||||
|
$commit->getSummary()));
|
||||||
|
|
||||||
$item->setSubhead($commit_link);
|
$item->setSubhead($commit_link);
|
||||||
$item->setEpoch($commit->getEpoch());
|
$item->setEpoch($commit->getEpoch());
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,7 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
||||||
|
|
||||||
protected $name;
|
protected $name;
|
||||||
protected $callsign;
|
protected $callsign;
|
||||||
|
protected $repositorySlug;
|
||||||
protected $uuid;
|
protected $uuid;
|
||||||
protected $viewPolicy;
|
protected $viewPolicy;
|
||||||
protected $editPolicy;
|
protected $editPolicy;
|
||||||
|
@ -93,6 +94,7 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
||||||
self::CONFIG_COLUMN_SCHEMA => array(
|
self::CONFIG_COLUMN_SCHEMA => array(
|
||||||
'name' => 'sort255',
|
'name' => 'sort255',
|
||||||
'callsign' => 'sort32',
|
'callsign' => 'sort32',
|
||||||
|
'repositorySlug' => 'sort64?',
|
||||||
'versionControlSystem' => 'text32',
|
'versionControlSystem' => 'text32',
|
||||||
'uuid' => 'text64?',
|
'uuid' => 'text64?',
|
||||||
'pushPolicy' => 'policy',
|
'pushPolicy' => 'policy',
|
||||||
|
@ -100,11 +102,6 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
||||||
'almanacServicePHID' => 'phid?',
|
'almanacServicePHID' => 'phid?',
|
||||||
),
|
),
|
||||||
self::CONFIG_KEY_SCHEMA => array(
|
self::CONFIG_KEY_SCHEMA => array(
|
||||||
'key_phid' => null,
|
|
||||||
'phid' => array(
|
|
||||||
'columns' => array('phid'),
|
|
||||||
'unique' => true,
|
|
||||||
),
|
|
||||||
'callsign' => array(
|
'callsign' => array(
|
||||||
'columns' => array('callsign'),
|
'columns' => array('callsign'),
|
||||||
'unique' => true,
|
'unique' => true,
|
||||||
|
@ -115,6 +112,10 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
||||||
'key_vcs' => array(
|
'key_vcs' => array(
|
||||||
'columns' => array('versionControlSystem'),
|
'columns' => array('versionControlSystem'),
|
||||||
),
|
),
|
||||||
|
'key_slug' => array(
|
||||||
|
'columns' => array('repositorySlug'),
|
||||||
|
'unique' => true,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
) + parent::getConfiguration();
|
) + parent::getConfiguration();
|
||||||
}
|
}
|
||||||
|
@ -297,7 +298,7 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getCloneName() {
|
public function getCloneName() {
|
||||||
$name = $this->getDetail('clone-name');
|
$name = $this->getRepositorySlug();
|
||||||
|
|
||||||
// Make some reasonable effort to produce reasonable default directory
|
// Make some reasonable effort to produce reasonable default directory
|
||||||
// names from repository names.
|
// names from repository names.
|
||||||
|
@ -314,6 +315,82 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
||||||
return $name;
|
return $name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function isValidRepositorySlug($slug) {
|
||||||
|
try {
|
||||||
|
self::asssertValidRepositorySlug($slug);
|
||||||
|
return true;
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function asssertValidRepositorySlug($slug) {
|
||||||
|
if (!strlen($slug)) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'The empty string is not a valid repository short name. '.
|
||||||
|
'Repository short names must be at least one character long.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen($slug) > 64) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'The name "%s" is not a valid repository short name. Repository '.
|
||||||
|
'short names must not be longer than 64 characters.',
|
||||||
|
$slug));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preg_match('/[^a-zA-Z0-9._-]/', $slug)) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'The name "%s" is not a valid repository short name. Repository '.
|
||||||
|
'short names may only contain letters, numbers, periods, hyphens '.
|
||||||
|
'and underscores.',
|
||||||
|
$slug));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!preg_match('/^[a-zA-Z0-9]/', $slug)) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'The name "%s" is not a valid repository short name. Repository '.
|
||||||
|
'short names must begin with a letter or number.',
|
||||||
|
$slug));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!preg_match('/[a-zA-Z0-9]\z/', $slug)) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'The name "%s" is not a valid repository short name. Repository '.
|
||||||
|
'short names must end with a letter or number.',
|
||||||
|
$slug));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preg_match('/__|--|\\.\\./', $slug)) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'The name "%s" is not a valid repository short name. Repository '.
|
||||||
|
'short names must not contain multiple consecutive underscores, '.
|
||||||
|
'hyphens, or periods.',
|
||||||
|
$slug));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preg_match('/^[A-Z]+\z/', $slug)) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'The name "%s" is not a valid repository short name. Repository '.
|
||||||
|
'short names may not contain only uppercase letters.',
|
||||||
|
$slug));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preg_match('/^\d+\z/', $slug)) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'The name "%s" is not a valid repository short name. Repository '.
|
||||||
|
'short names may not contain only numbers.',
|
||||||
|
$slug));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -( Remote Command Execution )------------------------------------------- */
|
/* -( Remote Command Execution )------------------------------------------- */
|
||||||
|
|
||||||
|
@ -746,30 +823,40 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
||||||
return $uri;
|
return $uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getNormalizedPath() {
|
public function updateURIIndex() {
|
||||||
$uri = (string)$this->getCloneURIObject();
|
$uris = array(
|
||||||
|
(string)$this->getCloneURIObject(),
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($uris as $key => $uri) {
|
||||||
|
$uris[$key] = $this->getNormalizedURI($uri)
|
||||||
|
->getNormalizedPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
PhabricatorRepositoryURIIndex::updateRepositoryURIs(
|
||||||
|
$this->getPHID(),
|
||||||
|
$uris);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getNormalizedURI($uri) {
|
||||||
switch ($this->getVersionControlSystem()) {
|
switch ($this->getVersionControlSystem()) {
|
||||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
|
||||||
$normalized_uri = new PhabricatorRepositoryURINormalizer(
|
return new PhabricatorRepositoryURINormalizer(
|
||||||
PhabricatorRepositoryURINormalizer::TYPE_GIT,
|
PhabricatorRepositoryURINormalizer::TYPE_GIT,
|
||||||
$uri);
|
$uri);
|
||||||
break;
|
|
||||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
|
||||||
$normalized_uri = new PhabricatorRepositoryURINormalizer(
|
return new PhabricatorRepositoryURINormalizer(
|
||||||
PhabricatorRepositoryURINormalizer::TYPE_SVN,
|
PhabricatorRepositoryURINormalizer::TYPE_SVN,
|
||||||
$uri);
|
$uri);
|
||||||
break;
|
|
||||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
|
||||||
$normalized_uri = new PhabricatorRepositoryURINormalizer(
|
return new PhabricatorRepositoryURINormalizer(
|
||||||
PhabricatorRepositoryURINormalizer::TYPE_MERCURIAL,
|
PhabricatorRepositoryURINormalizer::TYPE_MERCURIAL,
|
||||||
$uri);
|
$uri);
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
throw new Exception(pht('Unrecognized version control system.'));
|
throw new Exception(pht('Unrecognized version control system.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $normalized_uri->getNormalizedPath();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isTracked() {
|
public function isTracked() {
|
||||||
|
@ -847,7 +934,7 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
||||||
return $this->isBranchInFilter($branch, 'branch-filter');
|
return $this->isBranchInFilter($branch, 'branch-filter');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function formatCommitName($commit_identifier) {
|
public function formatCommitName($commit_identifier, $local = false) {
|
||||||
$vcs = $this->getVersionControlSystem();
|
$vcs = $this->getVersionControlSystem();
|
||||||
|
|
||||||
$type_git = PhabricatorRepositoryType::REPOSITORY_TYPE_GIT;
|
$type_git = PhabricatorRepositoryType::REPOSITORY_TYPE_GIT;
|
||||||
|
@ -856,12 +943,23 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
||||||
$is_git = ($vcs == $type_git);
|
$is_git = ($vcs == $type_git);
|
||||||
$is_hg = ($vcs == $type_hg);
|
$is_hg = ($vcs == $type_hg);
|
||||||
if ($is_git || $is_hg) {
|
if ($is_git || $is_hg) {
|
||||||
$short_identifier = substr($commit_identifier, 0, 12);
|
$name = substr($commit_identifier, 0, 12);
|
||||||
|
$need_scope = false;
|
||||||
} else {
|
} else {
|
||||||
$short_identifier = $commit_identifier;
|
$name = $commit_identifier;
|
||||||
|
$need_scope = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'r'.$this->getCallsign().$short_identifier;
|
if (!$local) {
|
||||||
|
$need_scope = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($need_scope) {
|
||||||
|
$scope = 'r'.$this->getCallsign();
|
||||||
|
$name = $scope.$name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isImporting() {
|
public function isImporting() {
|
||||||
|
@ -2143,13 +2241,17 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
||||||
public function destroyObjectPermanently(
|
public function destroyObjectPermanently(
|
||||||
PhabricatorDestructionEngine $engine) {
|
PhabricatorDestructionEngine $engine) {
|
||||||
|
|
||||||
|
$phid = $this->getPHID();
|
||||||
|
|
||||||
$this->openTransaction();
|
$this->openTransaction();
|
||||||
|
|
||||||
$this->delete();
|
$this->delete();
|
||||||
|
|
||||||
|
PhabricatorRepositoryURIIndex::updateRepositoryURIs($phid, array());
|
||||||
|
|
||||||
$books = id(new DivinerBookQuery())
|
$books = id(new DivinerBookQuery())
|
||||||
->setViewer($engine->getViewer())
|
->setViewer($engine->getViewer())
|
||||||
->withRepositoryPHIDs(array($this->getPHID()))
|
->withRepositoryPHIDs(array($phid))
|
||||||
->execute();
|
->execute();
|
||||||
foreach ($books as $book) {
|
foreach ($books as $book) {
|
||||||
$engine->destroyObject($book);
|
$engine->destroyObject($book);
|
||||||
|
@ -2157,7 +2259,7 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
||||||
|
|
||||||
$atoms = id(new DivinerAtomQuery())
|
$atoms = id(new DivinerAtomQuery())
|
||||||
->setViewer($engine->getViewer())
|
->setViewer($engine->getViewer())
|
||||||
->withRepositoryPHIDs(array($this->getPHID()))
|
->withRepositoryPHIDs(array($phid))
|
||||||
->execute();
|
->execute();
|
||||||
foreach ($atoms as $atom) {
|
foreach ($atoms as $atom) {
|
||||||
$engine->destroyObject($atom);
|
$engine->destroyObject($atom);
|
||||||
|
|
|
@ -266,9 +266,20 @@ final class PhabricatorRepositoryCommit
|
||||||
return $repository->formatCommitName($identifier);
|
return $repository->formatCommitName($identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getShortName() {
|
/**
|
||||||
|
* Return a local display name for use in the context of the containing
|
||||||
|
* repository.
|
||||||
|
*
|
||||||
|
* In Git and Mercurial, this returns only a short hash, like "abcdef012345".
|
||||||
|
* See @{method:getDisplayName} for a short name that always includes
|
||||||
|
* repository context.
|
||||||
|
*
|
||||||
|
* @return string Short human-readable name for use inside a repository.
|
||||||
|
*/
|
||||||
|
public function getLocalName() {
|
||||||
|
$repository = $this->getRepository();
|
||||||
$identifier = $this->getCommitIdentifier();
|
$identifier = $this->getCommitIdentifier();
|
||||||
return substr($identifier, 0, 9);
|
return $repository->formatCommitName($identifier, $local = true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function renderAuthorLink($handles) {
|
public function renderAuthorLink($handles) {
|
||||||
|
|
|
@ -23,7 +23,7 @@ final class PhabricatorRepositoryTransaction
|
||||||
const TYPE_PUSH_POLICY = 'repo:push-policy';
|
const TYPE_PUSH_POLICY = 'repo:push-policy';
|
||||||
const TYPE_CREDENTIAL = 'repo:credential';
|
const TYPE_CREDENTIAL = 'repo:credential';
|
||||||
const TYPE_DANGEROUS = 'repo:dangerous';
|
const TYPE_DANGEROUS = 'repo:dangerous';
|
||||||
const TYPE_CLONE_NAME = 'repo:clone-name';
|
const TYPE_SLUG = 'repo:slug';
|
||||||
const TYPE_SERVICE = 'repo:service';
|
const TYPE_SERVICE = 'repo:service';
|
||||||
const TYPE_SYMBOLS_SOURCES = 'repo:symbol-source';
|
const TYPE_SYMBOLS_SOURCES = 'repo:symbol-source';
|
||||||
const TYPE_SYMBOLS_LANGUAGE = 'repo:symbol-language';
|
const TYPE_SYMBOLS_LANGUAGE = 'repo:symbol-language';
|
||||||
|
@ -369,19 +369,19 @@ final class PhabricatorRepositoryTransaction
|
||||||
'%s enabled protection against dangerous changes.',
|
'%s enabled protection against dangerous changes.',
|
||||||
$this->renderHandleLink($author_phid));
|
$this->renderHandleLink($author_phid));
|
||||||
}
|
}
|
||||||
case self::TYPE_CLONE_NAME:
|
case self::TYPE_SLUG:
|
||||||
if (strlen($old) && !strlen($new)) {
|
if (strlen($old) && !strlen($new)) {
|
||||||
return pht(
|
return pht(
|
||||||
'%s removed the clone name of this repository.',
|
'%s removed the short name of this repository.',
|
||||||
$this->renderHandleLink($author_phid));
|
$this->renderHandleLink($author_phid));
|
||||||
} else if (strlen($new) && !strlen($old)) {
|
} else if (strlen($new) && !strlen($old)) {
|
||||||
return pht(
|
return pht(
|
||||||
'%s set the clone name of this repository to "%s".',
|
'%s set the short name of this repository to "%s".',
|
||||||
$this->renderHandleLink($author_phid),
|
$this->renderHandleLink($author_phid),
|
||||||
$new);
|
$new);
|
||||||
} else {
|
} else {
|
||||||
return pht(
|
return pht(
|
||||||
'%s changed the clone name of this repository from "%s" to "%s".',
|
'%s changed the short name of this repository from "%s" to "%s".',
|
||||||
$this->renderHandleLink($author_phid),
|
$this->renderHandleLink($author_phid),
|
||||||
$old,
|
$old,
|
||||||
$new);
|
$new);
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorRepositoryURIIndex
|
||||||
|
extends PhabricatorRepositoryDAO {
|
||||||
|
|
||||||
|
protected $repositoryPHID;
|
||||||
|
protected $repositoryURI;
|
||||||
|
|
||||||
|
protected function getConfiguration() {
|
||||||
|
return array(
|
||||||
|
self::CONFIG_TIMESTAMPS => false,
|
||||||
|
self::CONFIG_COLUMN_SCHEMA => array(
|
||||||
|
'repositoryURI' => 'text',
|
||||||
|
),
|
||||||
|
self::CONFIG_KEY_SCHEMA => array(
|
||||||
|
'key_repository' => array(
|
||||||
|
'columns' => array('repositoryPHID'),
|
||||||
|
),
|
||||||
|
'key_uri' => array(
|
||||||
|
'columns' => array('repositoryURI(128)'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
) + parent::getConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function updateRepositoryURIs(
|
||||||
|
$repository_phid,
|
||||||
|
array $uris) {
|
||||||
|
|
||||||
|
$table = new self();
|
||||||
|
$conn_w = $table->establishConnection('w');
|
||||||
|
|
||||||
|
$sql = array();
|
||||||
|
foreach ($uris as $key => $uri) {
|
||||||
|
if (!strlen($uri)) {
|
||||||
|
unset($uris[$key]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql[] = qsprintf(
|
||||||
|
$conn_w,
|
||||||
|
'(%s, %s)',
|
||||||
|
$repository_phid,
|
||||||
|
$uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
$table->openTransaction();
|
||||||
|
|
||||||
|
queryfx(
|
||||||
|
$conn_w,
|
||||||
|
'DELETE FROM %T WHERE repositoryPHID = %s',
|
||||||
|
$table->getTableName(),
|
||||||
|
$repository_phid);
|
||||||
|
|
||||||
|
if ($sql) {
|
||||||
|
queryfx(
|
||||||
|
$conn_w,
|
||||||
|
'INSERT INTO %T (repositoryPHID, repositoryURI) VALUES %Q',
|
||||||
|
$table->getTableName(),
|
||||||
|
implode(', ', $sql));
|
||||||
|
}
|
||||||
|
|
||||||
|
$table->saveTransaction();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -152,4 +152,68 @@ final class PhabricatorRepositoryTestCase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testRepositoryShortNameValidation() {
|
||||||
|
$good = array(
|
||||||
|
'sensible-repository',
|
||||||
|
'AReasonableName',
|
||||||
|
'ACRONYM-project',
|
||||||
|
'sol-123',
|
||||||
|
'46-helixes',
|
||||||
|
'node.io',
|
||||||
|
'internet.com',
|
||||||
|
'www.internet-site.com.repository',
|
||||||
|
'with_under-scores',
|
||||||
|
|
||||||
|
// Can't win them all.
|
||||||
|
'A-_._-_._-_._-_._-_._-_._-1',
|
||||||
|
|
||||||
|
// 64-character names are fine.
|
||||||
|
str_repeat('a', 64),
|
||||||
|
);
|
||||||
|
|
||||||
|
$poor = array(
|
||||||
|
'',
|
||||||
|
'1',
|
||||||
|
'.',
|
||||||
|
'-_-',
|
||||||
|
'AAAA',
|
||||||
|
'..',
|
||||||
|
'a/b',
|
||||||
|
'../../etc/passwd',
|
||||||
|
'/',
|
||||||
|
'!',
|
||||||
|
'@',
|
||||||
|
'ca$hmoney',
|
||||||
|
'repo with spaces',
|
||||||
|
'hyphen-',
|
||||||
|
'-ated',
|
||||||
|
'_underscores_',
|
||||||
|
'yes!',
|
||||||
|
|
||||||
|
// 65-character names are no good.
|
||||||
|
str_repeat('a', 65),
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($good as $nice_name) {
|
||||||
|
$actual = PhabricatorRepository::isValidRepositorySlug($nice_name);
|
||||||
|
$this->assertEqual(
|
||||||
|
true,
|
||||||
|
$actual,
|
||||||
|
pht(
|
||||||
|
'Expected "%s" to be a valid repository short name.',
|
||||||
|
$nice_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($poor as $poor_name) {
|
||||||
|
$actual = PhabricatorRepository::isValidRepositorySlug($poor_name);
|
||||||
|
$this->assertEqual(
|
||||||
|
false,
|
||||||
|
$actual,
|
||||||
|
pht(
|
||||||
|
'Expected "%s" to be rejected as an invalid repository '.
|
||||||
|
'short name.',
|
||||||
|
$poor_name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,7 @@ abstract class PhabricatorRepositoryCommitMessageParserWorker
|
||||||
->setMaximumBytes(255)
|
->setMaximumBytes(255)
|
||||||
->truncateString((string)$author));
|
->truncateString((string)$author));
|
||||||
|
|
||||||
|
$data->setCommitDetail('authorEpoch', $ref->getAuthorEpoch());
|
||||||
$data->setCommitDetail('authorName', $ref->getAuthorName());
|
$data->setCommitDetail('authorName', $ref->getAuthorName());
|
||||||
$data->setCommitDetail('authorEmail', $ref->getAuthorEmail());
|
$data->setCommitDetail('authorEmail', $ref->getAuthorEmail());
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ final class PhabricatorSearchHovercardController
|
||||||
$cards = array();
|
$cards = array();
|
||||||
foreach ($phids as $phid) {
|
foreach ($phids as $phid) {
|
||||||
$handle = $handles[$phid];
|
$handle = $handles[$phid];
|
||||||
$object = $objects[$phid];
|
$object = idx($objects, $phid);
|
||||||
|
|
||||||
$hovercard = id(new PhabricatorHovercardView())
|
$hovercard = id(new PhabricatorHovercardView())
|
||||||
->setUser($viewer)
|
->setUser($viewer)
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorProfilePanelEditEngine
|
||||||
|
extends PhabricatorEditEngine {
|
||||||
|
|
||||||
|
const ENGINECONST = 'search.profilepanel';
|
||||||
|
|
||||||
|
private $panelEngine;
|
||||||
|
private $profileObject;
|
||||||
|
private $newPanelConfiguration;
|
||||||
|
private $isBuiltin;
|
||||||
|
|
||||||
|
public function isEngineConfigurable() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setPanelEngine(PhabricatorProfilePanelEngine $engine) {
|
||||||
|
$this->panelEngine = $engine;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPanelEngine() {
|
||||||
|
return $this->panelEngine;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setProfileObject(
|
||||||
|
PhabricatorProfilePanelInterface $profile_object) {
|
||||||
|
$this->profileObject = $profile_object;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getProfileObject() {
|
||||||
|
return $this->profileObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setNewPanelConfiguration(
|
||||||
|
PhabricatorProfilePanelConfiguration $configuration) {
|
||||||
|
$this->newPanelConfiguration = $configuration;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getNewPanelConfiguration() {
|
||||||
|
return $this->newPanelConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setIsBuiltin($is_builtin) {
|
||||||
|
$this->isBuiltin = $is_builtin;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIsBuiltin() {
|
||||||
|
return $this->isBuiltin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEngineName() {
|
||||||
|
return pht('Profile Panels');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSummaryHeader() {
|
||||||
|
return pht('Edit Profile Panel Configurations');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSummaryText() {
|
||||||
|
return pht('This engine is used to modify menu items on profiles.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEngineApplicationClass() {
|
||||||
|
return 'PhabricatorSearchApplication';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function newEditableObject() {
|
||||||
|
if (!$this->newPanelConfiguration) {
|
||||||
|
throw new Exception(
|
||||||
|
pht('Profile panels can not be generated without an object context.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return clone $this->newPanelConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function newObjectQuery() {
|
||||||
|
return id(new PhabricatorProfilePanelConfigurationQuery());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getObjectCreateTitleText($object) {
|
||||||
|
if ($this->getIsBuiltin()) {
|
||||||
|
return pht('Edit Builtin Item');
|
||||||
|
} else {
|
||||||
|
return pht('Create Menu Item');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getObjectCreateButtonText($object) {
|
||||||
|
if ($this->getIsBuiltin()) {
|
||||||
|
return pht('Save Changes');
|
||||||
|
} else {
|
||||||
|
return pht('Create Menu Item');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getObjectEditTitleText($object) {
|
||||||
|
return pht('Edit Menu Item: %s', $object->getDisplayName());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getObjectEditShortText($object) {
|
||||||
|
return pht('Edit Menu Item');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getObjectCreateShortText() {
|
||||||
|
return pht('Edit Menu Item');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getObjectCreateCancelURI($object) {
|
||||||
|
return $this->getPanelEngine()->getConfigureURI();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getObjectViewURI($object) {
|
||||||
|
return $this->getPanelEngine()->getConfigureURI();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildCustomEditFields($object) {
|
||||||
|
$panel = $object->getPanel();
|
||||||
|
$fields = $panel->buildEditEngineFields($object);
|
||||||
|
|
||||||
|
$type_property =
|
||||||
|
PhabricatorProfilePanelConfigurationTransaction::TYPE_PROPERTY;
|
||||||
|
|
||||||
|
foreach ($fields as $field) {
|
||||||
|
$field
|
||||||
|
->setTransactionType($type_property)
|
||||||
|
->setMetadataValue('property.key', $field->getKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorProfilePanelEditor
|
||||||
|
extends PhabricatorApplicationTransactionEditor {
|
||||||
|
|
||||||
|
public function getEditorApplicationClass() {
|
||||||
|
return 'PhabricatorSearchApplication';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEditorObjectsDescription() {
|
||||||
|
return pht('Profile Panels');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTransactionTypes() {
|
||||||
|
$types = parent::getTransactionTypes();
|
||||||
|
|
||||||
|
$types[] = PhabricatorProfilePanelConfigurationTransaction::TYPE_PROPERTY;
|
||||||
|
$types[] = PhabricatorProfilePanelConfigurationTransaction::TYPE_ORDER;
|
||||||
|
$types[] = PhabricatorProfilePanelConfigurationTransaction::TYPE_VISIBILITY;
|
||||||
|
|
||||||
|
return $types;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getCustomTransactionOldValue(
|
||||||
|
PhabricatorLiskDAO $object,
|
||||||
|
PhabricatorApplicationTransaction $xaction) {
|
||||||
|
|
||||||
|
switch ($xaction->getTransactionType()) {
|
||||||
|
case PhabricatorProfilePanelConfigurationTransaction::TYPE_PROPERTY:
|
||||||
|
$key = $xaction->getMetadataValue('property.key');
|
||||||
|
return $object->getPanelProperty($key, null);
|
||||||
|
case PhabricatorProfilePanelConfigurationTransaction::TYPE_ORDER:
|
||||||
|
return $object->getPanelOrder();
|
||||||
|
case PhabricatorProfilePanelConfigurationTransaction::TYPE_VISIBILITY:
|
||||||
|
return $object->getVisibility();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getCustomTransactionNewValue(
|
||||||
|
PhabricatorLiskDAO $object,
|
||||||
|
PhabricatorApplicationTransaction $xaction) {
|
||||||
|
|
||||||
|
switch ($xaction->getTransactionType()) {
|
||||||
|
case PhabricatorProfilePanelConfigurationTransaction::TYPE_PROPERTY:
|
||||||
|
case PhabricatorProfilePanelConfigurationTransaction::TYPE_VISIBILITY:
|
||||||
|
return $xaction->getNewValue();
|
||||||
|
case PhabricatorProfilePanelConfigurationTransaction::TYPE_ORDER:
|
||||||
|
return (int)$xaction->getNewValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function applyCustomInternalTransaction(
|
||||||
|
PhabricatorLiskDAO $object,
|
||||||
|
PhabricatorApplicationTransaction $xaction) {
|
||||||
|
|
||||||
|
switch ($xaction->getTransactionType()) {
|
||||||
|
case PhabricatorProfilePanelConfigurationTransaction::TYPE_PROPERTY:
|
||||||
|
$key = $xaction->getMetadataValue('property.key');
|
||||||
|
$value = $xaction->getNewValue();
|
||||||
|
$object->setPanelProperty($key, $value);
|
||||||
|
return;
|
||||||
|
case PhabricatorProfilePanelConfigurationTransaction::TYPE_ORDER:
|
||||||
|
$object->setPanelOrder($xaction->getNewValue());
|
||||||
|
return;
|
||||||
|
case PhabricatorProfilePanelConfigurationTransaction::TYPE_VISIBILITY:
|
||||||
|
$object->setVisibility($xaction->getNewValue());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::applyCustomInternalTransaction($object, $xaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function applyCustomExternalTransaction(
|
||||||
|
PhabricatorLiskDAO $object,
|
||||||
|
PhabricatorApplicationTransaction $xaction) {
|
||||||
|
|
||||||
|
switch ($xaction->getTransactionType()) {
|
||||||
|
case PhabricatorProfilePanelConfigurationTransaction::TYPE_PROPERTY:
|
||||||
|
case PhabricatorProfilePanelConfigurationTransaction::TYPE_ORDER:
|
||||||
|
case PhabricatorProfilePanelConfigurationTransaction::TYPE_VISIBILITY:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::applyCustomExternalTransaction($object, $xaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
650
src/applications/search/engine/PhabricatorProfilePanelEngine.php
Normal file
650
src/applications/search/engine/PhabricatorProfilePanelEngine.php
Normal file
|
@ -0,0 +1,650 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorProfilePanelEngine extends Phobject {
|
||||||
|
|
||||||
|
private $viewer;
|
||||||
|
private $profileObject;
|
||||||
|
private $panels;
|
||||||
|
private $controller;
|
||||||
|
|
||||||
|
public function setViewer(PhabricatorUser $viewer) {
|
||||||
|
$this->viewer = $viewer;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getViewer() {
|
||||||
|
return $this->viewer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setProfileObject(
|
||||||
|
PhabricatorProfilePanelInterface $profile_object) {
|
||||||
|
$this->profileObject = $profile_object;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getProfileObject() {
|
||||||
|
return $this->profileObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setController(PhabricatorController $controller) {
|
||||||
|
$this->controller = $controller;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getController() {
|
||||||
|
return $this->controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildResponse() {
|
||||||
|
$controller = $this->getController();
|
||||||
|
|
||||||
|
$viewer = $controller->getViewer();
|
||||||
|
$this->setViewer($viewer);
|
||||||
|
|
||||||
|
$request = $controller->getRequest();
|
||||||
|
|
||||||
|
$panel_action = $request->getURIData('panelAction');
|
||||||
|
$panel_id = $request->getURIData('panelID');
|
||||||
|
|
||||||
|
$panel_list = $this->loadPanels();
|
||||||
|
|
||||||
|
$selected_panel = null;
|
||||||
|
if (strlen($panel_id)) {
|
||||||
|
$panel_id_int = (int)$panel_id;
|
||||||
|
foreach ($panel_list as $panel) {
|
||||||
|
if ($panel_id_int) {
|
||||||
|
if ((int)$panel->getID() === $panel_id_int) {
|
||||||
|
$selected_panel = $panel;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$builtin_key = $panel->getBuiltinKey();
|
||||||
|
if ($builtin_key === (string)$panel_id) {
|
||||||
|
$selected_panel = $panel;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($panel_action) {
|
||||||
|
case 'view':
|
||||||
|
case 'info':
|
||||||
|
case 'hide':
|
||||||
|
case 'builtin':
|
||||||
|
if (!$selected_panel) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$navigation = $this->buildNavigation();
|
||||||
|
$navigation->selectFilter('panel.configure');
|
||||||
|
|
||||||
|
$crumbs = $controller->buildApplicationCrumbsForEditEngine();
|
||||||
|
|
||||||
|
switch ($panel_action) {
|
||||||
|
case 'view':
|
||||||
|
$content = $this->buildPanelViewContent($selected_panel);
|
||||||
|
break;
|
||||||
|
case 'configure':
|
||||||
|
$content = $this->buildPanelConfigureContent($panel_list);
|
||||||
|
$crumbs->addTextCrumb(pht('Configure Menu'));
|
||||||
|
break;
|
||||||
|
case 'reorder':
|
||||||
|
$content = $this->buildPanelReorderContent($panel_list);
|
||||||
|
break;
|
||||||
|
case 'new':
|
||||||
|
$panel_key = $request->getURIData('panelKey');
|
||||||
|
$content = $this->buildPanelNewContent($panel_key);
|
||||||
|
break;
|
||||||
|
case 'builtin':
|
||||||
|
$content = $this->buildPanelBuiltinContent($selected_panel);
|
||||||
|
break;
|
||||||
|
case 'hide':
|
||||||
|
$content = $this->buildPanelHideContent($selected_panel);
|
||||||
|
break;
|
||||||
|
case 'edit':
|
||||||
|
$content = $this->buildPanelEditContent();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Unsupported panel action "%s".',
|
||||||
|
$panel_action));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($content instanceof AphrontResponse) {
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($content instanceof AphrontResponseProducerInterface) {
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $controller->newPage()
|
||||||
|
->setTitle(pht('Profile Stuff'))
|
||||||
|
->setNavigation($navigation)
|
||||||
|
->setCrumbs($crumbs)
|
||||||
|
->appendChild($content);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildNavigation() {
|
||||||
|
$nav = id(new AphrontSideNavFilterView())
|
||||||
|
->setIconNav(true)
|
||||||
|
->setBaseURI(new PhutilURI('/project/'));
|
||||||
|
|
||||||
|
$panels = $this->getPanels();
|
||||||
|
|
||||||
|
foreach ($panels as $panel) {
|
||||||
|
if ($panel->isDisabled()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$items = $panel->buildNavigationMenuItems();
|
||||||
|
foreach ($items as $item) {
|
||||||
|
$this->validateNavigationMenuItem($item);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the panel produced only a single item which does not otherwise
|
||||||
|
// have a key, try to automatically assign it a reasonable key. This
|
||||||
|
// makes selecting the correct item simpler.
|
||||||
|
|
||||||
|
if (count($items) == 1) {
|
||||||
|
$item = head($items);
|
||||||
|
if ($item->getKey() === null) {
|
||||||
|
$builtin_key = $panel->getBuiltinKey();
|
||||||
|
$panel_phid = $panel->getPHID();
|
||||||
|
if ($builtin_key !== null) {
|
||||||
|
$item->setKey($builtin_key);
|
||||||
|
} else if ($panel_phid !== null) {
|
||||||
|
$item->setKey($panel_phid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($items as $item) {
|
||||||
|
$nav->addMenuItem($item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$configure_item = $this->newConfigureMenuItem();
|
||||||
|
if ($configure_item) {
|
||||||
|
$nav->addMenuItem($configure_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
$nav->selectFilter(null);
|
||||||
|
|
||||||
|
return $nav;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getPanels() {
|
||||||
|
if ($this->panels === null) {
|
||||||
|
$this->panels = $this->loadPanels();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->panels;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function loadPanels() {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$object = $this->getProfileObject();
|
||||||
|
|
||||||
|
$panels = $this->loadBuiltinProfilePanels();
|
||||||
|
|
||||||
|
$stored_panels = id(new PhabricatorProfilePanelConfigurationQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withProfilePHIDs(array($object->getPHID()))
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
// Merge the stored panels into the builtin panels. If a builtin panel has
|
||||||
|
// a stored version, replace the defaults with the stored changes.
|
||||||
|
foreach ($stored_panels as $stored_panel) {
|
||||||
|
$builtin_key = $stored_panel->getBuiltinKey();
|
||||||
|
if ($builtin_key !== null) {
|
||||||
|
$panels[$builtin_key] = $stored_panel;
|
||||||
|
} else {
|
||||||
|
$panels[] = $stored_panel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($panels as $panel) {
|
||||||
|
$impl = $panel->getPanel();
|
||||||
|
|
||||||
|
$impl->setViewer($viewer);
|
||||||
|
}
|
||||||
|
|
||||||
|
$panels = msort($panels, 'getSortKey');
|
||||||
|
|
||||||
|
// Normalize keys since callers shouldn't rely on this array being
|
||||||
|
// partially keyed.
|
||||||
|
$panels = array_values($panels);
|
||||||
|
|
||||||
|
return $panels;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function loadBuiltinProfilePanels() {
|
||||||
|
$object = $this->getProfileObject();
|
||||||
|
$builtins = $object->getBuiltinProfilePanels();
|
||||||
|
|
||||||
|
$panels = PhabricatorProfilePanel::getAllPanels();
|
||||||
|
|
||||||
|
$order = 1;
|
||||||
|
$map = array();
|
||||||
|
foreach ($builtins as $builtin) {
|
||||||
|
$builtin_key = $builtin->getBuiltinKey();
|
||||||
|
|
||||||
|
if (!$builtin_key) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Object produced a builtin panel with no builtin panel key! '.
|
||||||
|
'Builtin panels must have a unique key.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($map[$builtin_key])) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Object produced two panels with the same builtin key ("%s"). '.
|
||||||
|
'Each panel must have a unique builtin key.',
|
||||||
|
$builtin_key));
|
||||||
|
}
|
||||||
|
|
||||||
|
$panel_key = $builtin->getPanelKey();
|
||||||
|
|
||||||
|
$panel = idx($panels, $panel_key);
|
||||||
|
if (!$panel) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Builtin panel ("%s") specifies a bad panel key ("%s"); there '.
|
||||||
|
'is no corresponding panel implementation available.',
|
||||||
|
$builtin_key,
|
||||||
|
$panel_key));
|
||||||
|
}
|
||||||
|
|
||||||
|
$builtin
|
||||||
|
->setProfilePHID($object->getPHID())
|
||||||
|
->attachPanel($panel)
|
||||||
|
->attachProfileObject($object)
|
||||||
|
->setPanelOrder($order);
|
||||||
|
|
||||||
|
$map[$builtin_key] = $builtin;
|
||||||
|
|
||||||
|
$order++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $map;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function validateNavigationMenuItem($item) {
|
||||||
|
if (!($item instanceof PHUIListItemView)) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Expected buildNavigationMenuItems() to return a list of '.
|
||||||
|
'PHUIListItemView objects, but got a surprise.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function newConfigureMenuItem() {
|
||||||
|
if (!PhabricatorEnv::getEnvConfig('phabricator.show-prototypes')) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$object = $this->getProfileObject();
|
||||||
|
|
||||||
|
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||||
|
$viewer,
|
||||||
|
$object,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT);
|
||||||
|
|
||||||
|
return id(new PHUIListItemView())
|
||||||
|
->setName('Configure Menu')
|
||||||
|
->setKey('panel.configure')
|
||||||
|
->setIcon('fa-gear')
|
||||||
|
->setHref($this->getPanelURI('configure/'))
|
||||||
|
->setDisabled(!$can_edit)
|
||||||
|
->setWorkflow(!$can_edit)
|
||||||
|
->setRenderNameAsTooltip(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getConfigureURI() {
|
||||||
|
return $this->getPanelURI('configure/');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getPanelURI($path) {
|
||||||
|
$project = $this->getProfileObject();
|
||||||
|
$id = $project->getID();
|
||||||
|
return "/project/{$id}/panel/{$path}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildPanelReorderContent(array $panels) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$object = $this->getProfileObject();
|
||||||
|
|
||||||
|
PhabricatorPolicyFilter::requireCapability(
|
||||||
|
$viewer,
|
||||||
|
$object,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT);
|
||||||
|
|
||||||
|
$controller = $this->getController();
|
||||||
|
$request = $controller->getRequest();
|
||||||
|
|
||||||
|
$request->validateCSRF();
|
||||||
|
|
||||||
|
$order = $request->getStrList('order');
|
||||||
|
|
||||||
|
$by_builtin = array();
|
||||||
|
$by_id = array();
|
||||||
|
|
||||||
|
foreach ($panels as $key => $panel) {
|
||||||
|
$id = $panel->getID();
|
||||||
|
if ($id) {
|
||||||
|
$by_id[$id] = $key;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$builtin_key = $panel->getBuiltinKey();
|
||||||
|
if ($builtin_key) {
|
||||||
|
$by_builtin[$builtin_key] = $key;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$key_order = array();
|
||||||
|
foreach ($order as $order_item) {
|
||||||
|
if (isset($by_id[$order_item])) {
|
||||||
|
$key_order[] = $by_id[$order_item];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (isset($by_builtin[$order_item])) {
|
||||||
|
$key_order[] = $by_builtin[$order_item];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$panels = array_select_keys($panels, $key_order) + $panels;
|
||||||
|
|
||||||
|
$type_order =
|
||||||
|
PhabricatorProfilePanelConfigurationTransaction::TYPE_ORDER;
|
||||||
|
|
||||||
|
$order = 1;
|
||||||
|
foreach ($panels as $panel) {
|
||||||
|
$xactions = array();
|
||||||
|
|
||||||
|
$xactions[] = id(new PhabricatorProfilePanelConfigurationTransaction())
|
||||||
|
->setTransactionType($type_order)
|
||||||
|
->setNewValue($order);
|
||||||
|
|
||||||
|
$editor = id(new PhabricatorProfilePanelEditor())
|
||||||
|
->setContentSourceFromRequest($request)
|
||||||
|
->setActor($viewer)
|
||||||
|
->setContinueOnMissingFields(true)
|
||||||
|
->setContinueOnNoEffect(true)
|
||||||
|
->applyTransactions($panel, $xactions);
|
||||||
|
|
||||||
|
$order++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return id(new AphrontRedirectResponse())
|
||||||
|
->setURI($this->getConfigureURI());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function buildPanelConfigureContent(array $panels) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$object = $this->getProfileObject();
|
||||||
|
|
||||||
|
PhabricatorPolicyFilter::requireCapability(
|
||||||
|
$viewer,
|
||||||
|
$object,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT);
|
||||||
|
|
||||||
|
$list_id = celerity_generate_unique_node_id();
|
||||||
|
|
||||||
|
Javelin::initBehavior(
|
||||||
|
'reorder-profile-menu-items',
|
||||||
|
array(
|
||||||
|
'listID' => $list_id,
|
||||||
|
'orderURI' => $this->getPanelURI('reorder/'),
|
||||||
|
));
|
||||||
|
|
||||||
|
$list = id(new PHUIObjectItemListView())
|
||||||
|
->setID($list_id);
|
||||||
|
|
||||||
|
foreach ($panels as $panel) {
|
||||||
|
$id = $panel->getID();
|
||||||
|
$builtin_key = $panel->getBuiltinKey();
|
||||||
|
|
||||||
|
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||||
|
$viewer,
|
||||||
|
$panel,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT);
|
||||||
|
|
||||||
|
$item = id(new PHUIObjectItemView());
|
||||||
|
|
||||||
|
$name = $panel->getDisplayName();
|
||||||
|
$type = $panel->getPanelTypeName();
|
||||||
|
if (!strlen(trim($name))) {
|
||||||
|
$name = pht('Untitled "%s" Item', $type);
|
||||||
|
}
|
||||||
|
|
||||||
|
$item->setHeader($name);
|
||||||
|
$item->addAttribute($type);
|
||||||
|
|
||||||
|
if ($can_edit) {
|
||||||
|
$item
|
||||||
|
->setGrippable(true)
|
||||||
|
->addSigil('profile-menu-item')
|
||||||
|
->setMetadata(
|
||||||
|
array(
|
||||||
|
'key' => nonempty($id, $builtin_key),
|
||||||
|
));
|
||||||
|
|
||||||
|
if ($id) {
|
||||||
|
$item->setHref($this->getPanelURI("edit/{$id}/"));
|
||||||
|
$hide_uri = $this->getPanelURI("hide/{$id}/");
|
||||||
|
} else {
|
||||||
|
$item->setHref($this->getPanelURI("builtin/{$builtin_key}/"));
|
||||||
|
$hide_uri = $this->getPanelURI("hide/{$builtin_key}/");
|
||||||
|
}
|
||||||
|
|
||||||
|
$item->addAction(
|
||||||
|
id(new PHUIListItemView())
|
||||||
|
->setHref($hide_uri)
|
||||||
|
->setWorkflow(true)
|
||||||
|
->setIcon(pht('fa-eye')));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($panel->isDisabled()) {
|
||||||
|
$item->setDisabled(true);
|
||||||
|
$item->addIcon('fa-times grey', pht('Disabled'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$list->addItem($item);
|
||||||
|
}
|
||||||
|
|
||||||
|
$action_view = id(new PhabricatorActionListView())
|
||||||
|
->setUser($viewer);
|
||||||
|
|
||||||
|
$panel_types = PhabricatorProfilePanel::getAllPanels();
|
||||||
|
|
||||||
|
$action_view->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setLabel(true)
|
||||||
|
->setName(pht('Add New Menu Item...')));
|
||||||
|
|
||||||
|
foreach ($panel_types as $panel_type) {
|
||||||
|
if (!$panel_type->canAddToObject($object)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$panel_key = $panel_type->getPanelKey();
|
||||||
|
|
||||||
|
$action_view->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setIcon($panel_type->getPanelTypeIcon())
|
||||||
|
->setName($panel_type->getPanelTypeName())
|
||||||
|
->setHref($this->getPanelURI("new/{$panel_key}/")));
|
||||||
|
}
|
||||||
|
|
||||||
|
$action_view->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setLabel(true)
|
||||||
|
->setName(pht('Documentation')));
|
||||||
|
|
||||||
|
$action_view->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setIcon('fa-book')
|
||||||
|
->setName(pht('TODO: Write Documentation')));
|
||||||
|
|
||||||
|
$action_button = id(new PHUIButtonView())
|
||||||
|
->setTag('a')
|
||||||
|
->setText(pht('Configure Menu'))
|
||||||
|
->setHref('#')
|
||||||
|
->setIconFont('fa-gear')
|
||||||
|
->setDropdownMenu($action_view);
|
||||||
|
|
||||||
|
$header = id(new PHUIHeaderView())
|
||||||
|
->setHeader(pht('Profile Menu Items'))
|
||||||
|
->addActionLink($action_button);
|
||||||
|
|
||||||
|
$box = id(new PHUIObjectBoxView())
|
||||||
|
->setHeader($header)
|
||||||
|
->setObjectList($list);
|
||||||
|
|
||||||
|
return $box;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildPanelNewContent($panel_key) {
|
||||||
|
$panel_types = PhabricatorProfilePanel::getAllPanels();
|
||||||
|
$panel_type = idx($panel_types, $panel_key);
|
||||||
|
if (!$panel_type) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
$object = $this->getProfileObject();
|
||||||
|
if (!$panel_type->canAddToObject($object)) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
$configuration =
|
||||||
|
PhabricatorProfilePanelConfiguration::initializeNewPanelConfiguration(
|
||||||
|
$object,
|
||||||
|
$panel_type);
|
||||||
|
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
PhabricatorPolicyFilter::requireCapability(
|
||||||
|
$viewer,
|
||||||
|
$configuration,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT);
|
||||||
|
|
||||||
|
$controller = $this->getController();
|
||||||
|
|
||||||
|
return id(new PhabricatorProfilePanelEditEngine())
|
||||||
|
->setPanelEngine($this)
|
||||||
|
->setProfileObject($object)
|
||||||
|
->setNewPanelConfiguration($configuration)
|
||||||
|
->setController($controller)
|
||||||
|
->buildResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildPanelEditContent() {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$object = $this->getProfileObject();
|
||||||
|
$controller = $this->getController();
|
||||||
|
|
||||||
|
return id(new PhabricatorProfilePanelEditEngine())
|
||||||
|
->setPanelEngine($this)
|
||||||
|
->setProfileObject($object)
|
||||||
|
->setController($controller)
|
||||||
|
->buildResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildPanelBuiltinContent(
|
||||||
|
PhabricatorProfilePanelConfiguration $configuration) {
|
||||||
|
|
||||||
|
// If this builtin panel has already been persisted, redirect to the
|
||||||
|
// edit page.
|
||||||
|
$id = $configuration->getID();
|
||||||
|
if ($id) {
|
||||||
|
return id(new AphrontRedirectResponse())
|
||||||
|
->setURI($this->getPanelURI("edit/{$id}/"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, act like we're creating a new panel, we're just starting
|
||||||
|
// with the builtin template.
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
PhabricatorPolicyFilter::requireCapability(
|
||||||
|
$viewer,
|
||||||
|
$configuration,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT);
|
||||||
|
|
||||||
|
$object = $this->getProfileObject();
|
||||||
|
$controller = $this->getController();
|
||||||
|
|
||||||
|
return id(new PhabricatorProfilePanelEditEngine())
|
||||||
|
->setIsBuiltin(true)
|
||||||
|
->setPanelEngine($this)
|
||||||
|
->setProfileObject($object)
|
||||||
|
->setNewPanelConfiguration($configuration)
|
||||||
|
->setController($controller)
|
||||||
|
->buildResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildPanelHideContent(
|
||||||
|
PhabricatorProfilePanelConfiguration $configuration) {
|
||||||
|
|
||||||
|
$controller = $this->getController();
|
||||||
|
$request = $controller->getRequest();
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
PhabricatorPolicyFilter::requireCapability(
|
||||||
|
$viewer,
|
||||||
|
$configuration,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT);
|
||||||
|
|
||||||
|
$v_visibility = $configuration->getVisibility();
|
||||||
|
if ($request->isFormPost()) {
|
||||||
|
$v_visibility = $request->getStr('visibility');
|
||||||
|
|
||||||
|
$type_visibility =
|
||||||
|
PhabricatorProfilePanelConfigurationTransaction::TYPE_VISIBILITY;
|
||||||
|
|
||||||
|
$xactions = array();
|
||||||
|
|
||||||
|
$xactions[] = id(new PhabricatorProfilePanelConfigurationTransaction())
|
||||||
|
->setTransactionType($type_visibility)
|
||||||
|
->setNewValue($v_visibility);
|
||||||
|
|
||||||
|
$editor = id(new PhabricatorProfilePanelEditor())
|
||||||
|
->setContentSourceFromRequest($request)
|
||||||
|
->setActor($viewer)
|
||||||
|
->setContinueOnMissingFields(true)
|
||||||
|
->setContinueOnNoEffect(true)
|
||||||
|
->applyTransactions($configuration, $xactions);
|
||||||
|
|
||||||
|
return id(new AphrontRedirectResponse())
|
||||||
|
->setURI($this->getConfigureURI());
|
||||||
|
}
|
||||||
|
|
||||||
|
$map = PhabricatorProfilePanelConfiguration::getVisibilityNameMap();
|
||||||
|
|
||||||
|
$form = id(new AphrontFormView())
|
||||||
|
->setUser($viewer)
|
||||||
|
->appendControl(
|
||||||
|
id(new AphrontFormSelectControl())
|
||||||
|
->setName('visibility')
|
||||||
|
->setLabel(pht('Visibility'))
|
||||||
|
->setValue($v_visibility)
|
||||||
|
->setOptions($map));
|
||||||
|
|
||||||
|
return $controller->newDialog()
|
||||||
|
->setTitle(pht('Change Item Visibility'))
|
||||||
|
->appendForm($form)
|
||||||
|
->addCancelButton($this->getConfigureURI())
|
||||||
|
->addSubmitButton(pht('Save Changes'));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
interface PhabricatorProfilePanelInterface {
|
||||||
|
|
||||||
|
public function getBuiltinProfilePanels();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorProfilePanelPHIDType
|
||||||
|
extends PhabricatorPHIDType {
|
||||||
|
|
||||||
|
const TYPECONST = 'PANL';
|
||||||
|
|
||||||
|
public function getTypeName() {
|
||||||
|
return pht('Profile Panel');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newObject() {
|
||||||
|
return new PhabricatorProfilePanelConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPHIDTypeApplicationClass() {
|
||||||
|
return 'PhabricatorSearchApplication';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildQueryForObjects(
|
||||||
|
PhabricatorObjectQuery $object_query,
|
||||||
|
array $phids) {
|
||||||
|
return id(new PhabricatorProfilePanelConfigurationQuery())
|
||||||
|
->withPHIDs($phids);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadHandles(
|
||||||
|
PhabricatorHandleQuery $query,
|
||||||
|
array $handles,
|
||||||
|
array $objects) {
|
||||||
|
|
||||||
|
foreach ($handles as $phid => $handle) {
|
||||||
|
$config = $objects[$phid];
|
||||||
|
|
||||||
|
$handle->setName(pht('Profile Panel'));
|
||||||
|
$handle->setURI($config->getURI());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorLinkProfilePanel
|
||||||
|
extends PhabricatorProfilePanel {
|
||||||
|
|
||||||
|
const PANELKEY = 'link';
|
||||||
|
|
||||||
|
public function getPanelTypeIcon() {
|
||||||
|
return 'fa-link';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPanelTypeName() {
|
||||||
|
return pht('Link');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canAddToObject(
|
||||||
|
PhabricatorProfilePanelInterface $object) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDisplayName(
|
||||||
|
PhabricatorProfilePanelConfiguration $config) {
|
||||||
|
return $this->getLinkName($config);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildEditEngineFields(
|
||||||
|
PhabricatorProfilePanelConfiguration $config) {
|
||||||
|
return array(
|
||||||
|
id(new PhabricatorTextEditField())
|
||||||
|
->setKey('name')
|
||||||
|
->setLabel(pht('Name'))
|
||||||
|
->setIsRequired(true)
|
||||||
|
->setValue($this->getLinkName($config)),
|
||||||
|
id(new PhabricatorTextEditField())
|
||||||
|
->setKey('uri')
|
||||||
|
->setLabel(pht('URI'))
|
||||||
|
->setIsRequired(true)
|
||||||
|
->setValue($this->getLinkURI($config)),
|
||||||
|
id(new PhabricatorIconSetEditField())
|
||||||
|
->setKey('icon')
|
||||||
|
->setLabel(pht('Icon'))
|
||||||
|
->setIconSet(new PhabricatorProfilePanelIconSet())
|
||||||
|
->setValue($this->getLinkIcon($config)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getLinkName(
|
||||||
|
PhabricatorProfilePanelConfiguration $config) {
|
||||||
|
return $config->getPanelProperty('name');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getLinkIcon(
|
||||||
|
PhabricatorProfilePanelConfiguration $config) {
|
||||||
|
return $config->getPanelProperty('icon', 'link');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getLinkURI(
|
||||||
|
PhabricatorProfilePanelConfiguration $config) {
|
||||||
|
return $config->getPanelProperty('uri');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function isValidLinkURI($uri) {
|
||||||
|
return PhabricatorEnv::isValidURIForLink($uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function newNavigationMenuItems(
|
||||||
|
PhabricatorProfilePanelConfiguration $config) {
|
||||||
|
|
||||||
|
$icon = $this->getLinkIcon($config);
|
||||||
|
$name = $this->getLinkName($config);
|
||||||
|
$href = $this->getLinkURI($config);
|
||||||
|
|
||||||
|
if (!$this->isValidLinkURI($href)) {
|
||||||
|
$href = '#';
|
||||||
|
}
|
||||||
|
|
||||||
|
$icon_object = id(new PhabricatorProfilePanelIconSet())
|
||||||
|
->getIcon($icon);
|
||||||
|
if ($icon_object) {
|
||||||
|
$icon_class = $icon_object->getIcon();
|
||||||
|
} else {
|
||||||
|
$icon_class = 'fa-link';
|
||||||
|
}
|
||||||
|
|
||||||
|
$item = id(new PHUIListItemView())
|
||||||
|
->setRenderNameAsTooltip(true)
|
||||||
|
->setType(PHUIListItemView::TYPE_ICON_NAV)
|
||||||
|
->setHref($href)
|
||||||
|
->setName($name)
|
||||||
|
->setIcon($icon_class);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
$item,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class PhabricatorProfilePanel extends Phobject {
|
||||||
|
|
||||||
|
private $viewer;
|
||||||
|
|
||||||
|
final public function buildNavigationMenuItems(
|
||||||
|
PhabricatorProfilePanelConfiguration $config) {
|
||||||
|
return $this->newNavigationMenuItems($config);
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract protected function newNavigationMenuItems(
|
||||||
|
PhabricatorProfilePanelConfiguration $config);
|
||||||
|
|
||||||
|
public function getPanelTypeIcon() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract public function getPanelTypeName();
|
||||||
|
|
||||||
|
abstract public function getDisplayName(
|
||||||
|
PhabricatorProfilePanelConfiguration $config);
|
||||||
|
|
||||||
|
public function buildEditEngineFields(
|
||||||
|
PhabricatorProfilePanelConfiguration $config) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canAddToObject(
|
||||||
|
PhabricatorProfilePanelInterface $object) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setViewer(PhabricatorUser $viewer) {
|
||||||
|
$this->viewer = $viewer;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getViewer() {
|
||||||
|
return $this->viewer;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function getPanelKey() {
|
||||||
|
return $this->getPhobjectClassConstant('PANELKEY');
|
||||||
|
}
|
||||||
|
|
||||||
|
final public static function getAllPanels() {
|
||||||
|
return id(new PhutilClassMapQuery())
|
||||||
|
->setAncestorClass(__CLASS__)
|
||||||
|
->setUniqueMethod('getPanelKey')
|
||||||
|
->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorProfilePanelIconSet
|
||||||
|
extends PhabricatorIconSet {
|
||||||
|
|
||||||
|
const ICONSETKEY = 'profilepanel';
|
||||||
|
|
||||||
|
public function getSelectIconTitleText() {
|
||||||
|
return pht('Choose Item Icon');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function newIcons() {
|
||||||
|
$list = array(
|
||||||
|
array(
|
||||||
|
'key' => 'link',
|
||||||
|
'icon' => 'fa-link',
|
||||||
|
'name' => pht('Link'),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'key' => 'maniphest',
|
||||||
|
'icon' => 'fa-anchor',
|
||||||
|
'name' => pht('Maniphest'),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'key' => 'feed',
|
||||||
|
'icon' => 'fa-newspaper-o',
|
||||||
|
'name' => pht('Feed'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
$icons = array();
|
||||||
|
foreach ($list as $spec) {
|
||||||
|
$icons[] = id(new PhabricatorIconSetIcon())
|
||||||
|
->setKey($spec['key'])
|
||||||
|
->setIcon($spec['icon'])
|
||||||
|
->setLabel($spec['name']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $icons;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,102 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorProfilePanelConfigurationQuery
|
||||||
|
extends PhabricatorCursorPagedPolicyAwareQuery {
|
||||||
|
|
||||||
|
private $ids;
|
||||||
|
private $phids;
|
||||||
|
private $profilePHIDs;
|
||||||
|
|
||||||
|
public function withIDs(array $ids) {
|
||||||
|
$this->ids = $ids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withPHIDs(array $phids) {
|
||||||
|
$this->phids = $phids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withProfilePHIDs(array $phids) {
|
||||||
|
$this->profilePHIDs = $phids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newResultObject() {
|
||||||
|
return new PhabricatorProfilePanelConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
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->phids !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'phid IN (%Ls)',
|
||||||
|
$this->phids);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->profilePHIDs !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'profilePHID IN (%Ls)',
|
||||||
|
$this->profilePHIDs);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $where;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function willFilterPage(array $page) {
|
||||||
|
$panels = PhabricatorProfilePanel::getAllPanels();
|
||||||
|
foreach ($page as $key => $panel) {
|
||||||
|
$panel_type = idx($panels, $panel->getPanelKey());
|
||||||
|
if (!$panel_type) {
|
||||||
|
$this->didRejectResult($panel);
|
||||||
|
unset($page[$key]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$panel->attachPanel($panel_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$page) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$profile_phids = mpull($page, 'getProfilePHID');
|
||||||
|
|
||||||
|
$profiles = id(new PhabricatorObjectQuery())
|
||||||
|
->setViewer($this->getViewer())
|
||||||
|
->setParentQuery($this)
|
||||||
|
->withPHIDs($profile_phids)
|
||||||
|
->execute();
|
||||||
|
$profiles = mpull($profiles, null, 'getPHID');
|
||||||
|
|
||||||
|
foreach ($page as $key => $panel) {
|
||||||
|
$profile = idx($profiles, $panel->getProfilePHID());
|
||||||
|
if (!$profile) {
|
||||||
|
$this->didRejectResult($panel);
|
||||||
|
unset($page[$key]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$panel->attachProfileObject($profile);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $page;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQueryApplicationClass() {
|
||||||
|
return 'PhabricatorSearchApplication';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,193 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorProfilePanelConfiguration
|
||||||
|
extends PhabricatorSearchDAO
|
||||||
|
implements
|
||||||
|
PhabricatorPolicyInterface,
|
||||||
|
PhabricatorExtendedPolicyInterface,
|
||||||
|
PhabricatorApplicationTransactionInterface {
|
||||||
|
|
||||||
|
protected $profilePHID;
|
||||||
|
protected $panelKey;
|
||||||
|
protected $builtinKey;
|
||||||
|
protected $panelOrder;
|
||||||
|
protected $visibility;
|
||||||
|
protected $panelProperties = array();
|
||||||
|
|
||||||
|
private $profileObject = self::ATTACHABLE;
|
||||||
|
private $panel = self::ATTACHABLE;
|
||||||
|
|
||||||
|
const VISIBILITY_VISIBLE = 'visible';
|
||||||
|
const VISIBILITY_DISABLED = 'disabled';
|
||||||
|
|
||||||
|
public static function initializeNewBuiltin() {
|
||||||
|
return id(new self())
|
||||||
|
->setVisibility(self::VISIBILITY_VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function initializeNewPanelConfiguration(
|
||||||
|
PhabricatorProfilePanelInterface $profile_object,
|
||||||
|
PhabricatorProfilePanel $panel) {
|
||||||
|
|
||||||
|
return self::initializeNewBuiltin()
|
||||||
|
->setProfilePHID($profile_object->getPHID())
|
||||||
|
->setPanelKey($panel->getPanelKey())
|
||||||
|
->attachPanel($panel)
|
||||||
|
->attachProfileObject($profile_object);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getConfiguration() {
|
||||||
|
return array(
|
||||||
|
self::CONFIG_AUX_PHID => true,
|
||||||
|
self::CONFIG_SERIALIZATION => array(
|
||||||
|
'panelProperties' => self::SERIALIZATION_JSON,
|
||||||
|
),
|
||||||
|
self::CONFIG_COLUMN_SCHEMA => array(
|
||||||
|
'panelKey' => 'text64',
|
||||||
|
'builtinKey' => 'text64?',
|
||||||
|
'panelOrder' => 'uint32?',
|
||||||
|
'visibility' => 'text32',
|
||||||
|
),
|
||||||
|
self::CONFIG_KEY_SCHEMA => array(
|
||||||
|
'key_profile' => array(
|
||||||
|
'columns' => array('profilePHID', 'panelOrder'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
) + parent::getConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getVisibilityNameMap() {
|
||||||
|
return array(
|
||||||
|
self::VISIBILITY_VISIBLE => pht('Visible'),
|
||||||
|
self::VISIBILITY_DISABLED => pht('Disabled'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function generatePHID() {
|
||||||
|
return PhabricatorPHID::generateNewPHID(
|
||||||
|
PhabricatorProfilePanelPHIDType::TYPECONST);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attachPanel(PhabricatorProfilePanel $panel) {
|
||||||
|
$this->panel = $panel;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPanel() {
|
||||||
|
return $this->assertAttached($this->panel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attachProfileObject(
|
||||||
|
PhabricatorProfilePanelInterface $profile_object) {
|
||||||
|
$this->profileObject = $profile_object;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getProfileObject() {
|
||||||
|
return $this->assertAttached($this->profileObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setPanelProperty($key, $value) {
|
||||||
|
$this->panelProperties[$key] = $value;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPanelProperty($key, $default = null) {
|
||||||
|
return idx($this->panelProperties, $key, $default);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildNavigationMenuItems() {
|
||||||
|
return $this->getPanel()->buildNavigationMenuItems($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPanelTypeName() {
|
||||||
|
return $this->getPanel()->getPanelTypeName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDisplayName() {
|
||||||
|
return $this->getPanel()->getDisplayName($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSortKey() {
|
||||||
|
$order = $this->getPanelOrder();
|
||||||
|
if ($order === null) {
|
||||||
|
$order = 'Z';
|
||||||
|
} else {
|
||||||
|
$order = sprintf('%020d', $order);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sprintf(
|
||||||
|
'~%s%020d',
|
||||||
|
$order,
|
||||||
|
$this->getID());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isDisabled() {
|
||||||
|
return ($this->getVisibility() === self::VISIBILITY_DISABLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function getCapabilities() {
|
||||||
|
return array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getPolicy($capability) {
|
||||||
|
return PhabricatorPolicies::getMostOpenPolicy();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
|
||||||
|
return $this->getProfileObject()->hasAutomaticCapability(
|
||||||
|
$capability,
|
||||||
|
$viewer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function describeAutomaticCapability($capability) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( PhabricatorExtendedPolicyInterface )--------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function getExtendedPolicy($capability, PhabricatorUser $viewer) {
|
||||||
|
return array(
|
||||||
|
array(
|
||||||
|
$this->getProfileObject(),
|
||||||
|
$capability,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function getApplicationTransactionEditor() {
|
||||||
|
return new PhabricatorProfilePanelEditor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApplicationTransactionObject() {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApplicationTransactionTemplate() {
|
||||||
|
return new PhabricatorProfilePanelConfigurationTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function willRenderTimeline(
|
||||||
|
PhabricatorApplicationTransactionView $timeline,
|
||||||
|
AphrontRequest $request) {
|
||||||
|
|
||||||
|
return $timeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorProfilePanelConfigurationTransaction
|
||||||
|
extends PhabricatorApplicationTransaction {
|
||||||
|
|
||||||
|
const TYPE_PROPERTY = 'profilepanel.property';
|
||||||
|
const TYPE_ORDER = 'profilepanel.order';
|
||||||
|
const TYPE_VISIBILITY = 'profilepanel.visibility';
|
||||||
|
|
||||||
|
public function getApplicationName() {
|
||||||
|
return 'search';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApplicationTransactionType() {
|
||||||
|
return PhabricatorProfilePanelPHIDType::TYPECONST;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApplicationTransactionCommentObject() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -21,6 +21,7 @@ final class PhabricatorSearchDatasource
|
||||||
new PhabricatorProjectDatasource(),
|
new PhabricatorProjectDatasource(),
|
||||||
new PhabricatorApplicationDatasource(),
|
new PhabricatorApplicationDatasource(),
|
||||||
new PhabricatorTypeaheadMonogramDatasource(),
|
new PhabricatorTypeaheadMonogramDatasource(),
|
||||||
|
new DiffusionRepositoryDatasource(),
|
||||||
new DiffusionSymbolDatasource(),
|
new DiffusionSymbolDatasource(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,10 @@ final class PhabricatorEditEngineConfigurationListController
|
||||||
$engine = PhabricatorEditEngine::getByKey($viewer, $engine_key)
|
$engine = PhabricatorEditEngine::getByKey($viewer, $engine_key)
|
||||||
->setViewer($viewer);
|
->setViewer($viewer);
|
||||||
|
|
||||||
|
if (!$engine->isEngineConfigurable()) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
|
||||||
$items = array();
|
$items = array();
|
||||||
$items[] = id(new PHUIListItemView())
|
$items[] = id(new PHUIListItemView())
|
||||||
->setType(PHUIListItemView::TYPE_LABEL)
|
->setType(PHUIListItemView::TYPE_LABEL)
|
||||||
|
|
|
@ -72,6 +72,10 @@ abstract class PhabricatorEditEngineController
|
||||||
$engine = $config->getEngine();
|
$engine = $config->getEngine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$engine->isEngineConfigurable()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return $config;
|
return $config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue