mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-28 00:10:57 +01:00
Merge branch 'master' into redesign-2015
This commit is contained in:
commit
3699253e49
127 changed files with 3234 additions and 2575 deletions
|
@ -1,6 +1,5 @@
|
|||
{
|
||||
"project.name" : "phabricator",
|
||||
"phabricator.uri" : "https://secure.phabricator.com/",
|
||||
"unit.engine" : "PhutilUnitTestEngine",
|
||||
"load" : ["src/"]
|
||||
"phabricator.uri": "https://secure.phabricator.com/",
|
||||
"unit.engine": "PhutilUnitTestEngine",
|
||||
"load": ["src/"]
|
||||
}
|
||||
|
|
1
.arclint
1
.arclint
|
@ -74,6 +74,7 @@
|
|||
"type": "xhpast",
|
||||
"include": "(\\.php$)",
|
||||
"severity": {
|
||||
"16": "advice",
|
||||
"34": "error"
|
||||
},
|
||||
"xhpast.blacklisted.function": {
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
*/
|
||||
return array(
|
||||
'names' => array(
|
||||
'core.pkg.css' => '55901d68',
|
||||
'core.pkg.js' => 'e4f47dfd',
|
||||
'core.pkg.css' => 'f85a5ce0',
|
||||
'core.pkg.js' => 'fbf1d615',
|
||||
'darkconsole.pkg.js' => 'e7393ebb',
|
||||
'differential.pkg.css' => 'bb338e4b',
|
||||
'differential.pkg.js' => '63a77807',
|
||||
'differential.pkg.css' => '30602b8c',
|
||||
'differential.pkg.js' => '8c98ce21',
|
||||
'diffusion.pkg.css' => '385e85b3',
|
||||
'diffusion.pkg.js' => '0115b37c',
|
||||
'maniphest.pkg.css' => '4845691a',
|
||||
|
@ -26,7 +26,7 @@ return array(
|
|||
'rsrc/css/aphront/pager-view.css' => '2e3539af',
|
||||
'rsrc/css/aphront/panel-view.css' => '8427b78d',
|
||||
'rsrc/css/aphront/phabricator-nav-view.css' => '0ecd30a1',
|
||||
'rsrc/css/aphront/table-view.css' => 'fb17602c',
|
||||
'rsrc/css/aphront/table-view.css' => '15fedf7a',
|
||||
'rsrc/css/aphront/tokenizer.css' => '04875312',
|
||||
'rsrc/css/aphront/tooltip.css' => '7672b60f',
|
||||
'rsrc/css/aphront/two-column.css' => '16ab3ad2',
|
||||
|
@ -60,7 +60,7 @@ return array(
|
|||
'rsrc/css/application/differential/add-comment.css' => 'c47f8c40',
|
||||
'rsrc/css/application/differential/changeset-view.css' => 'e19cfd6e',
|
||||
'rsrc/css/application/differential/core.css' => '7ac3cabc',
|
||||
'rsrc/css/application/differential/phui-inline-comment.css' => '2174771a',
|
||||
'rsrc/css/application/differential/phui-inline-comment.css' => 'aa16f165',
|
||||
'rsrc/css/application/differential/results-table.css' => '181aa9d9',
|
||||
'rsrc/css/application/differential/revision-comment.css' => '14b8565a',
|
||||
'rsrc/css/application/differential/revision-history.css' => '0e8eb855',
|
||||
|
@ -111,7 +111,7 @@ return array(
|
|||
'rsrc/css/core/core.css' => 'bbc7187b',
|
||||
'rsrc/css/core/remarkup.css' => 'ea91b3ee',
|
||||
'rsrc/css/core/syntax.css' => '6b7b24d9',
|
||||
'rsrc/css/core/z-index.css' => '8c8c40aa',
|
||||
'rsrc/css/core/z-index.css' => '63689f49',
|
||||
'rsrc/css/diviner/diviner-shared.css' => '38813222',
|
||||
'rsrc/css/font/font-awesome.css' => 'e2e712fe',
|
||||
'rsrc/css/font/font-source-sans-pro.css' => '8906c07b',
|
||||
|
@ -120,7 +120,7 @@ return array(
|
|||
'rsrc/css/layout/phabricator-hovercard-view.css' => '0d665853',
|
||||
'rsrc/css/layout/phabricator-side-menu-view.css' => 'a440478a',
|
||||
'rsrc/css/layout/phabricator-source-code-view.css' => '2ceee894',
|
||||
'rsrc/css/phui/calendar/phui-calendar-day.css' => 'c0cf782a',
|
||||
'rsrc/css/phui/calendar/phui-calendar-day.css' => 'd1cf6f93',
|
||||
'rsrc/css/phui/calendar/phui-calendar-list.css' => 'c1c7f338',
|
||||
'rsrc/css/phui/calendar/phui-calendar-month.css' => '476be7e0',
|
||||
'rsrc/css/phui/calendar/phui-calendar.css' => 'ccabe893',
|
||||
|
@ -132,7 +132,7 @@ return array(
|
|||
'rsrc/css/phui/phui-document.css' => '8be7a5e3',
|
||||
'rsrc/css/phui/phui-feed-story.css' => 'e5682f4c',
|
||||
'rsrc/css/phui/phui-fontkit.css' => 'b664ac96',
|
||||
'rsrc/css/phui/phui-form-view.css' => '87263b05',
|
||||
'rsrc/css/phui/phui-form-view.css' => 'a0e8f168',
|
||||
'rsrc/css/phui/phui-form.css' => 'f535f938',
|
||||
'rsrc/css/phui/phui-header-view.css' => 'd7612da3',
|
||||
'rsrc/css/phui/phui-icon.css' => '88ba9081',
|
||||
|
@ -325,9 +325,10 @@ return array(
|
|||
'rsrc/js/application/aphlict/behavior-aphlict-listen.js' => 'b1a59974',
|
||||
'rsrc/js/application/aphlict/behavior-aphlict-status.js' => 'ea681761',
|
||||
'rsrc/js/application/auth/behavior-persona-login.js' => '9414ff18',
|
||||
'rsrc/js/application/calendar/event-all-day.js' => 'ca5fa62a',
|
||||
'rsrc/js/application/config/behavior-reorder-fields.js' => '14a827de',
|
||||
'rsrc/js/application/conpherence/ConpherenceThreadManager.js' => '10246726',
|
||||
'rsrc/js/application/calendar/behavior-day-view.js' => '5c46cff2',
|
||||
'rsrc/js/application/calendar/behavior-event-all-day.js' => '38dcf3c8',
|
||||
'rsrc/js/application/config/behavior-reorder-fields.js' => 'b6993408',
|
||||
'rsrc/js/application/conpherence/ConpherenceThreadManager.js' => '01774ab2',
|
||||
'rsrc/js/application/conpherence/behavior-drag-and-drop-photo.js' => 'cf86d16a',
|
||||
'rsrc/js/application/conpherence/behavior-durable-column.js' => '16c695bf',
|
||||
'rsrc/js/application/conpherence/behavior-menu.js' => 'c0348cac',
|
||||
|
@ -346,7 +347,7 @@ return array(
|
|||
'rsrc/js/application/differential/behavior-comment-preview.js' => 'b064af76',
|
||||
'rsrc/js/application/differential/behavior-diff-radios.js' => 'e1ff79b1',
|
||||
'rsrc/js/application/differential/behavior-dropdown-menus.js' => '2035b9cb',
|
||||
'rsrc/js/application/differential/behavior-edit-inline-comments.js' => 'e723c323',
|
||||
'rsrc/js/application/differential/behavior-edit-inline-comments.js' => '037b59eb',
|
||||
'rsrc/js/application/differential/behavior-keyboard-nav.js' => '2c426492',
|
||||
'rsrc/js/application/differential/behavior-populate.js' => '8694b1df',
|
||||
'rsrc/js/application/differential/behavior-show-field-details.js' => 'bba9eedf',
|
||||
|
@ -363,7 +364,7 @@ return array(
|
|||
'rsrc/js/application/doorkeeper/behavior-doorkeeper-tag.js' => 'e5822781',
|
||||
'rsrc/js/application/files/behavior-icon-composer.js' => '8ef9ab58',
|
||||
'rsrc/js/application/files/behavior-launch-icon-composer.js' => '48086888',
|
||||
'rsrc/js/application/herald/HeraldRuleEditor.js' => '9229e764',
|
||||
'rsrc/js/application/herald/HeraldRuleEditor.js' => '271ffdd7',
|
||||
'rsrc/js/application/herald/PathTypeahead.js' => 'f7fc67ec',
|
||||
'rsrc/js/application/herald/herald-rule-editor.js' => '7ebaeed3',
|
||||
'rsrc/js/application/maniphest/behavior-batch-editor.js' => 'f5d1233b',
|
||||
|
@ -436,7 +437,7 @@ return array(
|
|||
'rsrc/js/core/behavior-device.js' => 'a205cf28',
|
||||
'rsrc/js/core/behavior-drag-and-drop-textarea.js' => '6d49590e',
|
||||
'rsrc/js/core/behavior-error-log.js' => '6882e80a',
|
||||
'rsrc/js/core/behavior-fancy-datepicker.js' => '5c0f680f',
|
||||
'rsrc/js/core/behavior-fancy-datepicker.js' => '510b5809',
|
||||
'rsrc/js/core/behavior-file-tree.js' => '88236f00',
|
||||
'rsrc/js/core/behavior-form.js' => '5c54cbf3',
|
||||
'rsrc/js/core/behavior-gesture.js' => '3ab51e2c',
|
||||
|
@ -482,7 +483,7 @@ return array(
|
|||
'aphront-multi-column-view-css' => 'fd18389d',
|
||||
'aphront-pager-view-css' => '2e3539af',
|
||||
'aphront-panel-view-css' => '8427b78d',
|
||||
'aphront-table-view-css' => 'fb17602c',
|
||||
'aphront-table-view-css' => '15fedf7a',
|
||||
'aphront-tokenizer-control-css' => '04875312',
|
||||
'aphront-tooltip-css' => '7672b60f',
|
||||
'aphront-two-column-view-css' => '16ab3ad2',
|
||||
|
@ -497,7 +498,7 @@ return array(
|
|||
'conpherence-menu-css' => 'f9f1d143',
|
||||
'conpherence-message-pane-css' => '7cbf4cbb',
|
||||
'conpherence-notification-css' => '919974b6',
|
||||
'conpherence-thread-manager' => '10246726',
|
||||
'conpherence-thread-manager' => '01774ab2',
|
||||
'conpherence-transaction-css' => '42a457f6',
|
||||
'conpherence-update-css' => '1099a660',
|
||||
'conpherence-widget-pane-css' => '77096740',
|
||||
|
@ -519,7 +520,7 @@ return array(
|
|||
'global-drag-and-drop-css' => '697324ad',
|
||||
'harbormaster-css' => '49d64eb4',
|
||||
'herald-css' => '826075fa',
|
||||
'herald-rule-editor' => '9229e764',
|
||||
'herald-rule-editor' => '271ffdd7',
|
||||
'herald-test-css' => '778b008e',
|
||||
'inline-comment-summary-css' => 'eb5f8e8c',
|
||||
'javelin-aphlict' => '5359e785',
|
||||
|
@ -535,7 +536,7 @@ return array(
|
|||
'javelin-behavior-audio-source' => '59b251eb',
|
||||
'javelin-behavior-audit-preview' => 'd835b03a',
|
||||
'javelin-behavior-choose-control' => '6153c708',
|
||||
'javelin-behavior-config-reorder-fields' => '14a827de',
|
||||
'javelin-behavior-config-reorder-fields' => 'b6993408',
|
||||
'javelin-behavior-conpherence-drag-and-drop-photo' => 'cf86d16a',
|
||||
'javelin-behavior-conpherence-menu' => 'c0348cac',
|
||||
'javelin-behavior-conpherence-pontificate' => '21ba5861',
|
||||
|
@ -546,12 +547,13 @@ return array(
|
|||
'javelin-behavior-dashboard-move-panels' => '82439934',
|
||||
'javelin-behavior-dashboard-query-panel-select' => '453c5375',
|
||||
'javelin-behavior-dashboard-tab-panel' => 'd4eecc63',
|
||||
'javelin-behavior-day-view' => '5c46cff2',
|
||||
'javelin-behavior-device' => 'a205cf28',
|
||||
'javelin-behavior-differential-add-reviewers-and-ccs' => 'e10f8e18',
|
||||
'javelin-behavior-differential-comment-jump' => '4fdb476d',
|
||||
'javelin-behavior-differential-diff-radios' => 'e1ff79b1',
|
||||
'javelin-behavior-differential-dropdown-menus' => '2035b9cb',
|
||||
'javelin-behavior-differential-edit-inline-comments' => 'e723c323',
|
||||
'javelin-behavior-differential-edit-inline-comments' => '037b59eb',
|
||||
'javelin-behavior-differential-feedback-preview' => 'b064af76',
|
||||
'javelin-behavior-differential-keyboard-navigation' => '2c426492',
|
||||
'javelin-behavior-differential-populate' => '8694b1df',
|
||||
|
@ -566,8 +568,8 @@ return array(
|
|||
'javelin-behavior-doorkeeper-tag' => 'e5822781',
|
||||
'javelin-behavior-durable-column' => '16c695bf',
|
||||
'javelin-behavior-error-log' => '6882e80a',
|
||||
'javelin-behavior-event-all-day' => 'ca5fa62a',
|
||||
'javelin-behavior-fancy-datepicker' => '5c0f680f',
|
||||
'javelin-behavior-event-all-day' => '38dcf3c8',
|
||||
'javelin-behavior-fancy-datepicker' => '510b5809',
|
||||
'javelin-behavior-global-drag-and-drop' => 'c8e57404',
|
||||
'javelin-behavior-herald-rule-editor' => '7ebaeed3',
|
||||
'javelin-behavior-high-security-warning' => 'a464fe03',
|
||||
|
@ -743,7 +745,7 @@ return array(
|
|||
'phabricator-uiexample-reactor-select' => 'a155550f',
|
||||
'phabricator-uiexample-reactor-sendclass' => '1def2711',
|
||||
'phabricator-uiexample-reactor-sendproperties' => 'b1f0ccee',
|
||||
'phabricator-zindex-css' => '8c8c40aa',
|
||||
'phabricator-zindex-css' => '63689f49',
|
||||
'phame-css' => '88bd4705',
|
||||
'pholio-css' => '95174bdd',
|
||||
'pholio-edit-css' => '3ad9d1ee',
|
||||
|
@ -757,7 +759,7 @@ return array(
|
|||
'phui-box-css' => 'a5bb366d',
|
||||
'phui-button-css' => 'b995182d',
|
||||
'phui-calendar-css' => 'ccabe893',
|
||||
'phui-calendar-day-css' => 'c0cf782a',
|
||||
'phui-calendar-day-css' => 'd1cf6f93',
|
||||
'phui-calendar-list-css' => 'c1c7f338',
|
||||
'phui-calendar-month-css' => '476be7e0',
|
||||
'phui-crumbs-view-css' => '3840dc4c',
|
||||
|
@ -766,13 +768,13 @@ return array(
|
|||
'phui-font-icon-base-css' => '3dad2ae3',
|
||||
'phui-fontkit-css' => 'b664ac96',
|
||||
'phui-form-css' => 'f535f938',
|
||||
'phui-form-view-css' => '87263b05',
|
||||
'phui-form-view-css' => 'a0e8f168',
|
||||
'phui-header-view-css' => 'd7612da3',
|
||||
'phui-icon-view-css' => '88ba9081',
|
||||
'phui-image-mask-css' => '5a8b09c8',
|
||||
'phui-info-panel-css' => '27ea50a1',
|
||||
'phui-info-view-css' => '33e54618',
|
||||
'phui-inline-comment-view-css' => '2174771a',
|
||||
'phui-inline-comment-view-css' => 'aa16f165',
|
||||
'phui-list-view-css' => 'e448b6ba',
|
||||
'phui-object-box-css' => '8eacbeed',
|
||||
'phui-object-item-list-view-css' => '24ed8d94',
|
||||
|
@ -815,9 +817,28 @@ return array(
|
|||
'unhandled-exception-css' => '4c96257a',
|
||||
),
|
||||
'requires' => array(
|
||||
'01774ab2' => array(
|
||||
'javelin-dom',
|
||||
'javelin-util',
|
||||
'javelin-stratcom',
|
||||
'javelin-install',
|
||||
'javelin-aphlict',
|
||||
'javelin-workflow',
|
||||
'javelin-router',
|
||||
'javelin-behavior-device',
|
||||
'javelin-vector',
|
||||
),
|
||||
'029a133d' => array(
|
||||
'aphront-dialog-view-css',
|
||||
),
|
||||
'037b59eb' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
'javelin-dom',
|
||||
'javelin-util',
|
||||
'javelin-vector',
|
||||
'differential-inline-comment-editor',
|
||||
),
|
||||
'048330fa' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-typeahead-ondemand-source',
|
||||
|
@ -874,17 +895,6 @@ return array(
|
|||
'javelin-install',
|
||||
'javelin-util',
|
||||
),
|
||||
10246726 => array(
|
||||
'javelin-dom',
|
||||
'javelin-util',
|
||||
'javelin-stratcom',
|
||||
'javelin-install',
|
||||
'javelin-aphlict',
|
||||
'javelin-workflow',
|
||||
'javelin-router',
|
||||
'javelin-behavior-device',
|
||||
'javelin-vector',
|
||||
),
|
||||
'13c739ea' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
|
@ -899,13 +909,6 @@ return array(
|
|||
'javelin-dom',
|
||||
'javelin-history',
|
||||
),
|
||||
'14a827de' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
'javelin-dom',
|
||||
'javelin-json',
|
||||
'phabricator-draggable-list',
|
||||
),
|
||||
'14ac66f5' => array(
|
||||
'javelin-install',
|
||||
'javelin-dom',
|
||||
|
@ -982,6 +985,15 @@ return array(
|
|||
'phabricator-drag-and-drop-file-upload',
|
||||
'phabricator-draggable-list',
|
||||
),
|
||||
'271ffdd7' => array(
|
||||
'multirow-row-manager',
|
||||
'javelin-install',
|
||||
'javelin-util',
|
||||
'javelin-dom',
|
||||
'javelin-stratcom',
|
||||
'javelin-json',
|
||||
'phabricator-prefab',
|
||||
),
|
||||
'2818f5ce' => array(
|
||||
'javelin-install',
|
||||
'javelin-util',
|
||||
|
@ -1147,6 +1159,13 @@ return array(
|
|||
'javelin-typeahead-source',
|
||||
'javelin-util',
|
||||
),
|
||||
'510b5809' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-util',
|
||||
'javelin-dom',
|
||||
'javelin-stratcom',
|
||||
'javelin-vector',
|
||||
),
|
||||
'519705ea' => array(
|
||||
'javelin-install',
|
||||
'javelin-dom',
|
||||
|
@ -1224,13 +1243,6 @@ return array(
|
|||
'javelin-uri',
|
||||
'javelin-routable',
|
||||
),
|
||||
'5c0f680f' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-util',
|
||||
'javelin-dom',
|
||||
'javelin-stratcom',
|
||||
'javelin-vector',
|
||||
),
|
||||
'5c54cbf3' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
|
@ -1505,15 +1517,6 @@ return array(
|
|||
'javelin-dom',
|
||||
'javelin-stratcom',
|
||||
),
|
||||
'9229e764' => array(
|
||||
'multirow-row-manager',
|
||||
'javelin-install',
|
||||
'javelin-util',
|
||||
'javelin-dom',
|
||||
'javelin-stratcom',
|
||||
'javelin-json',
|
||||
'phabricator-prefab',
|
||||
),
|
||||
93568464 => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
|
@ -1706,6 +1709,13 @@ return array(
|
|||
'javelin-dom',
|
||||
'javelin-util',
|
||||
),
|
||||
'b6993408' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
'javelin-dom',
|
||||
'javelin-json',
|
||||
'phabricator-draggable-list',
|
||||
),
|
||||
'ba4fa35c' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
|
@ -1913,14 +1923,6 @@ return array(
|
|||
'e6e25838' => array(
|
||||
'javelin-install',
|
||||
),
|
||||
'e723c323' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
'javelin-dom',
|
||||
'javelin-util',
|
||||
'javelin-vector',
|
||||
'differential-inline-comment-editor',
|
||||
),
|
||||
'e9581f08' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
|
|
2
resources/sql/autopatches/20150521.releephrepository.sql
Normal file
2
resources/sql/autopatches/20150521.releephrepository.sql
Normal file
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_releeph.releeph_project
|
||||
MODIFY arcanistProjectID int(10) unsigned NULL;
|
7
resources/sql/autopatches/20150525.diff.hidden.1.sql
Normal file
7
resources/sql/autopatches/20150525.diff.hidden.1.sql
Normal file
|
@ -0,0 +1,7 @@
|
|||
CREATE TABLE {$NAMESPACE}_differential.differential_hiddencomment (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
userPHID VARBINARY(64) NOT NULL,
|
||||
commentID INT UNSIGNED NOT NULL,
|
||||
UNIQUE KEY `key_user` (userPHID, commentID),
|
||||
KEY `key_comment` (commentID)
|
||||
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
|
2
resources/sql/autopatches/20150526.owners.mailkey.1.sql
Normal file
2
resources/sql/autopatches/20150526.owners.mailkey.1.sql
Normal file
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_owners.owners_package
|
||||
ADD mailKey binary(20) NOT NULL;
|
18
resources/sql/autopatches/20150526.owners.mailkey.2.php
Normal file
18
resources/sql/autopatches/20150526.owners.mailkey.2.php
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
$table = new PhabricatorOwnersPackage();
|
||||
$conn_w = $table->establishConnection('w');
|
||||
$iterator = new LiskMigrationIterator($table);
|
||||
foreach ($iterator as $package) {
|
||||
$id = $package->getID();
|
||||
|
||||
echo pht('Adding mail key for package %d...', $id);
|
||||
echo "\n";
|
||||
|
||||
queryfx(
|
||||
$conn_w,
|
||||
'UPDATE %T SET mailKey = %s WHERE id = %d',
|
||||
$table->getTableName(),
|
||||
Filesystem::readRandomCharacters(20),
|
||||
$id);
|
||||
}
|
19
resources/sql/autopatches/20150526.owners.xaction.sql
Normal file
19
resources/sql/autopatches/20150526.owners.xaction.sql
Normal file
|
@ -0,0 +1,19 @@
|
|||
CREATE TABLE {$NAMESPACE}_owners.owners_packagetransaction (
|
||||
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};
|
|
@ -374,6 +374,7 @@ phutil_register_library_map(array(
|
|||
'DifferentialGetWorkingCopy' => 'applications/differential/DifferentialGetWorkingCopy.php',
|
||||
'DifferentialGitHubLandingStrategy' => 'applications/differential/landing/DifferentialGitHubLandingStrategy.php',
|
||||
'DifferentialGitSVNIDField' => 'applications/differential/customfield/DifferentialGitSVNIDField.php',
|
||||
'DifferentialHiddenComment' => 'applications/differential/storage/DifferentialHiddenComment.php',
|
||||
'DifferentialHostField' => 'applications/differential/customfield/DifferentialHostField.php',
|
||||
'DifferentialHostedGitLandingStrategy' => 'applications/differential/landing/DifferentialHostedGitLandingStrategy.php',
|
||||
'DifferentialHostedMercurialLandingStrategy' => 'applications/differential/landing/DifferentialHostedMercurialLandingStrategy.php',
|
||||
|
@ -461,7 +462,6 @@ phutil_register_library_map(array(
|
|||
'DifferentialUpdateRevisionConduitAPIMethod' => 'applications/differential/conduit/DifferentialUpdateRevisionConduitAPIMethod.php',
|
||||
'DifferentialUpdateUnitResultsConduitAPIMethod' => 'applications/differential/conduit/DifferentialUpdateUnitResultsConduitAPIMethod.php',
|
||||
'DifferentialViewPolicyField' => 'applications/differential/customfield/DifferentialViewPolicyField.php',
|
||||
'DiffusionArcanistProjectDatasource' => 'applications/diffusion/typeahead/DiffusionArcanistProjectDatasource.php',
|
||||
'DiffusionAuditorDatasource' => 'applications/diffusion/typeahead/DiffusionAuditorDatasource.php',
|
||||
'DiffusionBranchQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionBranchQueryConduitAPIMethod.php',
|
||||
'DiffusionBranchTableController' => 'applications/diffusion/controller/DiffusionBranchTableController.php',
|
||||
|
@ -596,6 +596,7 @@ phutil_register_library_map(array(
|
|||
'DiffusionRepositoryEditEncodingController' => 'applications/diffusion/controller/DiffusionRepositoryEditEncodingController.php',
|
||||
'DiffusionRepositoryEditHostingController' => 'applications/diffusion/controller/DiffusionRepositoryEditHostingController.php',
|
||||
'DiffusionRepositoryEditMainController' => 'applications/diffusion/controller/DiffusionRepositoryEditMainController.php',
|
||||
'DiffusionRepositoryEditStagingController' => 'applications/diffusion/controller/DiffusionRepositoryEditStagingController.php',
|
||||
'DiffusionRepositoryEditStorageController' => 'applications/diffusion/controller/DiffusionRepositoryEditStorageController.php',
|
||||
'DiffusionRepositoryEditSubversionController' => 'applications/diffusion/controller/DiffusionRepositoryEditSubversionController.php',
|
||||
'DiffusionRepositoryEditUpdateController' => 'applications/diffusion/controller/DiffusionRepositoryEditUpdateController.php',
|
||||
|
@ -1176,6 +1177,7 @@ phutil_register_library_map(array(
|
|||
'PHUIDiffInlineCommentUndoView' => 'infrastructure/diff/view/PHUIDiffInlineCommentUndoView.php',
|
||||
'PHUIDiffInlineCommentView' => 'infrastructure/diff/view/PHUIDiffInlineCommentView.php',
|
||||
'PHUIDiffOneUpInlineCommentRowScaffold' => 'infrastructure/diff/view/PHUIDiffOneUpInlineCommentRowScaffold.php',
|
||||
'PHUIDiffRevealIconView' => 'infrastructure/diff/view/PHUIDiffRevealIconView.php',
|
||||
'PHUIDiffTwoUpInlineCommentRowScaffold' => 'infrastructure/diff/view/PHUIDiffTwoUpInlineCommentRowScaffold.php',
|
||||
'PHUIDocumentExample' => 'applications/uiexample/examples/PHUIDocumentExample.php',
|
||||
'PHUIDocumentView' => 'view/phui/PHUIDocumentView.php',
|
||||
|
@ -1226,10 +1228,6 @@ phutil_register_library_map(array(
|
|||
'PHUITypeaheadExample' => 'applications/uiexample/examples/PHUITypeaheadExample.php',
|
||||
'PHUIWorkboardView' => 'view/phui/PHUIWorkboardView.php',
|
||||
'PHUIWorkpanelView' => 'view/phui/PHUIWorkpanelView.php',
|
||||
'PackageCreateMail' => 'applications/owners/mail/PackageCreateMail.php',
|
||||
'PackageDeleteMail' => 'applications/owners/mail/PackageDeleteMail.php',
|
||||
'PackageMail' => 'applications/owners/mail/PackageMail.php',
|
||||
'PackageModifyMail' => 'applications/owners/mail/PackageModifyMail.php',
|
||||
'PassphraseAbstractKey' => 'applications/passphrase/keys/PassphraseAbstractKey.php',
|
||||
'PassphraseConduitAPIMethod' => 'applications/passphrase/conduit/PassphraseConduitAPIMethod.php',
|
||||
'PassphraseController' => 'applications/passphrase/controller/PassphraseController.php',
|
||||
|
@ -1496,6 +1494,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorCalendarEvent' => 'applications/calendar/storage/PhabricatorCalendarEvent.php',
|
||||
'PhabricatorCalendarEventCancelController' => 'applications/calendar/controller/PhabricatorCalendarEventCancelController.php',
|
||||
'PhabricatorCalendarEventCommentController' => 'applications/calendar/controller/PhabricatorCalendarEventCommentController.php',
|
||||
'PhabricatorCalendarEventDragController' => 'applications/calendar/controller/PhabricatorCalendarEventDragController.php',
|
||||
'PhabricatorCalendarEventEditController' => 'applications/calendar/controller/PhabricatorCalendarEventEditController.php',
|
||||
'PhabricatorCalendarEventEditIconController' => 'applications/calendar/controller/PhabricatorCalendarEventEditIconController.php',
|
||||
'PhabricatorCalendarEventEditor' => 'applications/calendar/editor/PhabricatorCalendarEventEditor.php',
|
||||
|
@ -1538,6 +1537,8 @@ phutil_register_library_map(array(
|
|||
'PhabricatorClusterConfigOptions' => 'applications/config/option/PhabricatorClusterConfigOptions.php',
|
||||
'PhabricatorCommitBranchesField' => 'applications/repository/customfield/PhabricatorCommitBranchesField.php',
|
||||
'PhabricatorCommitCustomField' => 'applications/repository/customfield/PhabricatorCommitCustomField.php',
|
||||
'PhabricatorCommitMergedCommitsField' => 'applications/repository/customfield/PhabricatorCommitMergedCommitsField.php',
|
||||
'PhabricatorCommitRepositoryField' => 'applications/repository/customfield/PhabricatorCommitRepositoryField.php',
|
||||
'PhabricatorCommitSearchEngine' => 'applications/audit/query/PhabricatorCommitSearchEngine.php',
|
||||
'PhabricatorCommitTagsField' => 'applications/repository/customfield/PhabricatorCommitTagsField.php',
|
||||
'PhabricatorCommonPasswords' => 'applications/auth/constants/PhabricatorCommonPasswords.php',
|
||||
|
@ -2160,19 +2161,21 @@ phutil_register_library_map(array(
|
|||
'PhabricatorOwnersConfigOptions' => 'applications/owners/config/PhabricatorOwnersConfigOptions.php',
|
||||
'PhabricatorOwnersController' => 'applications/owners/controller/PhabricatorOwnersController.php',
|
||||
'PhabricatorOwnersDAO' => 'applications/owners/storage/PhabricatorOwnersDAO.php',
|
||||
'PhabricatorOwnersDeleteController' => 'applications/owners/controller/PhabricatorOwnersDeleteController.php',
|
||||
'PhabricatorOwnersDetailController' => 'applications/owners/controller/PhabricatorOwnersDetailController.php',
|
||||
'PhabricatorOwnersEditController' => 'applications/owners/controller/PhabricatorOwnersEditController.php',
|
||||
'PhabricatorOwnersListController' => 'applications/owners/controller/PhabricatorOwnersListController.php',
|
||||
'PhabricatorOwnersOwner' => 'applications/owners/storage/PhabricatorOwnersOwner.php',
|
||||
'PhabricatorOwnersPackage' => 'applications/owners/storage/PhabricatorOwnersPackage.php',
|
||||
'PhabricatorOwnersPackageDatasource' => 'applications/owners/typeahead/PhabricatorOwnersPackageDatasource.php',
|
||||
'PhabricatorOwnersPackageEditor' => 'applications/owners/editor/PhabricatorOwnersPackageEditor.php',
|
||||
'PhabricatorOwnersPackagePHIDType' => 'applications/owners/phid/PhabricatorOwnersPackagePHIDType.php',
|
||||
'PhabricatorOwnersPackagePathValidator' => 'applications/repository/worker/commitchangeparser/PhabricatorOwnersPackagePathValidator.php',
|
||||
'PhabricatorOwnersPackageQuery' => 'applications/owners/query/PhabricatorOwnersPackageQuery.php',
|
||||
'PhabricatorOwnersPackageSearchEngine' => 'applications/owners/query/PhabricatorOwnersPackageSearchEngine.php',
|
||||
'PhabricatorOwnersPackageTestCase' => 'applications/owners/storage/__tests__/PhabricatorOwnersPackageTestCase.php',
|
||||
'PhabricatorOwnersPackageTransaction' => 'applications/owners/storage/PhabricatorOwnersPackageTransaction.php',
|
||||
'PhabricatorOwnersPackageTransactionEditor' => 'applications/owners/editor/PhabricatorOwnersPackageTransactionEditor.php',
|
||||
'PhabricatorOwnersPackageTransactionQuery' => 'applications/owners/query/PhabricatorOwnersPackageTransactionQuery.php',
|
||||
'PhabricatorOwnersPath' => 'applications/owners/storage/PhabricatorOwnersPath.php',
|
||||
'PhabricatorOwnersPathsController' => 'applications/owners/controller/PhabricatorOwnersPathsController.php',
|
||||
'PhabricatorPHDConfigOptions' => 'applications/config/option/PhabricatorPHDConfigOptions.php',
|
||||
'PhabricatorPHID' => 'applications/phid/storage/PhabricatorPHID.php',
|
||||
'PhabricatorPHIDConstants' => 'applications/phid/PhabricatorPHIDConstants.php',
|
||||
|
@ -2383,8 +2386,6 @@ phutil_register_library_map(array(
|
|||
'PhabricatorRepositoriesSetupCheck' => 'applications/config/check/PhabricatorRepositoriesSetupCheck.php',
|
||||
'PhabricatorRepository' => 'applications/repository/storage/PhabricatorRepository.php',
|
||||
'PhabricatorRepositoryArcanistProject' => 'applications/repository/storage/PhabricatorRepositoryArcanistProject.php',
|
||||
'PhabricatorRepositoryArcanistProjectDeleteController' => 'applications/repository/controller/PhabricatorRepositoryArcanistProjectDeleteController.php',
|
||||
'PhabricatorRepositoryArcanistProjectEditController' => 'applications/repository/controller/PhabricatorRepositoryArcanistProjectEditController.php',
|
||||
'PhabricatorRepositoryArcanistProjectPHIDType' => 'applications/repository/phid/PhabricatorRepositoryArcanistProjectPHIDType.php',
|
||||
'PhabricatorRepositoryArcanistProjectQuery' => 'applications/repository/query/PhabricatorRepositoryArcanistProjectQuery.php',
|
||||
'PhabricatorRepositoryAuditRequest' => 'applications/repository/storage/PhabricatorRepositoryAuditRequest.php',
|
||||
|
@ -3146,7 +3147,6 @@ phutil_register_library_map(array(
|
|||
'ReleephProductTransactionQuery' => 'applications/releeph/query/ReleephProductTransactionQuery.php',
|
||||
'ReleephProductViewController' => 'applications/releeph/controller/product/ReleephProductViewController.php',
|
||||
'ReleephProject' => 'applications/releeph/storage/ReleephProject.php',
|
||||
'ReleephProjectInfoConduitAPIMethod' => 'applications/releeph/conduit/ReleephProjectInfoConduitAPIMethod.php',
|
||||
'ReleephQueryBranchesConduitAPIMethod' => 'applications/releeph/conduit/ReleephQueryBranchesConduitAPIMethod.php',
|
||||
'ReleephQueryProductsConduitAPIMethod' => 'applications/releeph/conduit/ReleephQueryProductsConduitAPIMethod.php',
|
||||
'ReleephQueryRequestsConduitAPIMethod' => 'applications/releeph/conduit/ReleephQueryRequestsConduitAPIMethod.php',
|
||||
|
@ -3614,6 +3614,7 @@ phutil_register_library_map(array(
|
|||
'DifferentialGetRevisionConduitAPIMethod' => 'DifferentialConduitAPIMethod',
|
||||
'DifferentialGitHubLandingStrategy' => 'DifferentialLandingStrategy',
|
||||
'DifferentialGitSVNIDField' => 'DifferentialCustomField',
|
||||
'DifferentialHiddenComment' => 'DifferentialDAO',
|
||||
'DifferentialHostField' => 'DifferentialCustomField',
|
||||
'DifferentialHostedGitLandingStrategy' => 'DifferentialLandingStrategy',
|
||||
'DifferentialHostedMercurialLandingStrategy' => 'DifferentialLandingStrategy',
|
||||
|
@ -3706,7 +3707,6 @@ phutil_register_library_map(array(
|
|||
'DifferentialUpdateRevisionConduitAPIMethod' => 'DifferentialConduitAPIMethod',
|
||||
'DifferentialUpdateUnitResultsConduitAPIMethod' => 'DifferentialConduitAPIMethod',
|
||||
'DifferentialViewPolicyField' => 'DifferentialCoreCustomField',
|
||||
'DiffusionArcanistProjectDatasource' => 'PhabricatorTypeaheadDatasource',
|
||||
'DiffusionAuditorDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
||||
'DiffusionBranchQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
|
||||
'DiffusionBranchTableController' => 'DiffusionController',
|
||||
|
@ -3831,6 +3831,7 @@ phutil_register_library_map(array(
|
|||
'DiffusionRepositoryEditEncodingController' => 'DiffusionRepositoryEditController',
|
||||
'DiffusionRepositoryEditHostingController' => 'DiffusionRepositoryEditController',
|
||||
'DiffusionRepositoryEditMainController' => 'DiffusionRepositoryEditController',
|
||||
'DiffusionRepositoryEditStagingController' => 'DiffusionRepositoryEditController',
|
||||
'DiffusionRepositoryEditStorageController' => 'DiffusionRepositoryEditController',
|
||||
'DiffusionRepositoryEditSubversionController' => 'DiffusionRepositoryEditController',
|
||||
'DiffusionRepositoryEditUpdateController' => 'DiffusionRepositoryEditController',
|
||||
|
@ -4502,6 +4503,7 @@ phutil_register_library_map(array(
|
|||
'PHUIDiffInlineCommentUndoView' => 'PHUIDiffInlineCommentView',
|
||||
'PHUIDiffInlineCommentView' => 'AphrontView',
|
||||
'PHUIDiffOneUpInlineCommentRowScaffold' => 'PHUIDiffInlineCommentRowScaffold',
|
||||
'PHUIDiffRevealIconView' => 'AphrontView',
|
||||
'PHUIDiffTwoUpInlineCommentRowScaffold' => 'PHUIDiffInlineCommentRowScaffold',
|
||||
'PHUIDocumentExample' => 'PhabricatorUIExample',
|
||||
'PHUIDocumentView' => 'AphrontTagView',
|
||||
|
@ -4552,10 +4554,6 @@ phutil_register_library_map(array(
|
|||
'PHUITypeaheadExample' => 'PhabricatorUIExample',
|
||||
'PHUIWorkboardView' => 'AphrontTagView',
|
||||
'PHUIWorkpanelView' => 'AphrontTagView',
|
||||
'PackageCreateMail' => 'PackageMail',
|
||||
'PackageDeleteMail' => 'PackageMail',
|
||||
'PackageMail' => 'PhabricatorMail',
|
||||
'PackageModifyMail' => 'PackageMail',
|
||||
'PassphraseAbstractKey' => 'Phobject',
|
||||
'PassphraseConduitAPIMethod' => 'ConduitAPIMethod',
|
||||
'PassphraseController' => 'PhabricatorController',
|
||||
|
@ -4849,6 +4847,7 @@ phutil_register_library_map(array(
|
|||
),
|
||||
'PhabricatorCalendarEventCancelController' => 'PhabricatorCalendarController',
|
||||
'PhabricatorCalendarEventCommentController' => 'PhabricatorCalendarController',
|
||||
'PhabricatorCalendarEventDragController' => 'PhabricatorCalendarController',
|
||||
'PhabricatorCalendarEventEditController' => 'PhabricatorCalendarController',
|
||||
'PhabricatorCalendarEventEditIconController' => 'PhabricatorCalendarController',
|
||||
'PhabricatorCalendarEventEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||
|
@ -4900,6 +4899,8 @@ phutil_register_library_map(array(
|
|||
'PhabricatorClusterConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||
'PhabricatorCommitBranchesField' => 'PhabricatorCommitCustomField',
|
||||
'PhabricatorCommitCustomField' => 'PhabricatorCustomField',
|
||||
'PhabricatorCommitMergedCommitsField' => 'PhabricatorCommitCustomField',
|
||||
'PhabricatorCommitRepositoryField' => 'PhabricatorCommitCustomField',
|
||||
'PhabricatorCommitSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||
'PhabricatorCommitTagsField' => 'PhabricatorCommitCustomField',
|
||||
'PhabricatorCommonPasswords' => 'Phobject',
|
||||
|
@ -5560,7 +5561,6 @@ phutil_register_library_map(array(
|
|||
'PhabricatorOwnersConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||
'PhabricatorOwnersController' => 'PhabricatorController',
|
||||
'PhabricatorOwnersDAO' => 'PhabricatorLiskDAO',
|
||||
'PhabricatorOwnersDeleteController' => 'PhabricatorOwnersController',
|
||||
'PhabricatorOwnersDetailController' => 'PhabricatorOwnersController',
|
||||
'PhabricatorOwnersEditController' => 'PhabricatorOwnersController',
|
||||
'PhabricatorOwnersListController' => 'PhabricatorOwnersController',
|
||||
|
@ -5568,13 +5568,18 @@ phutil_register_library_map(array(
|
|||
'PhabricatorOwnersPackage' => array(
|
||||
'PhabricatorOwnersDAO',
|
||||
'PhabricatorPolicyInterface',
|
||||
'PhabricatorApplicationTransactionInterface',
|
||||
),
|
||||
'PhabricatorOwnersPackageDatasource' => 'PhabricatorTypeaheadDatasource',
|
||||
'PhabricatorOwnersPackageEditor' => 'PhabricatorEditor',
|
||||
'PhabricatorOwnersPackagePHIDType' => 'PhabricatorPHIDType',
|
||||
'PhabricatorOwnersPackageQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'PhabricatorOwnersPackageSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||
'PhabricatorOwnersPackageTestCase' => 'PhabricatorTestCase',
|
||||
'PhabricatorOwnersPackageTransaction' => 'PhabricatorApplicationTransaction',
|
||||
'PhabricatorOwnersPackageTransactionEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||
'PhabricatorOwnersPackageTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||
'PhabricatorOwnersPath' => 'PhabricatorOwnersDAO',
|
||||
'PhabricatorOwnersPathsController' => 'PhabricatorOwnersController',
|
||||
'PhabricatorPHDConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||
'PhabricatorPHPASTApplication' => 'PhabricatorApplication',
|
||||
'PhabricatorPHPConfigSetupCheck' => 'PhabricatorSetupCheck',
|
||||
|
@ -5825,8 +5830,6 @@ phutil_register_library_map(array(
|
|||
'PhabricatorPolicyInterface',
|
||||
'PhabricatorDestructibleInterface',
|
||||
),
|
||||
'PhabricatorRepositoryArcanistProjectDeleteController' => 'PhabricatorRepositoryController',
|
||||
'PhabricatorRepositoryArcanistProjectEditController' => 'PhabricatorRepositoryController',
|
||||
'PhabricatorRepositoryArcanistProjectPHIDType' => 'PhabricatorPHIDType',
|
||||
'PhabricatorRepositoryArcanistProjectQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'PhabricatorRepositoryAuditRequest' => array(
|
||||
|
@ -6724,7 +6727,6 @@ phutil_register_library_map(array(
|
|||
'PhabricatorApplicationTransactionInterface',
|
||||
'PhabricatorPolicyInterface',
|
||||
),
|
||||
'ReleephProjectInfoConduitAPIMethod' => 'ReleephConduitAPIMethod',
|
||||
'ReleephQueryBranchesConduitAPIMethod' => 'ReleephConduitAPIMethod',
|
||||
'ReleephQueryProductsConduitAPIMethod' => 'ReleephConduitAPIMethod',
|
||||
'ReleephQueryRequestsConduitAPIMethod' => 'ReleephConduitAPIMethod',
|
||||
|
|
|
@ -7,8 +7,12 @@ final class ArcanistProjectInfoConduitAPIMethod
|
|||
return 'arcanist.projectinfo';
|
||||
}
|
||||
|
||||
public function getMethodStatus() {
|
||||
return self::METHOD_STATUS_DEPRECATED;
|
||||
}
|
||||
|
||||
public function getMethodDescription() {
|
||||
return pht('Get information about Arcanist projects.');
|
||||
return pht('Arcanist projects are deprecated.');
|
||||
}
|
||||
|
||||
protected function defineParamTypes() {
|
||||
|
|
|
@ -23,6 +23,14 @@ final class PhabricatorAuditInlineComment
|
|||
return $this->proxy;
|
||||
}
|
||||
|
||||
public function supportsHiding() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isHidden() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getTransactionCommentForSave() {
|
||||
$content_source = PhabricatorContentSource::newForSource(
|
||||
PhabricatorContentSource::SOURCE_LEGACY,
|
||||
|
|
|
@ -54,6 +54,8 @@ final class PhabricatorCalendarApplication extends PhabricatorApplication {
|
|||
=> 'PhabricatorCalendarEventEditController',
|
||||
'edit/(?P<id>[1-9]\d*)/'
|
||||
=> 'PhabricatorCalendarEventEditController',
|
||||
'drag/(?P<id>[1-9]\d*)/'
|
||||
=> 'PhabricatorCalendarEventDragController',
|
||||
'cancel/(?P<id>[1-9]\d*)/'
|
||||
=> 'PhabricatorCalendarEventCancelController',
|
||||
'(?P<action>join|decline|accept)/(?P<id>[1-9]\d*)/'
|
||||
|
|
|
@ -5,11 +5,23 @@ abstract class PhabricatorCalendarController extends PhabricatorController {
|
|||
protected function buildApplicationCrumbs() {
|
||||
$crumbs = parent::buildApplicationCrumbs();
|
||||
|
||||
$actions = id(new PhabricatorActionListView())
|
||||
->setUser($this->getViewer())
|
||||
->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Create Private Event'))
|
||||
->setHref('/calendar/event/create/?mode=private'))
|
||||
->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Create Public Event'))
|
||||
->setHref('/calendar/event/create/?mode=public'));
|
||||
|
||||
$crumbs->addAction(
|
||||
id(new PHUIListItemView())
|
||||
->setName(pht('Create Event'))
|
||||
->setHref($this->getApplicationURI().'event/create/')
|
||||
->setIcon('fa-plus-square'));
|
||||
->setIcon('fa-plus-square')
|
||||
->setDropdownMenu($actions));
|
||||
|
||||
return $crumbs;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorCalendarEventDragController
|
||||
extends PhabricatorCalendarController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $request->getViewer();
|
||||
|
||||
$event = id(new PhabricatorCalendarEventQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($request->getURIData('id')))
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->executeOne();
|
||||
if (!$event) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
if (!$request->validateCSRF()) {
|
||||
return new Aphront400Response();
|
||||
}
|
||||
|
||||
if ($event->getIsAllDay()) {
|
||||
return new Aphront400Response();
|
||||
}
|
||||
|
||||
$xactions = array();
|
||||
|
||||
$duration = $event->getDateTo() - $event->getDateFrom();
|
||||
|
||||
$start = $request->getInt('start');
|
||||
$start_value = id(AphrontFormDateControlValue::newFromEpoch(
|
||||
$viewer,
|
||||
$start));
|
||||
|
||||
$end = $start + $duration;
|
||||
$end_value = id(AphrontFormDateControlValue::newFromEpoch(
|
||||
$viewer,
|
||||
$end));
|
||||
|
||||
|
||||
$xactions[] = id(new PhabricatorCalendarEventTransaction())
|
||||
->setTransactionType(
|
||||
PhabricatorCalendarEventTransaction::TYPE_START_DATE)
|
||||
->setNewValue($start_value);
|
||||
|
||||
$xactions[] = id(new PhabricatorCalendarEventTransaction())
|
||||
->setTransactionType(
|
||||
PhabricatorCalendarEventTransaction::TYPE_END_DATE)
|
||||
->setNewValue($end_value);
|
||||
|
||||
|
||||
$editor = id(new PhabricatorCalendarEventEditor())
|
||||
->setActor($viewer)
|
||||
->setContinueOnMissingFields(true)
|
||||
->setContentSourceFromRequest($request)
|
||||
->setContinueOnNoEffect(true);
|
||||
|
||||
$xactions = $editor->applyTransactions($event, $xactions);
|
||||
|
||||
return id(new AphrontReloadResponse());
|
||||
}
|
||||
}
|
|
@ -14,8 +14,8 @@ final class PhabricatorCalendarEventEditController
|
|||
}
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$user = $request->getUser();
|
||||
$user_phid = $user->getPHID();
|
||||
$viewer = $request->getViewer();
|
||||
$user_phid = $viewer->getPHID();
|
||||
$error_name = true;
|
||||
$error_start_date = true;
|
||||
$error_end_date = true;
|
||||
|
@ -25,9 +25,44 @@ final class PhabricatorCalendarEventEditController
|
|||
$start_date_id = celerity_generate_unique_node_id();
|
||||
$end_date_id = null;
|
||||
|
||||
$next_workflow = $request->getStr('next');
|
||||
$uri_query = $request->getStr('query');
|
||||
|
||||
if ($this->isCreate()) {
|
||||
$event = PhabricatorCalendarEvent::initializeNewCalendarEvent($user);
|
||||
list($start_value, $end_value) = $this->getDefaultTimeValues($user);
|
||||
$mode = $request->getStr('mode');
|
||||
$event = PhabricatorCalendarEvent::initializeNewCalendarEvent(
|
||||
$viewer,
|
||||
$mode);
|
||||
|
||||
$create_start_year = $request->getInt('year');
|
||||
$create_start_month = $request->getInt('month');
|
||||
$create_start_day = $request->getInt('day');
|
||||
$create_start_time = $request->getStr('time');
|
||||
|
||||
if ($create_start_year) {
|
||||
$start = AphrontFormDateControlValue::newFromParts(
|
||||
$viewer,
|
||||
$create_start_year,
|
||||
$create_start_month,
|
||||
$create_start_day,
|
||||
$create_start_time);
|
||||
if (!$start->isValid()) {
|
||||
return new Aphront400Response();
|
||||
}
|
||||
$start_value = AphrontFormDateControlValue::newFromEpoch(
|
||||
$viewer,
|
||||
$start->getEpoch());
|
||||
|
||||
$end = clone $start_value->getDateTime();
|
||||
$end->modify('+1 hour');
|
||||
$end_value = AphrontFormDateControlValue::newFromEpoch(
|
||||
$viewer,
|
||||
$end->format('U'));
|
||||
|
||||
} else {
|
||||
list($start_value, $end_value) = $this->getDefaultTimeValues($viewer);
|
||||
}
|
||||
|
||||
|
||||
$submit_label = pht('Create');
|
||||
$page_title = pht('Create Event');
|
||||
|
@ -38,7 +73,7 @@ final class PhabricatorCalendarEventEditController
|
|||
$end_date_id = celerity_generate_unique_node_id();
|
||||
} else {
|
||||
$event = id(new PhabricatorCalendarEventQuery())
|
||||
->setViewer($user)
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($this->id))
|
||||
->requireCapabilities(
|
||||
array(
|
||||
|
@ -51,10 +86,10 @@ final class PhabricatorCalendarEventEditController
|
|||
}
|
||||
|
||||
$end_value = AphrontFormDateControlValue::newFromEpoch(
|
||||
$user,
|
||||
$viewer,
|
||||
$event->getDateTo());
|
||||
$start_value = AphrontFormDateControlValue::newFromEpoch(
|
||||
$user,
|
||||
$viewer,
|
||||
$event->getDateFrom());
|
||||
|
||||
$submit_label = pht('Update');
|
||||
|
@ -81,7 +116,7 @@ final class PhabricatorCalendarEventEditController
|
|||
$icon = $event->getIcon();
|
||||
|
||||
$current_policies = id(new PhabricatorPolicyQuery())
|
||||
->setViewer($user)
|
||||
->setViewer($viewer)
|
||||
->setObject($event)
|
||||
->execute();
|
||||
|
||||
|
@ -106,9 +141,9 @@ final class PhabricatorCalendarEventEditController
|
|||
$new_invitees = $this->getNewInviteeList($invitees, $event);
|
||||
$status_attending = PhabricatorCalendarEventInvitee::STATUS_ATTENDING;
|
||||
if ($this->isCreate()) {
|
||||
$status = idx($new_invitees, $user->getPHID());
|
||||
$status = idx($new_invitees, $viewer->getPHID());
|
||||
if ($status) {
|
||||
$new_invitees[$user->getPHID()] = $status_attending;
|
||||
$new_invitees[$viewer->getPHID()] = $status_attending;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -161,14 +196,29 @@ final class PhabricatorCalendarEventEditController
|
|||
->setNewValue($request->getStr('editPolicy'));
|
||||
|
||||
$editor = id(new PhabricatorCalendarEventEditor())
|
||||
->setActor($user)
|
||||
->setActor($viewer)
|
||||
->setContentSourceFromRequest($request)
|
||||
->setContinueOnNoEffect(true);
|
||||
|
||||
try {
|
||||
$xactions = $editor->applyTransactions($event, $xactions);
|
||||
$response = id(new AphrontRedirectResponse());
|
||||
return $response->setURI('/E'.$event->getID());
|
||||
switch ($next_workflow) {
|
||||
case 'day':
|
||||
if (!$uri_query) {
|
||||
$uri_query = 'month';
|
||||
}
|
||||
$year = $start_value->getDateTime()->format('Y');
|
||||
$month = $start_value->getDateTime()->format('m');
|
||||
$day = $start_value->getDateTime()->format('d');
|
||||
$response->setURI(
|
||||
'/calendar/query/'.$uri_query.'/'.$year.'/'.$month.'/'.$day.'/');
|
||||
break;
|
||||
default:
|
||||
$response->setURI('/E'.$event->getID());
|
||||
break;
|
||||
}
|
||||
return $response;
|
||||
} catch (PhabricatorApplicationTransactionValidationException $ex) {
|
||||
$validation_exception = $ex;
|
||||
$error_name = $ex->getShortMessage(
|
||||
|
@ -204,7 +254,7 @@ final class PhabricatorCalendarEventEditController
|
|||
$all_day_id);
|
||||
|
||||
$start_control = id(new AphrontFormDateControl())
|
||||
->setUser($user)
|
||||
->setUser($viewer)
|
||||
->setName('start')
|
||||
->setLabel(pht('Start'))
|
||||
->setError($error_start_date)
|
||||
|
@ -214,7 +264,7 @@ final class PhabricatorCalendarEventEditController
|
|||
->setEndDateID($end_date_id);
|
||||
|
||||
$end_control = id(new AphrontFormDateControl())
|
||||
->setUser($user)
|
||||
->setUser($viewer)
|
||||
->setName('end')
|
||||
->setLabel(pht('End'))
|
||||
->setError($error_end_date)
|
||||
|
@ -228,13 +278,13 @@ final class PhabricatorCalendarEventEditController
|
|||
->setValue($description);
|
||||
|
||||
$view_policies = id(new AphrontFormPolicyControl())
|
||||
->setUser($user)
|
||||
->setUser($viewer)
|
||||
->setCapability(PhabricatorPolicyCapability::CAN_VIEW)
|
||||
->setPolicyObject($event)
|
||||
->setPolicies($current_policies)
|
||||
->setName('viewPolicy');
|
||||
$edit_policies = id(new AphrontFormPolicyControl())
|
||||
->setUser($user)
|
||||
->setUser($viewer)
|
||||
->setCapability(PhabricatorPolicyCapability::CAN_EDIT)
|
||||
->setPolicyObject($event)
|
||||
->setPolicies($current_policies)
|
||||
|
@ -244,14 +294,14 @@ final class PhabricatorCalendarEventEditController
|
|||
->setLabel(pht('Subscribers'))
|
||||
->setName('subscribers')
|
||||
->setValue($subscribers)
|
||||
->setUser($user)
|
||||
->setUser($viewer)
|
||||
->setDatasource(new PhabricatorMetaMTAMailableDatasource());
|
||||
|
||||
$invitees = id(new AphrontFormTokenizerControl())
|
||||
->setLabel(pht('Invitees'))
|
||||
->setName('invitees')
|
||||
->setValue($invitees)
|
||||
->setUser($user)
|
||||
->setUser($viewer)
|
||||
->setDatasource(new PhabricatorMetaMTAMailableDatasource());
|
||||
|
||||
if ($this->isCreate()) {
|
||||
|
@ -269,7 +319,9 @@ final class PhabricatorCalendarEventEditController
|
|||
->setValue($icon);
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($user)
|
||||
->addHiddenInput('next', $next_workflow)
|
||||
->addHiddenInput('query', $uri_query)
|
||||
->setUser($viewer)
|
||||
->appendChild($name)
|
||||
->appendChild($all_day_checkbox)
|
||||
->appendChild($start_control)
|
||||
|
@ -351,19 +403,19 @@ final class PhabricatorCalendarEventEditController
|
|||
return $new;
|
||||
}
|
||||
|
||||
private function getDefaultTimeValues($user) {
|
||||
private function getDefaultTimeValues($viewer) {
|
||||
$start = new DateTime('@'.time());
|
||||
$start->setTimeZone($user->getTimeZone());
|
||||
$start->setTimeZone($viewer->getTimeZone());
|
||||
|
||||
$start->setTime($start->format('H'), 0, 0);
|
||||
$start->modify('+1 hour');
|
||||
$end = id(clone $start)->modify('+1 hour');
|
||||
|
||||
$start_value = AphrontFormDateControlValue::newFromEpoch(
|
||||
$user,
|
||||
$viewer,
|
||||
$start->format('U'));
|
||||
$end_value = AphrontFormDateControlValue::newFromEpoch(
|
||||
$user,
|
||||
$viewer,
|
||||
$end->format('U'));
|
||||
|
||||
return array($start_value, $end_value);
|
||||
|
|
|
@ -180,6 +180,21 @@ final class PhabricatorCalendarEventQuery
|
|||
|
||||
|
||||
protected function willFilterPage(array $events) {
|
||||
$range_start = $this->rangeBegin;
|
||||
$range_end = $this->rangeEnd;
|
||||
|
||||
foreach ($events as $key => $event) {
|
||||
$event_start = $event->getDateFrom();
|
||||
$event_end = $event->getDateTo();
|
||||
|
||||
if ($range_start && $event_end < $range_start) {
|
||||
unset($events[$key]);
|
||||
}
|
||||
if ($range_end && $event_start > $range_end) {
|
||||
unset($events[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$phids = array();
|
||||
|
||||
foreach ($events as $event) {
|
||||
|
@ -197,6 +212,8 @@ final class PhabricatorCalendarEventQuery
|
|||
$event->attachInvitees($event_invitees);
|
||||
}
|
||||
|
||||
$events = msort($events, 'getDateFrom');
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
|
|
|
@ -390,12 +390,13 @@ final class PhabricatorCalendarEventSearchEngine
|
|||
list($start_year, $start_month, $start_day) =
|
||||
$this->getDisplayYearAndMonthAndDay($query);
|
||||
|
||||
$day_view = new PHUICalendarDayView(
|
||||
$day_view = id(new PHUICalendarDayView(
|
||||
$this->getDateFrom($query),
|
||||
$this->getDateTo($query),
|
||||
$start_year,
|
||||
$start_month,
|
||||
$start_day);
|
||||
$start_day))
|
||||
->setQuery($query->getQueryKey());
|
||||
|
||||
$day_view->setUser($viewer);
|
||||
|
||||
|
@ -408,7 +409,13 @@ final class PhabricatorCalendarEventSearchEngine
|
|||
|
||||
$viewer_is_invited = $status->getIsUserInvited($viewer->getPHID());
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
$status,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
$event = new AphrontCalendarEventView();
|
||||
$event->setCanEdit($can_edit);
|
||||
$event->setEventID($status->getID());
|
||||
$event->setEpochRange($status->getDateFrom(), $status->getDateTo());
|
||||
$event->setIsAllDay($status->getIsAllDay());
|
||||
|
|
|
@ -28,18 +28,26 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
|
|||
private $invitees = self::ATTACHABLE;
|
||||
private $appliedViewer;
|
||||
|
||||
public static function initializeNewCalendarEvent(PhabricatorUser $actor) {
|
||||
public static function initializeNewCalendarEvent(
|
||||
PhabricatorUser $actor,
|
||||
$mode) {
|
||||
$app = id(new PhabricatorApplicationQuery())
|
||||
->setViewer($actor)
|
||||
->withClasses(array('PhabricatorCalendarApplication'))
|
||||
->executeOne();
|
||||
|
||||
if ($mode == 'public') {
|
||||
$view_policy = PhabricatorPolicies::getMostOpenPolicy();
|
||||
} else {
|
||||
$view_policy = $actor->getPHID();
|
||||
}
|
||||
|
||||
return id(new PhabricatorCalendarEvent())
|
||||
->setUserPHID($actor->getPHID())
|
||||
->setIsCancelled(0)
|
||||
->setIsAllDay(0)
|
||||
->setIcon(self::DEFAULT_ICON)
|
||||
->setViewPolicy($actor->getPHID())
|
||||
->setViewPolicy($view_policy)
|
||||
->setEditPolicy($actor->getPHID())
|
||||
->attachInvitees(array())
|
||||
->applyViewerTimezone($actor);
|
||||
|
|
|
@ -12,6 +12,7 @@ final class AphrontCalendarEventView extends AphrontView {
|
|||
private $uri;
|
||||
private $isAllDay;
|
||||
private $icon;
|
||||
private $canEdit;
|
||||
|
||||
public function setURI($uri) {
|
||||
$this->uri = $uri;
|
||||
|
@ -97,6 +98,14 @@ final class AphrontCalendarEventView extends AphrontView {
|
|||
return $this->icon;
|
||||
}
|
||||
|
||||
public function setCanEdit($can_edit) {
|
||||
$this->canEdit = $can_edit;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCanEdit() {
|
||||
return $this->canEdit;
|
||||
}
|
||||
|
||||
public function getMultiDay() {
|
||||
$nextday = strtotime('12:00 AM Tomorrow', $this->getEpochStart());
|
||||
|
|
|
@ -98,7 +98,7 @@ final class PhabricatorConduitLogController
|
|||
array($call->getMethod(), $client),
|
||||
$status,
|
||||
$call->getError(),
|
||||
pht('%d us', number_format($call->getDuration())),
|
||||
pht('%s us', new PhutilNumber($call->getDuration())),
|
||||
phabricator_datetime($call->getDateCreated(), $viewer),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -198,7 +198,7 @@ final class DarkConsoleServicesPlugin extends DarkConsolePlugin {
|
|||
$summary[] = array(
|
||||
$type,
|
||||
number_format($counts[$type]),
|
||||
pht('%d us', number_format((int)(1000000 * $totals[$type]))),
|
||||
pht('%s us', new PhutilNumber((int)(1000000 * $totals[$type]))),
|
||||
sprintf('%.1f%%', 100 * $totals[$type] / $page_total),
|
||||
);
|
||||
}
|
||||
|
@ -258,10 +258,12 @@ final class DarkConsoleServicesPlugin extends DarkConsolePlugin {
|
|||
break;
|
||||
}
|
||||
|
||||
$offset = ($row['begin'] - $data['start']);
|
||||
|
||||
$rows[] = array(
|
||||
$row['type'],
|
||||
pht('+%d ms', number_format(1000 * ($row['begin'] - $data['start']))),
|
||||
pht('%d us', number_format(1000000 * $row['duration'])),
|
||||
pht('+%s ms', new PhutilNumber(1000 * $offset)),
|
||||
pht('%s us', new PhutilNumber(1000000 * $row['duration'])),
|
||||
$info,
|
||||
$analysis,
|
||||
);
|
||||
|
|
|
@ -50,7 +50,7 @@ final class PhabricatorDaemonConsoleController
|
|||
$rows[] = array(
|
||||
$class,
|
||||
number_format($info['n']),
|
||||
pht('%d us', number_format((int)($info['duration'] / $info['n']))),
|
||||
pht('%s us', new PhutilNumber((int)($info['duration'] / $info['n']))),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -141,7 +141,7 @@ final class PhabricatorWorkerTaskDetailController
|
|||
$expires);
|
||||
|
||||
if ($task->isArchived()) {
|
||||
$duration = pht('%d us', number_format($task->getDuration()));
|
||||
$duration = pht('%s us', new PhutilNumber($task->getDuration()));
|
||||
} else {
|
||||
$duration = phutil_tag('em', array(), pht('Not Completed'));
|
||||
}
|
||||
|
|
|
@ -191,6 +191,7 @@ final class DifferentialChangesetViewController extends DifferentialController {
|
|||
if ($revision) {
|
||||
$query = id(new DifferentialInlineCommentQuery())
|
||||
->setViewer($viewer)
|
||||
->needHidden(true)
|
||||
->withRevisionPHIDs(array($revision->getPHID()));
|
||||
$inlines = $query->execute();
|
||||
$inlines = $query->adjustInlinesForChangesets(
|
||||
|
|
|
@ -42,6 +42,7 @@ final class DifferentialInlineCommentEditController
|
|||
->setViewer($this->getViewer())
|
||||
->withIDs(array($id))
|
||||
->withDeletedDrafts(true)
|
||||
->needHidden(true)
|
||||
->executeOne();
|
||||
}
|
||||
|
||||
|
@ -50,6 +51,7 @@ final class DifferentialInlineCommentEditController
|
|||
->setViewer($this->getViewer())
|
||||
->withPHIDs(array($phid))
|
||||
->withDeletedDrafts(true)
|
||||
->needHidden(true)
|
||||
->executeOne();
|
||||
}
|
||||
|
||||
|
@ -152,4 +154,38 @@ final class DifferentialInlineCommentEditController
|
|||
return $this->loadRevision()->getAuthorPHID();
|
||||
}
|
||||
|
||||
protected function hideComments(array $ids) {
|
||||
$viewer = $this->getViewer();
|
||||
$table = new DifferentialHiddenComment();
|
||||
$conn_w = $table->establishConnection('w');
|
||||
|
||||
$sql = array();
|
||||
foreach ($ids as $id) {
|
||||
$sql[] = qsprintf(
|
||||
$conn_w,
|
||||
'(%s, %d)',
|
||||
$viewer->getPHID(),
|
||||
$id);
|
||||
}
|
||||
|
||||
queryfx(
|
||||
$conn_w,
|
||||
'INSERT IGNORE INTO %T (userPHID, commentID) VALUES %Q',
|
||||
$table->getTableName(),
|
||||
implode(', ', $sql));
|
||||
}
|
||||
|
||||
protected function showComments(array $ids) {
|
||||
$viewer = $this->getViewer();
|
||||
$table = new DifferentialHiddenComment();
|
||||
$conn_w = $table->establishConnection('w');
|
||||
|
||||
queryfx(
|
||||
$conn_w,
|
||||
'DELETE FROM %T WHERE userPHID = %s AND commentID IN (%Ld)',
|
||||
$table->getTableName(),
|
||||
$viewer->getPHID(),
|
||||
$ids);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ extends PhabricatorInlineCommentPreviewController {
|
|||
->withDrafts(true)
|
||||
->withAuthorPHIDs(array($viewer->getPHID()))
|
||||
->withRevisionPHIDs(array($revision->getPHID()))
|
||||
->needHidden(true)
|
||||
->execute();
|
||||
}
|
||||
|
||||
|
|
|
@ -175,6 +175,7 @@ final class DifferentialRevisionViewController extends DifferentialController {
|
|||
|
||||
$query = id(new DifferentialInlineCommentQuery())
|
||||
->setViewer($user)
|
||||
->needHidden(true)
|
||||
->withRevisionPHIDs(array($revision->getPHID()));
|
||||
$inlines = $query->execute();
|
||||
$inlines = $query->adjustInlinesForChangesets(
|
||||
|
|
|
@ -47,6 +47,11 @@ final class DifferentialGitHubLandingStrategy
|
|||
DifferentialRevision $revision,
|
||||
PhabricatorRepository $repository) {
|
||||
|
||||
// TODO: This temporarily disables this action, because it doesn't work
|
||||
// and is confusing to users. If you want to use it, comment out this line
|
||||
// for now and we'll provide real support eventually.
|
||||
return;
|
||||
|
||||
$vcs = $repository->getVersionControlSystem();
|
||||
if ($vcs !== PhabricatorRepositoryType::REPOSITORY_TYPE_GIT) {
|
||||
return;
|
||||
|
|
|
@ -906,11 +906,10 @@ final class DifferentialChangesetParser {
|
|||
$shield = $renderer->renderShield(
|
||||
pht('This file was completely deleted.'));
|
||||
} else if ($this->changeset->getAffectedLineCount() > 2500) {
|
||||
$lines = number_format($this->changeset->getAffectedLineCount());
|
||||
$shield = $renderer->renderShield(
|
||||
pht(
|
||||
'This file has a very large number of changes (%s lines).',
|
||||
$lines));
|
||||
new PhutilNumber($this->changeset->getAffectedLineCount())));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ final class DifferentialInlineCommentQuery
|
|||
private $authorPHIDs;
|
||||
private $revisionPHIDs;
|
||||
private $deletedDrafts;
|
||||
private $needHidden;
|
||||
|
||||
public function setViewer(PhabricatorUser $viewer) {
|
||||
$this->viewer = $viewer;
|
||||
|
@ -55,6 +56,11 @@ final class DifferentialInlineCommentQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function needHidden($need) {
|
||||
$this->needHidden = $need;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function execute() {
|
||||
$table = new DifferentialTransactionComment();
|
||||
$conn_r = $table->establishConnection('r');
|
||||
|
@ -68,6 +74,26 @@ final class DifferentialInlineCommentQuery
|
|||
|
||||
$comments = $table->loadAllFromArray($data);
|
||||
|
||||
if ($this->needHidden) {
|
||||
$viewer_phid = $this->getViewer()->getPHID();
|
||||
if ($viewer_phid && $comments) {
|
||||
$hidden = queryfx_all(
|
||||
$conn_r,
|
||||
'SELECT commentID FROM %T WHERE userPHID = %s
|
||||
AND commentID IN (%Ls)',
|
||||
id(new DifferentialHiddenComment())->getTableName(),
|
||||
$viewer_phid,
|
||||
mpull($comments, 'getID'));
|
||||
$hidden = array_fuse(ipull($hidden, 'commentID'));
|
||||
} else {
|
||||
$hidden = array();
|
||||
}
|
||||
|
||||
foreach ($comments as $inline) {
|
||||
$inline->attachIsHidden(isset($hidden[$inline->getID()]));
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($comments as $key => $value) {
|
||||
$comments[$key] = DifferentialInlineComment::newFromModernComment(
|
||||
$value);
|
||||
|
|
|
@ -41,8 +41,10 @@ final class DifferentialChangesetOneUpRenderer
|
|||
|
||||
$column_width = 4;
|
||||
|
||||
$hidden = new PHUIDiffRevealIconView();
|
||||
|
||||
$out = array();
|
||||
foreach ($primitives as $p) {
|
||||
foreach ($primitives as $k => $p) {
|
||||
$type = $p['type'];
|
||||
switch ($type) {
|
||||
case 'old':
|
||||
|
@ -51,6 +53,27 @@ final class DifferentialChangesetOneUpRenderer
|
|||
case 'new-file':
|
||||
$is_old = ($type == 'old' || $type == 'old-file');
|
||||
|
||||
$o_hidden = array();
|
||||
$n_hidden = array();
|
||||
|
||||
for ($look = $k + 1; isset($primitives[$look]); $look++) {
|
||||
$next = $primitives[$look];
|
||||
switch ($next['type']) {
|
||||
case 'inline':
|
||||
$comment = $next['comment'];
|
||||
if ($comment->isHidden()) {
|
||||
if ($next['right']) {
|
||||
$n_hidden[] = $comment;
|
||||
} else {
|
||||
$o_hidden[] = $comment;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
|
||||
$cells = array();
|
||||
if ($is_old) {
|
||||
if ($p['htype']) {
|
||||
|
@ -68,7 +91,13 @@ final class DifferentialChangesetOneUpRenderer
|
|||
} else {
|
||||
$left_id = null;
|
||||
}
|
||||
$cells[] = phutil_tag('th', array('id' => $left_id), $p['line']);
|
||||
|
||||
$line = $p['line'];
|
||||
if ($o_hidden) {
|
||||
$line = array($hidden, $line);
|
||||
}
|
||||
|
||||
$cells[] = phutil_tag('th', array('id' => $left_id), $line);
|
||||
|
||||
$cells[] = phutil_tag('th', array());
|
||||
$cells[] = $no_copy;
|
||||
|
@ -85,7 +114,13 @@ final class DifferentialChangesetOneUpRenderer
|
|||
} else {
|
||||
$left_id = null;
|
||||
}
|
||||
$cells[] = phutil_tag('th', array('id' => $left_id), $p['oline']);
|
||||
|
||||
$oline = $p['oline'];
|
||||
if ($o_hidden) {
|
||||
$oline = array($hidden, $oline);
|
||||
}
|
||||
|
||||
$cells[] = phutil_tag('th', array('id' => $left_id), $oline);
|
||||
}
|
||||
|
||||
if ($type == 'new-file') {
|
||||
|
@ -97,8 +132,13 @@ final class DifferentialChangesetOneUpRenderer
|
|||
} else {
|
||||
$right_id = null;
|
||||
}
|
||||
$cells[] = phutil_tag('th', array('id' => $right_id), $p['line']);
|
||||
|
||||
$line = $p['line'];
|
||||
if ($n_hidden) {
|
||||
$line = array($hidden, $line);
|
||||
}
|
||||
|
||||
$cells[] = phutil_tag('th', array('id' => $right_id), $line);
|
||||
|
||||
$cells[] = $no_copy;
|
||||
$cells[] = phutil_tag('td', array('class' => $class), $p['render']);
|
||||
|
|
|
@ -69,6 +69,8 @@ final class DifferentialChangesetTwoUpRenderer
|
|||
$depths = $this->getDepths();
|
||||
$mask = $this->getMask();
|
||||
|
||||
$hidden = new PHUIDiffRevealIconView();
|
||||
|
||||
for ($ii = $range_start; $ii < $range_start + $range_len; $ii++) {
|
||||
if (empty($mask[$ii])) {
|
||||
// If we aren't going to show this line, we've just entered a gap.
|
||||
|
@ -235,6 +237,69 @@ final class DifferentialChangesetTwoUpRenderer
|
|||
$n_id = null;
|
||||
}
|
||||
|
||||
$old_comments = $this->getOldComments();
|
||||
$new_comments = $this->getNewComments();
|
||||
$scaffolds = array();
|
||||
|
||||
$o_hidden = array();
|
||||
$n_hidden = array();
|
||||
|
||||
if ($o_num && isset($old_comments[$o_num])) {
|
||||
foreach ($old_comments[$o_num] as $comment) {
|
||||
$inline = $this->buildInlineComment(
|
||||
$comment,
|
||||
$on_right = false);
|
||||
$scaffold = $this->getRowScaffoldForInline($inline);
|
||||
|
||||
if ($comment->isHidden()) {
|
||||
$o_hidden[] = $comment;
|
||||
}
|
||||
|
||||
if ($n_num && isset($new_comments[$n_num])) {
|
||||
foreach ($new_comments[$n_num] as $key => $new_comment) {
|
||||
if ($comment->isCompatible($new_comment)) {
|
||||
$companion = $this->buildInlineComment(
|
||||
$new_comment,
|
||||
$on_right = true);
|
||||
|
||||
if ($new_comment->isHidden()) {
|
||||
$n_hidden = $new_comment;
|
||||
}
|
||||
|
||||
$scaffold->addInlineView($companion);
|
||||
unset($new_comments[$n_num][$key]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$scaffolds[] = $scaffold;
|
||||
}
|
||||
}
|
||||
|
||||
if ($n_num && isset($new_comments[$n_num])) {
|
||||
foreach ($new_comments[$n_num] as $comment) {
|
||||
$inline = $this->buildInlineComment(
|
||||
$comment,
|
||||
$on_right = true);
|
||||
|
||||
if ($comment->isHidden()) {
|
||||
$n_hidden[] = $comment;
|
||||
}
|
||||
|
||||
$scaffolds[] = $this->getRowScaffoldForInline($inline);
|
||||
}
|
||||
}
|
||||
|
||||
if ($o_hidden) {
|
||||
$o_num = array($hidden, $o_num);
|
||||
}
|
||||
|
||||
if ($n_hidden) {
|
||||
$n_num = array($hidden, $n_num);
|
||||
}
|
||||
|
||||
// NOTE: This is a unicode zero-width space, which we use as a hint when
|
||||
// intercepting 'copy' events to make sure sensible text ends up on the
|
||||
// clipboard. See the 'phabricator-oncopy' behavior.
|
||||
|
@ -259,40 +324,8 @@ final class DifferentialChangesetTwoUpRenderer
|
|||
$html[] = $context_not_available;
|
||||
}
|
||||
|
||||
$old_comments = $this->getOldComments();
|
||||
$new_comments = $this->getNewComments();
|
||||
|
||||
if ($o_num && isset($old_comments[$o_num])) {
|
||||
foreach ($old_comments[$o_num] as $comment) {
|
||||
$inline = $this->buildInlineComment(
|
||||
$comment,
|
||||
$on_right = false);
|
||||
$scaffold = $this->getRowScaffoldForInline($inline);
|
||||
|
||||
if ($n_num && isset($new_comments[$n_num])) {
|
||||
foreach ($new_comments[$n_num] as $key => $new_comment) {
|
||||
if ($comment->isCompatible($new_comment)) {
|
||||
$companion = $this->buildInlineComment(
|
||||
$new_comment,
|
||||
$on_right = true);
|
||||
|
||||
$scaffold->addInlineView($companion);
|
||||
unset($new_comments[$n_num][$key]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$html[] = $scaffold;
|
||||
}
|
||||
}
|
||||
if ($n_num && isset($new_comments[$n_num])) {
|
||||
foreach ($new_comments[$n_num] as $comment) {
|
||||
$inline = $this->buildInlineComment(
|
||||
$comment,
|
||||
$on_right = true);
|
||||
$html[] = $this->getRowScaffoldForInline($inline);
|
||||
}
|
||||
foreach ($scaffolds as $scaffold) {
|
||||
$html[] = $scaffold;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
final class DifferentialHiddenComment
|
||||
extends DifferentialDAO {
|
||||
|
||||
protected $userPHID;
|
||||
protected $commentID;
|
||||
|
||||
protected function getConfiguration() {
|
||||
return array(
|
||||
self::CONFIG_TIMESTAMPS => false,
|
||||
self::CONFIG_KEY_SCHEMA => array(
|
||||
'key_user' => array(
|
||||
'columns' => array('userPHID', 'commentID'),
|
||||
'unique' => true,
|
||||
),
|
||||
'key_comment' => array(
|
||||
'columns' => array('commentID'),
|
||||
),
|
||||
),
|
||||
) + parent::getConfiguration();
|
||||
}
|
||||
|
||||
}
|
|
@ -24,6 +24,7 @@ final class DifferentialInlineComment
|
|||
->setViewPolicy('public')
|
||||
->setEditPolicy($this->getAuthorPHID())
|
||||
->setContentSource($content_source)
|
||||
->attachIsHidden(false)
|
||||
->setCommentVersion(1);
|
||||
|
||||
return $this->proxy;
|
||||
|
@ -49,6 +50,20 @@ final class DifferentialInlineComment
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function supportsHiding() {
|
||||
if ($this->getSyntheticAuthor()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isHidden() {
|
||||
if (!$this->supportsHiding()) {
|
||||
return false;
|
||||
}
|
||||
return $this->proxy->getIsHidden();
|
||||
}
|
||||
|
||||
public function getID() {
|
||||
return $this->proxy->getID();
|
||||
}
|
||||
|
|
|
@ -522,6 +522,7 @@ final class DifferentialRevision extends DifferentialDAO
|
|||
}
|
||||
|
||||
$query = id(new DifferentialInlineCommentQuery())
|
||||
->needHidden(true)
|
||||
->setViewer($viewer);
|
||||
|
||||
// NOTE: This is a bit sketchy: this method adjusts the inlines as a
|
||||
|
|
|
@ -13,6 +13,7 @@ final class DifferentialTransactionComment
|
|||
protected $replyToCommentPHID;
|
||||
|
||||
private $replyToComment = self::ATTACHABLE;
|
||||
private $isHidden = self::ATTACHABLE;
|
||||
|
||||
public function getApplicationTransactionObject() {
|
||||
return new DifferentialTransaction();
|
||||
|
@ -99,4 +100,13 @@ final class DifferentialTransactionComment
|
|||
return $inline_groups;
|
||||
}
|
||||
|
||||
public function getIsHidden() {
|
||||
return $this->assertAttached($this->isHidden);
|
||||
}
|
||||
|
||||
public function attachIsHidden($hidden) {
|
||||
$this->isHidden = $hidden;
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -232,8 +232,9 @@ final class DifferentialChangesetListView extends AphrontView {
|
|||
|
||||
if ($this->inlineURI) {
|
||||
Javelin::initBehavior('differential-edit-inline-comments', array(
|
||||
'uri' => $this->inlineURI,
|
||||
'stage' => 'differential-review-stage',
|
||||
'uri' => $this->inlineURI,
|
||||
'stage' => 'differential-review-stage',
|
||||
'revealIcon' => hsprintf('%s', new PHUIDiffRevealIconView()),
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
@ -101,6 +101,7 @@ final class PhabricatorDiffusionApplication extends PhabricatorApplication {
|
|||
'(?P<serve>serve)/' => 'DiffusionRepositoryEditHostingController',
|
||||
'update/' => 'DiffusionRepositoryEditUpdateController',
|
||||
'symbol/' => 'DiffusionRepositorySymbolsController',
|
||||
'staging/' => 'DiffusionRepositoryEditStagingController',
|
||||
),
|
||||
'pathtree/(?P<dblob>.*)' => 'DiffusionPathTreeController',
|
||||
'mirror/' => array(
|
||||
|
|
|
@ -20,6 +20,22 @@ final class PhabricatorDiffusionConfigOptions
|
|||
}
|
||||
|
||||
public function getOptions() {
|
||||
$custom_field_type = 'custom:PhabricatorCustomFieldConfigOptionType';
|
||||
|
||||
$fields = array(
|
||||
new PhabricatorCommitRepositoryField(),
|
||||
new PhabricatorCommitBranchesField(),
|
||||
new PhabricatorCommitTagsField(),
|
||||
new PhabricatorCommitMergedCommitsField(),
|
||||
);
|
||||
|
||||
$default_fields = array();
|
||||
foreach ($fields as $field) {
|
||||
$default_fields[$field->getFieldKey()] = array(
|
||||
'disabled' => $field->shouldDisableByDefault(),
|
||||
);
|
||||
}
|
||||
|
||||
return array(
|
||||
$this->newOption(
|
||||
'metamta.diffusion.subject-prefix',
|
||||
|
@ -124,6 +140,12 @@ final class PhabricatorDiffusionConfigOptions
|
|||
'from web traffic (for example, if you use different SSH and '.
|
||||
'web load balancers), you can set the SSH hostname here. This '.
|
||||
'is an advanced option.')),
|
||||
$this->newOption('diffusion.fields', $custom_field_type, $default_fields)
|
||||
->setCustomData(
|
||||
id(new PhabricatorRepositoryCommit())
|
||||
->getCustomFieldBaseClass())
|
||||
->setDescription(
|
||||
pht('Select and reorder Diffusion fields.')),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -240,10 +240,10 @@ final class DiffusionCommitController extends DiffusionController {
|
|||
|
||||
$change_panel = new PHUIObjectBoxView();
|
||||
$header = new PHUIHeaderView();
|
||||
$header->setHeader(pht('Changes (%d', number_format($count)));
|
||||
$header->setHeader(pht('Changes (%s)', new PhutilNumber($count)));
|
||||
$change_panel->setID('toc');
|
||||
if ($count > self::CHANGES_LIMIT && !$show_all_details) {
|
||||
|
||||
if ($count > self::CHANGES_LIMIT && !$show_all_details) {
|
||||
$icon = id(new PHUIIconView())
|
||||
->setIconFont('fa-files-o');
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ final class DiffusionRepositoryEditMainController
|
|||
|
||||
$has_branches = ($is_git || $is_hg);
|
||||
$has_local = $repository->usesLocalWorkingCopy();
|
||||
$supports_staging = $repository->supportsStaging();
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs($is_main = true);
|
||||
|
||||
|
@ -92,6 +93,13 @@ final class DiffusionRepositoryEditMainController
|
|||
$this->buildStorageActions($repository));
|
||||
}
|
||||
|
||||
$staging_properties = null;
|
||||
if ($supports_staging) {
|
||||
$staging_properties = $this->buildStagingProperties(
|
||||
$repository,
|
||||
$this->buildStagingActions($repository));
|
||||
}
|
||||
|
||||
$actions_properties = $this->buildActionsProperties(
|
||||
$repository,
|
||||
$this->buildActionsActions($repository));
|
||||
|
@ -157,6 +165,12 @@ final class DiffusionRepositoryEditMainController
|
|||
->addPropertyList($storage_properties);
|
||||
}
|
||||
|
||||
if ($staging_properties) {
|
||||
$boxes[] = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Staging'))
|
||||
->addPropertyList($staging_properties);
|
||||
}
|
||||
|
||||
$boxes[] = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Text Encoding'))
|
||||
->addPropertyList($encoding_properties);
|
||||
|
@ -609,6 +623,45 @@ final class DiffusionRepositoryEditMainController
|
|||
return $view;
|
||||
}
|
||||
|
||||
|
||||
private function buildStagingActions(PhabricatorRepository $repository) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$view = id(new PhabricatorActionListView())
|
||||
->setObjectURI($this->getRequest()->getRequestURI())
|
||||
->setUser($viewer);
|
||||
|
||||
$edit = id(new PhabricatorActionView())
|
||||
->setIcon('fa-pencil')
|
||||
->setName(pht('Edit Staging'))
|
||||
->setHref(
|
||||
$this->getRepositoryControllerURI($repository, 'edit/staging/'));
|
||||
$view->addAction($edit);
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
private function buildStagingProperties(
|
||||
PhabricatorRepository $repository,
|
||||
PhabricatorActionListView $actions) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$view = id(new PHUIPropertyListView())
|
||||
->setUser($viewer)
|
||||
->setActionList($actions);
|
||||
|
||||
$staging_uri = $repository->getStagingURI();
|
||||
if (!$staging_uri) {
|
||||
$staging_uri = phutil_tag('em', array(), pht('No Staging Area'));
|
||||
}
|
||||
|
||||
$view->addProperty(
|
||||
pht('Staging Area'),
|
||||
$staging_uri);
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
private function buildHostingActions(PhabricatorRepository $repository) {
|
||||
$user = $this->getRequest()->getUser();
|
||||
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionRepositoryEditStagingController
|
||||
extends DiffusionRepositoryEditController {
|
||||
|
||||
protected function processDiffusionRequest(AphrontRequest $request) {
|
||||
$user = $request->getUser();
|
||||
$drequest = $this->diffusionRequest;
|
||||
$repository = $drequest->getRepository();
|
||||
|
||||
$repository = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer($user)
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->withIDs(array($repository->getID()))
|
||||
->executeOne();
|
||||
if (!$repository) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
if (!$repository->supportsStaging()) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
|
||||
|
||||
$v_area = $repository->getHumanReadableDetail('staging-uri');
|
||||
if ($request->isFormPost()) {
|
||||
$v_area = $request->getStr('area');
|
||||
|
||||
$xactions = array();
|
||||
$template = id(new PhabricatorRepositoryTransaction());
|
||||
|
||||
$type_encoding = PhabricatorRepositoryTransaction::TYPE_STAGING_URI;
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_encoding)
|
||||
->setNewValue($v_area);
|
||||
|
||||
id(new PhabricatorRepositoryEditor())
|
||||
->setContinueOnNoEffect(true)
|
||||
->setContentSourceFromRequest($request)
|
||||
->setActor($user)
|
||||
->applyTransactions($repository, $xactions);
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI($edit_uri);
|
||||
}
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb(pht('Edit Staging'));
|
||||
|
||||
$title = pht('Edit %s', $repository->getName());
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($user)
|
||||
->appendRemarkupInstructions(
|
||||
pht(
|
||||
"To make it easier to run integration tests and builds on code ".
|
||||
"under review, you can configure a **Staging Area**. When `arc` ".
|
||||
"creates a diff, it will push a copy of the changes to the ".
|
||||
"configured staging area with a corresponding tag.".
|
||||
"\n\n".
|
||||
"IMPORTANT: This feature is new, experimental, and not supported. ".
|
||||
"Use it at your own risk."))
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setLabel(pht('Staging Area URI'))
|
||||
->setName('area')
|
||||
->setValue($v_area))
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue(pht('Save'))
|
||||
->addCancelButton($edit_uri));
|
||||
|
||||
$object_box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText($title)
|
||||
->setForm($form);
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
array(
|
||||
$crumbs,
|
||||
$object_box,
|
||||
),
|
||||
array(
|
||||
'title' => $title,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionArcanistProjectDatasource
|
||||
extends PhabricatorTypeaheadDatasource {
|
||||
|
||||
public function isBrowsable() {
|
||||
// TODO: We should probably make this browsable, or maybe remove it.
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getBrowseTitle() {
|
||||
return pht('Browse Arcanist Projects');
|
||||
}
|
||||
|
||||
public function getPlaceholderText() {
|
||||
return pht('Type an arcanist project name...');
|
||||
}
|
||||
|
||||
public function getDatasourceApplicationClass() {
|
||||
return 'PhabricatorDiffusionApplication';
|
||||
}
|
||||
|
||||
public function loadResults() {
|
||||
$viewer = $this->getViewer();
|
||||
$raw_query = $this->getRawQuery();
|
||||
|
||||
$results = array();
|
||||
|
||||
$arcprojs = id(new PhabricatorRepositoryArcanistProject())->loadAll();
|
||||
foreach ($arcprojs as $proj) {
|
||||
$results[] = id(new PhabricatorTypeaheadResult())
|
||||
->setName($proj->getName())
|
||||
->setPHID($proj->getPHID());
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
}
|
|
@ -42,7 +42,6 @@ abstract class HeraldAdapter {
|
|||
const FIELD_APPLICATION_EMAIL = 'applicaton-email';
|
||||
const FIELD_TASK_PRIORITY = 'taskpriority';
|
||||
const FIELD_TASK_STATUS = 'taskstatus';
|
||||
const FIELD_ARCANIST_PROJECT = 'arcanist-project';
|
||||
const FIELD_PUSHER_IS_COMMITTER = 'pusher-is-committer';
|
||||
const FIELD_PATH = 'path';
|
||||
|
||||
|
@ -100,7 +99,6 @@ abstract class HeraldAdapter {
|
|||
const VALUE_BUILD_PLAN = 'buildplan';
|
||||
const VALUE_TASK_PRIORITY = 'taskpriority';
|
||||
const VALUE_TASK_STATUS = 'taskstatus';
|
||||
const VALUE_ARCANIST_PROJECT = 'arcanistprojects';
|
||||
const VALUE_LEGAL_DOCUMENTS = 'legaldocuments';
|
||||
const VALUE_APPLICATION_EMAIL = 'applicationemail';
|
||||
|
||||
|
@ -385,7 +383,6 @@ abstract class HeraldAdapter {
|
|||
self::FIELD_APPLICATION_EMAIL => pht('Receiving email address'),
|
||||
self::FIELD_TASK_PRIORITY => pht('Task priority'),
|
||||
self::FIELD_TASK_STATUS => pht('Task status'),
|
||||
self::FIELD_ARCANIST_PROJECT => pht('Arcanist Project'),
|
||||
self::FIELD_PUSHER_IS_COMMITTER => pht('Pusher same as committer'),
|
||||
self::FIELD_PATH => pht('Path'),
|
||||
) + $this->getCustomFieldNameMap();
|
||||
|
@ -441,7 +438,6 @@ abstract class HeraldAdapter {
|
|||
case self::FIELD_PUSHER:
|
||||
case self::FIELD_TASK_PRIORITY:
|
||||
case self::FIELD_TASK_STATUS:
|
||||
case self::FIELD_ARCANIST_PROJECT:
|
||||
return array(
|
||||
self::CONDITION_IS_ANY,
|
||||
self::CONDITION_IS_NOT_ANY,
|
||||
|
@ -946,8 +942,6 @@ abstract class HeraldAdapter {
|
|||
return self::VALUE_TASK_PRIORITY;
|
||||
case self::FIELD_TASK_STATUS:
|
||||
return self::VALUE_TASK_STATUS;
|
||||
case self::FIELD_ARCANIST_PROJECT:
|
||||
return self::VALUE_ARCANIST_PROJECT;
|
||||
default:
|
||||
return self::VALUE_USER;
|
||||
}
|
||||
|
@ -1203,7 +1197,15 @@ abstract class HeraldAdapter {
|
|||
$rule_global = HeraldRuleTypeConfig::RULE_TYPE_GLOBAL;
|
||||
|
||||
$action_type = $action->getAction();
|
||||
$action_name = idx($this->getActionNameMap($rule_global), $action_type);
|
||||
|
||||
$default = $this->isHeraldCustomKey($action_type)
|
||||
? pht('(Unknown Custom Action "%s") equals', $action_type)
|
||||
: pht('(Unknown Action "%s") equals', $action_type);
|
||||
|
||||
$action_name = idx(
|
||||
$this->getActionNameMap($rule_global),
|
||||
$action_type,
|
||||
$default);
|
||||
|
||||
$target = $this->renderActionTargetAsText($action, $handles);
|
||||
|
||||
|
@ -1525,7 +1527,9 @@ abstract class HeraldAdapter {
|
|||
$supported = $this->getActions($rule_type);
|
||||
$supported = array_fuse($supported);
|
||||
if (empty($supported[$action])) {
|
||||
throw new Exception(
|
||||
return new HeraldApplyTranscript(
|
||||
$effect,
|
||||
false,
|
||||
pht(
|
||||
'Adapter "%s" does not support action "%s" for rule type "%s".',
|
||||
get_class($this),
|
||||
|
@ -1548,7 +1552,9 @@ abstract class HeraldAdapter {
|
|||
$result = $this->handleCustomHeraldEffect($effect);
|
||||
|
||||
if (!$result) {
|
||||
throw new Exception(
|
||||
return new HeraldApplyTranscript(
|
||||
$effect,
|
||||
false,
|
||||
pht(
|
||||
'No custom action exists to handle rule action "%s".',
|
||||
$action));
|
||||
|
|
|
@ -154,7 +154,10 @@ final class HeraldDifferentialDiffAdapter extends HeraldDifferentialAdapter {
|
|||
pht('Blocked diff.'));
|
||||
break;
|
||||
default:
|
||||
throw new Exception(pht('No rules to handle action "%s"!', $action));
|
||||
$result[] = new HeraldApplyTranscript(
|
||||
$effect,
|
||||
false,
|
||||
pht('No rules to handle action "%s"!', $action));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -80,7 +80,6 @@ final class HeraldDifferentialRevisionAdapter
|
|||
self::FIELD_AFFECTED_PACKAGE,
|
||||
self::FIELD_AFFECTED_PACKAGE_OWNER,
|
||||
self::FIELD_IS_NEW_OBJECT,
|
||||
self::FIELD_ARCANIST_PROJECT,
|
||||
),
|
||||
parent::getFields());
|
||||
}
|
||||
|
@ -259,8 +258,6 @@ final class HeraldDifferentialRevisionAdapter
|
|||
$packages = $this->loadAffectedPackages();
|
||||
return PhabricatorOwnersOwner::loadAffiliatedUserPHIDs(
|
||||
mpull($packages, 'getID'));
|
||||
case self::FIELD_ARCANIST_PROJECT:
|
||||
return $this->revision->getArcanistProjectPHID();
|
||||
}
|
||||
|
||||
return parent::getHeraldField($field);
|
||||
|
|
|
@ -320,7 +320,7 @@ final class HeraldRuleController extends HeraldController {
|
|||
try {
|
||||
$adapter->willSaveAction($rule, $obj);
|
||||
} catch (HeraldInvalidActionException $ex) {
|
||||
$errors[] = $ex;
|
||||
$errors[] = $ex->getMessage();
|
||||
}
|
||||
|
||||
$actions[] = $obj;
|
||||
|
@ -354,7 +354,6 @@ final class HeraldRuleController extends HeraldController {
|
|||
if ($rule->getConditions()) {
|
||||
$serial_conditions = array();
|
||||
foreach ($rule->getConditions() as $condition) {
|
||||
|
||||
$value = $condition->getValue();
|
||||
switch ($condition->getFieldName()) {
|
||||
case HeraldAdapter::FIELD_TASK_PRIORITY:
|
||||
|
@ -394,10 +393,10 @@ final class HeraldRuleController extends HeraldController {
|
|||
$serial_actions = array(
|
||||
array('default', ''),
|
||||
);
|
||||
|
||||
if ($rule->getActions()) {
|
||||
$serial_actions = array();
|
||||
foreach ($rule->getActions() as $action) {
|
||||
|
||||
switch ($action->getAction()) {
|
||||
case HeraldAdapter::ACTION_FLAG:
|
||||
case HeraldAdapter::ACTION_BLOCK:
|
||||
|
@ -438,21 +437,39 @@ final class HeraldRuleController extends HeraldController {
|
|||
// names of, so that saving a rule without touching anything doesn't change
|
||||
// it.
|
||||
foreach ($rule->getConditions() as $condition) {
|
||||
if (empty($field_map[$condition->getFieldName()])) {
|
||||
$field_map[$condition->getFieldName()] = pht('<Unknown Field>');
|
||||
$field_name = $condition->getFieldName();
|
||||
|
||||
if (empty($field_map[$field_name])) {
|
||||
$field_map[$field_name] = pht('<Unknown Field "%s">', $field_name);
|
||||
}
|
||||
}
|
||||
|
||||
$actions = $adapter->getActions($rule->getRuleType());
|
||||
$action_map = array_select_keys($all_actions, $actions);
|
||||
|
||||
// Populate any actions which exist in the rule but which we don't know the
|
||||
// names of, so that saving a rule without touching anything doesn't change
|
||||
// it.
|
||||
foreach ($rule->getActions() as $action) {
|
||||
$action_name = $action->getAction();
|
||||
|
||||
if (empty($action_map[$action_name])) {
|
||||
$action_map[$action_name] = pht('<Unknown Action "%s">', $action_name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$config_info = array();
|
||||
$config_info['fields'] = $field_map;
|
||||
$config_info['conditions'] = $all_conditions;
|
||||
$config_info['actions'] = $action_map;
|
||||
|
||||
foreach ($config_info['fields'] as $field => $name) {
|
||||
$field_conditions = $adapter->getConditionsForField($field);
|
||||
try {
|
||||
$field_conditions = $adapter->getConditionsForField($field);
|
||||
} catch (Exception $ex) {
|
||||
$field_conditions = array(HeraldAdapter::CONDITION_UNCONDITIONALLY);
|
||||
}
|
||||
$config_info['conditionMap'][$field] = $field_conditions;
|
||||
}
|
||||
|
||||
|
@ -468,9 +485,15 @@ final class HeraldRuleController extends HeraldController {
|
|||
$config_info['rule_type'] = $rule->getRuleType();
|
||||
|
||||
foreach ($config_info['actions'] as $action => $name) {
|
||||
$config_info['targets'][$action] = $adapter->getValueTypeForAction(
|
||||
$action,
|
||||
$rule->getRuleType());
|
||||
try {
|
||||
$action_value = $adapter->getValueTypeForAction(
|
||||
$action,
|
||||
$rule->getRuleType());
|
||||
} catch (Exception $ex) {
|
||||
$action_value = array(HeraldAdapter::VALUE_NONE);
|
||||
}
|
||||
|
||||
$config_info['targets'][$action] = $action_value;
|
||||
}
|
||||
|
||||
$changeflag_options =
|
||||
|
@ -603,7 +626,6 @@ final class HeraldRuleController extends HeraldController {
|
|||
'taskpriority' => new ManiphestTaskPriorityDatasource(),
|
||||
'taskstatus' => new ManiphestTaskStatusDatasource(),
|
||||
'buildplan' => new HarbormasterBuildPlanDatasource(),
|
||||
'arcanistprojects' => new DiffusionArcanistProjectDatasource(),
|
||||
'package' => new PhabricatorOwnersPackageDatasource(),
|
||||
'project' => new PhabricatorProjectDatasource(),
|
||||
'user' => new PhabricatorPeopleDatasource(),
|
||||
|
|
|
@ -380,7 +380,10 @@ final class HeraldTranscriptController extends HeraldController {
|
|||
$item->setState(PHUIObjectItemView::STATE_FAIL);
|
||||
}
|
||||
|
||||
$rule = idx($action_names, $apply_xscript->getAction(), pht('Unknown'));
|
||||
$rule = idx(
|
||||
$action_names,
|
||||
$apply_xscript->getAction(),
|
||||
pht('Unknown Action "%s"', $apply_xscript->getAction()));
|
||||
|
||||
$item->setHeader(pht('%s: %s', $rule, $target));
|
||||
$item->addAttribute($apply_xscript->getReason());
|
||||
|
|
|
@ -272,6 +272,16 @@ final class HeraldEngine {
|
|||
$result = false;
|
||||
} else {
|
||||
foreach ($conditions as $condition) {
|
||||
try {
|
||||
$object->getHeraldField($condition->getFieldName());
|
||||
} catch (Exception $ex) {
|
||||
$reason = pht(
|
||||
'Field "%s" does not exist!',
|
||||
$condition->getFieldName());
|
||||
$result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
$match = $this->doesConditionMatch($rule, $condition, $object);
|
||||
|
||||
if (!$all && $match) {
|
||||
|
|
|
@ -125,7 +125,7 @@ final class HeraldTranscriptSearchEngine
|
|||
}
|
||||
$item->addAttribute($handles[$xscript->getObjectPHID()]->renderLink());
|
||||
$item->addAttribute(
|
||||
pht('%d ms', number_format((int)(1000 * $xscript->getDuration()))));
|
||||
pht('%s ms', new PhutilNumber((int)(1000 * $xscript->getDuration()))));
|
||||
$item->addIcon(
|
||||
'none',
|
||||
phabricator_datetime($xscript->getTime(), $viewer));
|
||||
|
|
|
@ -42,12 +42,11 @@ final class PhabricatorOwnersApplication extends PhabricatorApplication {
|
|||
public function getRoutes() {
|
||||
return array(
|
||||
'/owners/' => array(
|
||||
'' => 'PhabricatorOwnersListController',
|
||||
'view/(?P<view>[^/]+)/' => 'PhabricatorOwnersListController',
|
||||
'(?:query/(?P<queryKey>[^/]+)/)?' => 'PhabricatorOwnersListController',
|
||||
'edit/(?P<id>[1-9]\d*)/' => 'PhabricatorOwnersEditController',
|
||||
'new/' => 'PhabricatorOwnersEditController',
|
||||
'package/(?P<id>[1-9]\d*)/' => 'PhabricatorOwnersDetailController',
|
||||
'delete/(?P<id>[1-9]\d*)/' => 'PhabricatorOwnersDeleteController',
|
||||
'paths/(?P<id>[1-9]\d*)/' => 'PhabricatorOwnersPathsController',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,70 +1,3 @@
|
|||
<?php
|
||||
|
||||
abstract class PhabricatorOwnersController extends PhabricatorController {
|
||||
|
||||
private $filter;
|
||||
|
||||
private function getSideNavFilter() {
|
||||
return $this->filter;
|
||||
}
|
||||
protected function setSideNavFilter($filter) {
|
||||
$this->filter = $filter;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function buildSideNavView() {
|
||||
$nav = new AphrontSideNavFilterView();
|
||||
$base_uri = new PhutilURI('/owners/');
|
||||
$nav->setBaseURI($base_uri);
|
||||
|
||||
$nav->addLabel(pht('Packages'));
|
||||
$this->getExtraPackageViews($nav);
|
||||
$nav->addFilter('view/owned', pht('Owned'));
|
||||
$nav->addFilter('view/projects', pht('Projects'));
|
||||
$nav->addFilter('view/all', pht('All'));
|
||||
|
||||
$nav->selectFilter($this->getSideNavFilter(), 'view/owned');
|
||||
|
||||
$filter = $nav->getSelectedFilter();
|
||||
switch ($filter) {
|
||||
case 'view/owned':
|
||||
$title = pht('Owned Packages');
|
||||
break;
|
||||
case 'view/all':
|
||||
$title = pht('All Packages');
|
||||
break;
|
||||
case 'view/projects':
|
||||
$title = pht('Projects');
|
||||
break;
|
||||
case 'new':
|
||||
$title = pht('New Package');
|
||||
break;
|
||||
default:
|
||||
$title = pht('Package');
|
||||
break;
|
||||
}
|
||||
|
||||
return $nav;
|
||||
}
|
||||
|
||||
protected function buildApplicationCrumbs() {
|
||||
$crumbs = parent::buildApplicationCrumbs();
|
||||
|
||||
$crumbs->addAction(
|
||||
id(new PHUIListItemView())
|
||||
->setName(pht('Create Package'))
|
||||
->setHref('/owners/new/')
|
||||
->setIcon('fa-plus-square'));
|
||||
|
||||
return $crumbs;
|
||||
}
|
||||
|
||||
public function buildApplicationMenu() {
|
||||
return $this->buildSideNavView()->getMenu();
|
||||
}
|
||||
|
||||
protected function getExtraPackageViews(AphrontSideNavFilterView $view) {
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
abstract class PhabricatorOwnersController extends PhabricatorController {}
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorOwnersDeleteController
|
||||
extends PhabricatorOwnersController {
|
||||
|
||||
private $id;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->id = $data['id'];
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$package = id(new PhabricatorOwnersPackage())->load($this->id);
|
||||
if (!$package) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
if ($request->isDialogFormPost()) {
|
||||
id(new PhabricatorOwnersPackageEditor())
|
||||
->setActor($user)
|
||||
->setPackage($package)
|
||||
->delete();
|
||||
return id(new AphrontRedirectResponse())->setURI('/owners/');
|
||||
}
|
||||
|
||||
$text = pht(
|
||||
'Are you sure you want to delete the "%s" package? This '.
|
||||
'operation can not be undone.',
|
||||
$package->getName());
|
||||
$dialog = id(new AphrontDialogView())
|
||||
->setUser($user)
|
||||
->setTitle(pht('Really delete this package?'))
|
||||
->appendChild(phutil_tag('p', array(), $text))
|
||||
->addSubmitButton(pht('Delete'))
|
||||
->addCancelButton('/owners/package/'.$package->getID().'/')
|
||||
->setSubmitURI($request->getRequestURI());
|
||||
|
||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
||||
}
|
||||
|
||||
}
|
|
@ -3,25 +3,22 @@
|
|||
final class PhabricatorOwnersDetailController
|
||||
extends PhabricatorOwnersController {
|
||||
|
||||
private $id;
|
||||
private $package;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->id = $data['id'];
|
||||
public function shouldAllowPublic() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$package = id(new PhabricatorOwnersPackage())->load($this->id);
|
||||
$package = id(new PhabricatorOwnersPackageQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($request->getURIData('id')))
|
||||
->executeOne();
|
||||
if (!$package) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
$this->package = $package;
|
||||
|
||||
$paths = $package->loadPaths();
|
||||
$owners = $package->loadOwners();
|
||||
|
||||
$repository_phids = array();
|
||||
foreach ($paths as $path) {
|
||||
|
@ -30,7 +27,7 @@ final class PhabricatorOwnersDetailController
|
|||
|
||||
if ($repository_phids) {
|
||||
$repositories = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer($user)
|
||||
->setViewer($viewer)
|
||||
->withPHIDs(array_keys($repository_phids))
|
||||
->execute();
|
||||
$repositories = mpull($repositories, null, 'getPHID');
|
||||
|
@ -38,101 +35,18 @@ final class PhabricatorOwnersDetailController
|
|||
$repositories = array();
|
||||
}
|
||||
|
||||
$phids = array();
|
||||
foreach ($owners as $owner) {
|
||||
$phids[$owner->getUserPHID()] = true;
|
||||
}
|
||||
$phids = array_keys($phids);
|
||||
$actions = $this->buildPackageActionView($package);
|
||||
$properties = $this->buildPackagePropertyView($package);
|
||||
$properties->setActionList($actions);
|
||||
|
||||
$handles = $this->loadViewerHandles($phids);
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setUser($viewer)
|
||||
->setHeader($package->getName())
|
||||
->setPolicyObject($package);
|
||||
|
||||
$rows = array();
|
||||
|
||||
$rows[] = array(pht('Name'), $package->getName());
|
||||
$rows[] = array(pht('Description'), $package->getDescription());
|
||||
|
||||
$primary_owner = null;
|
||||
$primary_phid = $package->getPrimaryOwnerPHID();
|
||||
if ($primary_phid && isset($handles[$primary_phid])) {
|
||||
$primary_owner = phutil_tag(
|
||||
'strong',
|
||||
array(),
|
||||
$handles[$primary_phid]->renderLink());
|
||||
}
|
||||
$rows[] = array(pht('Primary Owner'), $primary_owner);
|
||||
|
||||
$owner_links = array();
|
||||
foreach ($owners as $owner) {
|
||||
$owner_links[] = $handles[$owner->getUserPHID()]->renderLink();
|
||||
}
|
||||
$owner_links = phutil_implode_html(phutil_tag('br'), $owner_links);
|
||||
$rows[] = array(pht('Owners'), $owner_links);
|
||||
|
||||
$rows[] = array(
|
||||
pht('Auditing'),
|
||||
$package->getAuditingEnabled() ?
|
||||
pht('Enabled') :
|
||||
pht('Disabled'),
|
||||
);
|
||||
|
||||
$path_links = array();
|
||||
foreach ($paths as $path) {
|
||||
$repo = idx($repositories, $path->getRepositoryPHID());
|
||||
if (!$repo) {
|
||||
continue;
|
||||
}
|
||||
$href = DiffusionRequest::generateDiffusionURI(
|
||||
array(
|
||||
'callsign' => $repo->getCallsign(),
|
||||
'branch' => $repo->getDefaultBranch(),
|
||||
'path' => $path->getPath(),
|
||||
'action' => 'browse',
|
||||
));
|
||||
$repo_name = phutil_tag('strong', array(), $repo->getName());
|
||||
$path_link = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => (string)$href,
|
||||
),
|
||||
$path->getPath());
|
||||
$path_links[] = hsprintf(
|
||||
'%s %s %s',
|
||||
($path->getExcluded() ? "\xE2\x80\x93" : '+'),
|
||||
$repo_name,
|
||||
$path_link);
|
||||
}
|
||||
$path_links = phutil_implode_html(phutil_tag('br'), $path_links);
|
||||
$rows[] = array(pht('Paths'), $path_links);
|
||||
|
||||
$table = new AphrontTableView($rows);
|
||||
$table->setColumnClasses(
|
||||
array(
|
||||
'header',
|
||||
'wide',
|
||||
));
|
||||
|
||||
$panel = new PHUIObjectBoxView();
|
||||
$header = new PHUIHeaderView();
|
||||
$header->setHeader(
|
||||
pht('Package Details for "%s"', $package->getName()));
|
||||
$header->addActionLink(
|
||||
id(new PHUIButtonView())
|
||||
->setTag('a')
|
||||
->setHref('/owners/delete/'.$package->getID().'/')
|
||||
->addSigil('workflow')
|
||||
->setText(pht('Delete Package')));
|
||||
|
||||
$header->addActionLink(
|
||||
id(new PHUIButtonView())
|
||||
->setTag('a')
|
||||
->setHref('/owners/edit/'.$package->getID().'/')
|
||||
->setText(pht('Edit Package')));
|
||||
|
||||
$panel->setHeader($header);
|
||||
$panel->setTable($table);
|
||||
|
||||
$key = 'package/'.$package->getID();
|
||||
$this->setSideNavFilter($key);
|
||||
$panel = id(new PHUIObjectBoxView())
|
||||
->setHeader($header)
|
||||
->addPropertyList($properties);
|
||||
|
||||
$commit_views = array();
|
||||
|
||||
|
@ -151,7 +65,7 @@ final class PhabricatorOwnersDetailController
|
|||
->execute();
|
||||
if ($attention_commits) {
|
||||
$view = id(new PhabricatorAuditListView())
|
||||
->setUser($user)
|
||||
->setUser($viewer)
|
||||
->setCommits($attention_commits);
|
||||
|
||||
$commit_views[] = array(
|
||||
|
@ -172,7 +86,7 @@ final class PhabricatorOwnersDetailController
|
|||
->execute();
|
||||
|
||||
$view = id(new PhabricatorAuditListView())
|
||||
->setUser($user)
|
||||
->setUser($viewer)
|
||||
->setCommits($all_commits)
|
||||
->setNoDataString(pht('No commits in this package.'));
|
||||
|
||||
|
@ -210,21 +124,165 @@ final class PhabricatorOwnersDetailController
|
|||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb($package->getName());
|
||||
|
||||
$nav = $this->buildSideNavView();
|
||||
$nav->appendChild($crumbs);
|
||||
$nav->appendChild($panel);
|
||||
$nav->appendChild($commit_panels);
|
||||
$timeline = $this->buildTransactionTimeline(
|
||||
$package,
|
||||
new PhabricatorOwnersPackageTransactionQuery());
|
||||
$timeline->setShouldTerminate(true);
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
$nav,
|
||||
array(
|
||||
'title' => pht('Package %s', $package->getName()),
|
||||
$crumbs,
|
||||
$panel,
|
||||
$this->renderPathsTable($paths, $repositories),
|
||||
$commit_panels,
|
||||
$timeline,
|
||||
),
|
||||
array(
|
||||
'title' => $package->getName(),
|
||||
));
|
||||
}
|
||||
|
||||
protected function getExtraPackageViews(AphrontSideNavFilterView $view) {
|
||||
$package = $this->package;
|
||||
$view->addFilter('package/'.$package->getID(), pht('Details'));
|
||||
|
||||
private function buildPackagePropertyView(PhabricatorOwnersPackage $package) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$view = id(new PHUIPropertyListView())
|
||||
->setUser($viewer);
|
||||
|
||||
$primary_phid = $package->getPrimaryOwnerPHID();
|
||||
if ($primary_phid) {
|
||||
$primary_owner = $viewer->renderHandle($primary_phid);
|
||||
} else {
|
||||
$primary_owner = phutil_tag('em', array(), pht('None'));
|
||||
}
|
||||
$view->addProperty(pht('Primary Owner'), $primary_owner);
|
||||
|
||||
// TODO: needOwners() this on the Query.
|
||||
$owners = $package->loadOwners();
|
||||
if ($owners) {
|
||||
$owner_list = $viewer->renderHandleList(mpull($owners, 'getUserPHID'));
|
||||
} else {
|
||||
$owner_list = phutil_tag('em', array(), pht('None'));
|
||||
}
|
||||
$view->addProperty(pht('Owners'), $owner_list);
|
||||
|
||||
if ($package->getAuditingEnabled()) {
|
||||
$auditing = pht('Enabled');
|
||||
} else {
|
||||
$auditing = pht('Disabled');
|
||||
}
|
||||
$view->addProperty(pht('Auditing'), $auditing);
|
||||
|
||||
$description = $package->getDescription();
|
||||
if (strlen($description)) {
|
||||
$view->addSectionHeader(pht('Description'));
|
||||
$view->addTextContent(
|
||||
$output = PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())->setContent($description),
|
||||
'default',
|
||||
$viewer));
|
||||
}
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
private function buildPackageActionView(PhabricatorOwnersPackage $package) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
// TODO: Implement this capability.
|
||||
$can_edit = true;
|
||||
|
||||
$id = $package->getID();
|
||||
$edit_uri = $this->getApplicationURI("/edit/{$id}/");
|
||||
$paths_uri = $this->getApplicationURI("/paths/{$id}/");
|
||||
|
||||
$view = id(new PhabricatorActionListView())
|
||||
->setUser($viewer)
|
||||
->setObject($package)
|
||||
->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Edit Package'))
|
||||
->setIcon('fa-pencil')
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(!$can_edit)
|
||||
->setHref($edit_uri))
|
||||
->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Edit Paths'))
|
||||
->setIcon('fa-folder-open')
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(!$can_edit)
|
||||
->setHref($paths_uri));
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
private function renderPathsTable(array $paths, array $repositories) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$rows = array();
|
||||
foreach ($paths as $path) {
|
||||
$repo = idx($repositories, $path->getRepositoryPHID());
|
||||
if (!$repo) {
|
||||
continue;
|
||||
}
|
||||
$href = DiffusionRequest::generateDiffusionURI(
|
||||
array(
|
||||
'callsign' => $repo->getCallsign(),
|
||||
'branch' => $repo->getDefaultBranch(),
|
||||
'path' => $path->getPath(),
|
||||
'action' => 'browse',
|
||||
));
|
||||
|
||||
$path_link = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => (string)$href,
|
||||
),
|
||||
$path->getPath());
|
||||
|
||||
$rows[] = array(
|
||||
($path->getExcluded() ? '-' : '+'),
|
||||
$repo->getName(),
|
||||
$path_link,
|
||||
);
|
||||
}
|
||||
|
||||
$info = null;
|
||||
if (!$paths) {
|
||||
$info = id(new PHUIInfoView())
|
||||
->setSeverity(PHUIInfoView::SEVERITY_WARNING)
|
||||
->setErrors(
|
||||
array(
|
||||
pht(
|
||||
'This package does not contain any paths yet. Use '.
|
||||
'"Edit Paths" to add some.'),
|
||||
));
|
||||
}
|
||||
|
||||
$table = id(new AphrontTableView($rows))
|
||||
->setHeaders(
|
||||
array(
|
||||
null,
|
||||
pht('Repository'),
|
||||
pht('Path'),
|
||||
))
|
||||
->setColumnClasses(
|
||||
array(
|
||||
null,
|
||||
null,
|
||||
'wide',
|
||||
));
|
||||
|
||||
$box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Paths'))
|
||||
->appendChild($table);
|
||||
|
||||
if ($info) {
|
||||
$box->setInfoView($info);
|
||||
}
|
||||
|
||||
return $box;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,180 +3,132 @@
|
|||
final class PhabricatorOwnersEditController
|
||||
extends PhabricatorOwnersController {
|
||||
|
||||
private $id;
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $request->getUser();
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->id = idx($data, 'id');
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
if ($this->id) {
|
||||
$package = id(new PhabricatorOwnersPackage())->load($this->id);
|
||||
$id = $request->getURIData('id');
|
||||
if ($id) {
|
||||
$package = id(new PhabricatorOwnersPackageQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($id))
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
// TODO: Support this capability.
|
||||
// PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->executeOne();
|
||||
if (!$package) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
$is_new = false;
|
||||
} else {
|
||||
$package = new PhabricatorOwnersPackage();
|
||||
$package->setPrimaryOwnerPHID($user->getPHID());
|
||||
$package = PhabricatorOwnersPackage::initializeNewPackage($viewer);
|
||||
$is_new = true;
|
||||
}
|
||||
|
||||
$e_name = true;
|
||||
$e_primary = true;
|
||||
|
||||
$v_name = $package->getName();
|
||||
$v_primary = $package->getPrimaryOwnerPHID();
|
||||
// TODO: Pull these off needOwners() on the Query.
|
||||
$v_owners = mpull($package->loadOwners(), 'getUserPHID');
|
||||
$v_auditing = $package->getAuditingEnabled();
|
||||
$v_description = $package->getDescription();
|
||||
|
||||
|
||||
$errors = array();
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$package->setName($request->getStr('name'));
|
||||
$package->setDescription($request->getStr('description'));
|
||||
$old_auditing_enabled = $package->getAuditingEnabled();
|
||||
$package->setAuditingEnabled(
|
||||
($request->getStr('auditing') === 'enabled')
|
||||
? 1
|
||||
: 0);
|
||||
$xactions = array();
|
||||
|
||||
$primary = $request->getArr('primary');
|
||||
$primary = reset($primary);
|
||||
$old_primary = $package->getPrimaryOwnerPHID();
|
||||
$package->setPrimaryOwnerPHID($primary);
|
||||
$v_name = $request->getStr('name');
|
||||
$v_primary = head($request->getArr('primary'));
|
||||
$v_owners = $request->getArr('owners');
|
||||
$v_auditing = ($request->getStr('auditing') == 'enabled');
|
||||
$v_description = $request->getStr('description');
|
||||
|
||||
$owners = $request->getArr('owners');
|
||||
if ($primary) {
|
||||
array_unshift($owners, $primary);
|
||||
if ($v_primary) {
|
||||
$v_owners[] = $v_primary;
|
||||
$v_owners = array_unique($v_owners);
|
||||
}
|
||||
$owners = array_unique($owners);
|
||||
|
||||
$paths = $request->getArr('path');
|
||||
$repos = $request->getArr('repo');
|
||||
$excludes = $request->getArr('exclude');
|
||||
$type_name = PhabricatorOwnersPackageTransaction::TYPE_NAME;
|
||||
$type_primary = PhabricatorOwnersPackageTransaction::TYPE_PRIMARY;
|
||||
$type_owners = PhabricatorOwnersPackageTransaction::TYPE_OWNERS;
|
||||
$type_auditing = PhabricatorOwnersPackageTransaction::TYPE_AUDITING;
|
||||
$type_description = PhabricatorOwnersPackageTransaction::TYPE_DESCRIPTION;
|
||||
|
||||
$path_refs = array();
|
||||
for ($ii = 0; $ii < count($paths); $ii++) {
|
||||
if (empty($paths[$ii]) || empty($repos[$ii])) {
|
||||
continue;
|
||||
$xactions[] = id(new PhabricatorOwnersPackageTransaction())
|
||||
->setTransactionType($type_name)
|
||||
->setNewValue($v_name);
|
||||
|
||||
$xactions[] = id(new PhabricatorOwnersPackageTransaction())
|
||||
->setTransactionType($type_primary)
|
||||
->setNewValue($v_primary);
|
||||
|
||||
$xactions[] = id(new PhabricatorOwnersPackageTransaction())
|
||||
->setTransactionType($type_owners)
|
||||
->setNewValue($v_owners);
|
||||
|
||||
$xactions[] = id(new PhabricatorOwnersPackageTransaction())
|
||||
->setTransactionType($type_auditing)
|
||||
->setNewValue($v_auditing);
|
||||
|
||||
$xactions[] = id(new PhabricatorOwnersPackageTransaction())
|
||||
->setTransactionType($type_description)
|
||||
->setNewValue($v_description);
|
||||
|
||||
$editor = id(new PhabricatorOwnersPackageTransactionEditor())
|
||||
->setActor($viewer)
|
||||
->setContentSourceFromRequest($request)
|
||||
->setContinueOnNoEffect(true);
|
||||
|
||||
try {
|
||||
$editor->applyTransactions($package, $xactions);
|
||||
|
||||
$id = $package->getID();
|
||||
if ($is_new) {
|
||||
$next_uri = '/owners/paths/'.$id.'/';
|
||||
} else {
|
||||
$next_uri = '/owners/package/'.$id.'/';
|
||||
}
|
||||
$path_refs[] = array(
|
||||
'repositoryPHID' => $repos[$ii],
|
||||
'path' => $paths[$ii],
|
||||
'excluded' => $excludes[$ii],
|
||||
);
|
||||
}
|
||||
|
||||
if (!strlen($package->getName())) {
|
||||
$e_name = pht('Required');
|
||||
$errors[] = pht('Package name is required.');
|
||||
} else {
|
||||
$e_name = null;
|
||||
}
|
||||
return id(new AphrontRedirectResponse())->setURI($next_uri);
|
||||
} catch (AphrontDuplicateKeyQueryException $ex) {
|
||||
$e_name = pht('Duplicate');
|
||||
$errors[] = pht('Package name must be unique.');
|
||||
} catch (PhabricatorApplicationTransactionValidationException $ex) {
|
||||
$validation_exception = $ex;
|
||||
|
||||
if (!$package->getPrimaryOwnerPHID()) {
|
||||
$e_primary = pht('Required');
|
||||
$errors[] = pht('Package must have a primary owner.');
|
||||
} else {
|
||||
$e_primary = null;
|
||||
}
|
||||
|
||||
if (!$path_refs) {
|
||||
$errors[] = pht('Package must include at least one path.');
|
||||
}
|
||||
|
||||
if (!$errors) {
|
||||
$package->attachUnsavedOwners($owners);
|
||||
$package->attachUnsavedPaths($path_refs);
|
||||
$package->attachOldAuditingEnabled($old_auditing_enabled);
|
||||
$package->attachOldPrimaryOwnerPHID($old_primary);
|
||||
try {
|
||||
id(new PhabricatorOwnersPackageEditor())
|
||||
->setActor($user)
|
||||
->setPackage($package)
|
||||
->save();
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI('/owners/package/'.$package->getID().'/');
|
||||
} catch (AphrontDuplicateKeyQueryException $ex) {
|
||||
$e_name = pht('Duplicate');
|
||||
$errors[] = pht('Package name must be unique.');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$owners = $package->loadOwners();
|
||||
$owners = mpull($owners, 'getUserPHID');
|
||||
|
||||
$paths = $package->loadPaths();
|
||||
$path_refs = array();
|
||||
foreach ($paths as $path) {
|
||||
$path_refs[] = array(
|
||||
'repositoryPHID' => $path->getRepositoryPHID(),
|
||||
'path' => $path->getPath(),
|
||||
'excluded' => $path->getExcluded(),
|
||||
);
|
||||
$e_name = $ex->getShortMessage($type_name);
|
||||
$e_primary = $ex->getShortMessage($type_primary);
|
||||
}
|
||||
}
|
||||
|
||||
$primary = $package->getPrimaryOwnerPHID();
|
||||
if ($primary) {
|
||||
$value_primary_owner = array($primary);
|
||||
if ($v_primary) {
|
||||
$value_primary_owner = array($v_primary);
|
||||
} else {
|
||||
$value_primary_owner = array();
|
||||
}
|
||||
|
||||
if ($package->getID()) {
|
||||
$title = pht('Edit Package');
|
||||
$side_nav_filter = 'edit/'.$this->id;
|
||||
} else {
|
||||
if ($is_new) {
|
||||
$cancel_uri = '/owners/';
|
||||
$title = pht('New Package');
|
||||
$side_nav_filter = 'new';
|
||||
$button_text = pht('Continue');
|
||||
} else {
|
||||
$cancel_uri = '/owners/package/'.$package->getID().'/';
|
||||
$title = pht('Edit Package');
|
||||
$button_text = pht('Save Package');
|
||||
}
|
||||
$this->setSideNavFilter($side_nav_filter);
|
||||
|
||||
$repos = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer($user)
|
||||
->execute();
|
||||
|
||||
$default_paths = array();
|
||||
foreach ($repos as $repo) {
|
||||
$default_path = $repo->getDetail('default-owners-path');
|
||||
if ($default_path) {
|
||||
$default_paths[$repo->getPHID()] = $default_path;
|
||||
}
|
||||
}
|
||||
|
||||
$repos = mpull($repos, 'getCallsign', 'getPHID');
|
||||
asort($repos);
|
||||
|
||||
$template = new AphrontTypeaheadTemplateView();
|
||||
$template = $template->render();
|
||||
|
||||
Javelin::initBehavior(
|
||||
'owners-path-editor',
|
||||
array(
|
||||
'root' => 'path-editor',
|
||||
'table' => 'paths',
|
||||
'add_button' => 'addpath',
|
||||
'repositories' => $repos,
|
||||
'input_template' => $template,
|
||||
'pathRefs' => $path_refs,
|
||||
|
||||
'completeURI' => '/diffusion/services/path/complete/',
|
||||
'validateURI' => '/diffusion/services/path/validate/',
|
||||
|
||||
'repositoryDefaultPaths' => $default_paths,
|
||||
));
|
||||
|
||||
require_celerity_resource('owners-path-editor-css');
|
||||
|
||||
$cancel_uri = $package->getID()
|
||||
? '/owners/package/'.$package->getID().'/'
|
||||
: '/owners/';
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($user)
|
||||
->setUser($viewer)
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setLabel(pht('Name'))
|
||||
->setName('name')
|
||||
->setValue($package->getName())
|
||||
->setValue($v_name)
|
||||
->setError($e_name))
|
||||
->appendControl(
|
||||
id(new AphrontFormTokenizerControl())
|
||||
|
@ -191,7 +143,7 @@ final class PhabricatorOwnersEditController
|
|||
->setDatasource(new PhabricatorProjectOrUserDatasource())
|
||||
->setLabel(pht('Owners'))
|
||||
->setName('owners')
|
||||
->setValue($owners))
|
||||
->setValue($v_owners))
|
||||
->appendChild(
|
||||
id(new AphrontFormSelectControl())
|
||||
->setName('auditing')
|
||||
|
@ -202,47 +154,22 @@ final class PhabricatorOwnersEditController
|
|||
'this package will be reviewed to make sure an owner '.
|
||||
'of the package is involved and the commit message has '.
|
||||
'a valid revision, reviewed by, and author.'))
|
||||
->setOptions(array(
|
||||
'disabled' => pht('Disabled'),
|
||||
'enabled' => pht('Enabled'),
|
||||
))
|
||||
->setValue(
|
||||
$package->getAuditingEnabled()
|
||||
? 'enabled'
|
||||
: 'disabled'))
|
||||
->setOptions(
|
||||
array(
|
||||
'disabled' => pht('Disabled'),
|
||||
'enabled' => pht('Enabled'),
|
||||
))
|
||||
->setValue(($v_auditing ? 'enabled' : 'disabled')))
|
||||
->appendChild(
|
||||
id(new PHUIFormInsetView())
|
||||
->setTitle(pht('Paths'))
|
||||
->addDivAttributes(array('id' => 'path-editor'))
|
||||
->setRightButton(javelin_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '#',
|
||||
'class' => 'button green',
|
||||
'sigil' => 'addpath',
|
||||
'mustcapture' => true,
|
||||
),
|
||||
pht('Add New Path')))
|
||||
->setDescription(
|
||||
pht(
|
||||
'Specify the files and directories which comprise '.
|
||||
'this package.'))
|
||||
->setContent(javelin_tag(
|
||||
'table',
|
||||
array(
|
||||
'class' => 'owners-path-editor-table',
|
||||
'sigil' => 'paths',
|
||||
),
|
||||
'')))
|
||||
->appendChild(
|
||||
id(new AphrontFormTextAreaControl())
|
||||
id(new PhabricatorRemarkupControl())
|
||||
->setUser($viewer)
|
||||
->setLabel(pht('Description'))
|
||||
->setName('description')
|
||||
->setValue($package->getDescription()))
|
||||
->setValue($v_description))
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->addCancelButton($cancel_uri)
|
||||
->setValue(pht('Save Package')));
|
||||
->setValue($button_text));
|
||||
|
||||
$form_box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText($title)
|
||||
|
@ -251,29 +178,22 @@ final class PhabricatorOwnersEditController
|
|||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
if ($package->getID()) {
|
||||
$crumbs->addTextCrumb(pht('Edit %s', $package->getName()));
|
||||
$crumbs->addTextCrumb(
|
||||
$package->getName(),
|
||||
$this->getApplicationURI('package/'.$package->getID().'/'));
|
||||
$crumbs->addTextCrumb(pht('Edit'));
|
||||
} else {
|
||||
$crumbs->addTextCrumb(pht('New Package'));
|
||||
}
|
||||
|
||||
$nav = $this->buildSideNavView();
|
||||
$nav->appendChild($crumbs);
|
||||
$nav->appendChild($form_box);
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
array(
|
||||
$nav,
|
||||
$crumbs,
|
||||
$form_box,
|
||||
),
|
||||
array(
|
||||
'title' => $title,
|
||||
));
|
||||
}
|
||||
|
||||
protected function getExtraPackageViews(AphrontSideNavFilterView $view) {
|
||||
if ($this->id) {
|
||||
$view->addFilter('edit/'.$this->id, pht('Edit'));
|
||||
} else {
|
||||
$view->addFilter('new', pht('New'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,340 +3,52 @@
|
|||
final class PhabricatorOwnersListController
|
||||
extends PhabricatorOwnersController {
|
||||
|
||||
protected $view;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->view = idx($data, 'view', 'owned');
|
||||
$this->setSideNavFilter('view/'.$this->view);
|
||||
public function shouldAllowPublic() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$controller = id(new PhabricatorApplicationSearchController())
|
||||
->setQueryKey($request->getURIData('queryKey'))
|
||||
->setSearchEngine(new PhabricatorOwnersPackageSearchEngine())
|
||||
->setNavigation($this->buildSideNavView());
|
||||
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$package = new PhabricatorOwnersPackage();
|
||||
$owner = new PhabricatorOwnersOwner();
|
||||
$path = new PhabricatorOwnersPath();
|
||||
|
||||
$repository_phid = '';
|
||||
if ($request->getStr('repository') != '') {
|
||||
$repository_phid = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer($user)
|
||||
->withCallsigns(array($request->getStr('repository')))
|
||||
->executeOne()
|
||||
->getPHID();
|
||||
}
|
||||
|
||||
switch ($this->view) {
|
||||
case 'search':
|
||||
$packages = array();
|
||||
|
||||
$conn_r = $package->establishConnection('r');
|
||||
|
||||
$where = array('1 = 1');
|
||||
$join = array();
|
||||
$having = '';
|
||||
|
||||
if ($request->getStr('name')) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'p.name LIKE %~',
|
||||
$request->getStr('name'));
|
||||
}
|
||||
|
||||
if ($repository_phid || $request->getStr('path')) {
|
||||
|
||||
$join[] = qsprintf(
|
||||
$conn_r,
|
||||
'JOIN %T path ON path.packageID = p.id',
|
||||
$path->getTableName());
|
||||
|
||||
if ($repository_phid) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'path.repositoryPHID = %s',
|
||||
$repository_phid);
|
||||
}
|
||||
|
||||
if ($request->getStr('path')) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'(path.path LIKE %~ AND NOT path.excluded) OR
|
||||
%s LIKE CONCAT(REPLACE(path.path, %s, %s), %s)',
|
||||
$request->getStr('path'),
|
||||
$request->getStr('path'),
|
||||
'_',
|
||||
'\_',
|
||||
'%');
|
||||
$having = 'HAVING MAX(path.excluded) = 0';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ($request->getArr('owner')) {
|
||||
$join[] = qsprintf(
|
||||
$conn_r,
|
||||
'JOIN %T o ON o.packageID = p.id',
|
||||
$owner->getTableName());
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'o.userPHID IN (%Ls)',
|
||||
$request->getArr('owner'));
|
||||
}
|
||||
|
||||
$data = queryfx_all(
|
||||
$conn_r,
|
||||
'SELECT p.* FROM %T p %Q WHERE %Q GROUP BY p.id %Q',
|
||||
$package->getTableName(),
|
||||
implode(' ', $join),
|
||||
'('.implode(') AND (', $where).')',
|
||||
$having);
|
||||
$packages = $package->loadAllFromArray($data);
|
||||
|
||||
$header = pht('Search Results');
|
||||
$nodata = pht('No packages match your query.');
|
||||
break;
|
||||
case 'owned':
|
||||
$data = queryfx_all(
|
||||
$package->establishConnection('r'),
|
||||
'SELECT p.* FROM %T p JOIN %T o ON p.id = o.packageID
|
||||
WHERE o.userPHID = %s GROUP BY p.id',
|
||||
$package->getTableName(),
|
||||
$owner->getTableName(),
|
||||
$user->getPHID());
|
||||
$packages = $package->loadAllFromArray($data);
|
||||
|
||||
$header = pht('Owned Packages');
|
||||
$nodata = pht('No owned packages');
|
||||
break;
|
||||
case 'projects':
|
||||
$projects = id(new PhabricatorProjectQuery())
|
||||
->setViewer($user)
|
||||
->withMemberPHIDs(array($user->getPHID()))
|
||||
->withStatus(PhabricatorProjectQuery::STATUS_ANY)
|
||||
->execute();
|
||||
$owner_phids = mpull($projects, 'getPHID');
|
||||
if ($owner_phids) {
|
||||
$data = queryfx_all(
|
||||
$package->establishConnection('r'),
|
||||
'SELECT p.* FROM %T p JOIN %T o ON p.id = o.packageID
|
||||
WHERE o.userPHID IN (%Ls) GROUP BY p.id',
|
||||
$package->getTableName(),
|
||||
$owner->getTableName(),
|
||||
$owner_phids);
|
||||
} else {
|
||||
$data = array();
|
||||
}
|
||||
$packages = $package->loadAllFromArray($data);
|
||||
|
||||
$header = pht('Project Packages');
|
||||
$nodata = pht('No owned packages');
|
||||
break;
|
||||
case 'all':
|
||||
$packages = $package->loadAll();
|
||||
|
||||
$header = pht('All Packages');
|
||||
$nodata = pht('There are no defined packages.');
|
||||
break;
|
||||
}
|
||||
|
||||
$content = $this->renderPackageTable(
|
||||
$packages,
|
||||
$header,
|
||||
$nodata);
|
||||
|
||||
$filter = new AphrontListFilterView();
|
||||
|
||||
$owner_phids = $request->getArr('owner');
|
||||
|
||||
$callsigns = array('' => pht('(Any Repository)'));
|
||||
$repositories = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer($user)
|
||||
->setOrder('callsign')
|
||||
->execute();
|
||||
foreach ($repositories as $repository) {
|
||||
$callsigns[$repository->getCallsign()] =
|
||||
$repository->getCallsign().': '.$repository->getName();
|
||||
}
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($user)
|
||||
->setAction('/owners/view/search/')
|
||||
->setMethod('GET')
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setName('name')
|
||||
->setLabel(pht('Name'))
|
||||
->setValue($request->getStr('name')))
|
||||
->appendControl(
|
||||
id(new AphrontFormTokenizerControl())
|
||||
->setDatasource(new PhabricatorProjectOrUserDatasource())
|
||||
->setLimit(1)
|
||||
->setName('owner')
|
||||
->setLabel(pht('Owner'))
|
||||
->setValue($owner_phids))
|
||||
->appendChild(
|
||||
id(new AphrontFormSelectControl())
|
||||
->setName('repository')
|
||||
->setLabel(pht('Repository'))
|
||||
->setOptions($callsigns)
|
||||
->setValue($request->getStr('repository')))
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setName('path')
|
||||
->setLabel(pht('Path'))
|
||||
->setValue($request->getStr('path')))
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue(pht('Search for Packages')));
|
||||
|
||||
$filter->appendChild($form);
|
||||
$title = pht('Package Index');
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb($header);
|
||||
|
||||
$nav = $this->buildSideNavView();
|
||||
$nav->appendChild($crumbs);
|
||||
$nav->appendChild($filter);
|
||||
$nav->appendChild($content);
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
$nav,
|
||||
array(
|
||||
'title' => pht('Package Index'),
|
||||
));
|
||||
return $this->delegateToController($controller);
|
||||
}
|
||||
|
||||
private function renderPackageTable(array $packages, $header, $nodata) {
|
||||
assert_instances_of($packages, 'PhabricatorOwnersPackage');
|
||||
public function buildSideNavView($for_app = false) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
if ($packages) {
|
||||
$package_ids = mpull($packages, 'getID');
|
||||
$nav = new AphrontSideNavFilterView();
|
||||
$nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
|
||||
|
||||
$owners = id(new PhabricatorOwnersOwner())->loadAllWhere(
|
||||
'packageID IN (%Ld)',
|
||||
$package_ids);
|
||||
|
||||
$paths = id(new PhabricatorOwnersPath())->loadAllWhere(
|
||||
'packageID in (%Ld)',
|
||||
$package_ids);
|
||||
|
||||
$phids = array();
|
||||
foreach ($owners as $owner) {
|
||||
$phids[$owner->getUserPHID()] = true;
|
||||
}
|
||||
$phids = array_keys($phids);
|
||||
$handles = $this->loadViewerHandles($phids);
|
||||
|
||||
$repository_phids = array();
|
||||
foreach ($paths as $path) {
|
||||
$repository_phids[$path->getRepositoryPHID()] = true;
|
||||
}
|
||||
|
||||
if ($repository_phids) {
|
||||
$repositories = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer($this->getRequest()->getUser())
|
||||
->withPHIDs(array_keys($repository_phids))
|
||||
->execute();
|
||||
} else {
|
||||
$repositories = array();
|
||||
}
|
||||
|
||||
$repositories = mpull($repositories, null, 'getPHID');
|
||||
$owners = mgroup($owners, 'getPackageID');
|
||||
$paths = mgroup($paths, 'getPackageID');
|
||||
} else {
|
||||
$handles = array();
|
||||
$repositories = array();
|
||||
$owners = array();
|
||||
$paths = array();
|
||||
if ($for_app) {
|
||||
$nav->addFilter('new/', pht('Create Package'));
|
||||
}
|
||||
|
||||
$rows = array();
|
||||
foreach ($packages as $package) {
|
||||
id(new PhabricatorOwnersPackageSearchEngine())
|
||||
->setViewer($viewer)
|
||||
->addNavigationItems($nav->getMenu());
|
||||
|
||||
$pkg_owners = idx($owners, $package->getID(), array());
|
||||
foreach ($pkg_owners as $key => $owner) {
|
||||
$pkg_owners[$key] = $handles[$owner->getUserPHID()]->renderLink();
|
||||
if ($owner->getUserPHID() == $package->getPrimaryOwnerPHID()) {
|
||||
$pkg_owners[$key] = phutil_tag('strong', array(), $pkg_owners[$key]);
|
||||
}
|
||||
}
|
||||
$pkg_owners = phutil_implode_html(phutil_tag('br'), $pkg_owners);
|
||||
$nav->selectFilter(null);
|
||||
|
||||
$pkg_paths = idx($paths, $package->getID(), array());
|
||||
foreach ($pkg_paths as $key => $path) {
|
||||
$repo = idx($repositories, $path->getRepositoryPHID());
|
||||
if ($repo) {
|
||||
$href = DiffusionRequest::generateDiffusionURI(
|
||||
array(
|
||||
'callsign' => $repo->getCallsign(),
|
||||
'branch' => $repo->getDefaultBranch(),
|
||||
'path' => $path->getPath(),
|
||||
'action' => 'browse',
|
||||
));
|
||||
$pkg_paths[$key] = hsprintf(
|
||||
'%s %s%s',
|
||||
($path->getExcluded() ? "\xE2\x80\x93" : '+'),
|
||||
phutil_tag('strong', array(), $repo->getName()),
|
||||
phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => (string)$href,
|
||||
),
|
||||
$path->getPath()));
|
||||
} else {
|
||||
$pkg_paths[$key] = $path->getPath();
|
||||
}
|
||||
}
|
||||
$pkg_paths = phutil_implode_html(phutil_tag('br'), $pkg_paths);
|
||||
|
||||
$rows[] = array(
|
||||
phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '/owners/package/'.$package->getID().'/',
|
||||
),
|
||||
$package->getName()),
|
||||
$pkg_owners,
|
||||
$pkg_paths,
|
||||
phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '/audit/?auditorPHIDs='.$package->getPHID(),
|
||||
),
|
||||
pht('Related Commits')),
|
||||
);
|
||||
}
|
||||
|
||||
$table = new AphrontTableView($rows);
|
||||
$table->setHeaders(
|
||||
array(
|
||||
pht('Name'),
|
||||
pht('Owners'),
|
||||
pht('Paths'),
|
||||
pht('Related Commits'),
|
||||
));
|
||||
$table->setColumnClasses(
|
||||
array(
|
||||
'pri',
|
||||
'',
|
||||
'wide wrap',
|
||||
'narrow',
|
||||
));
|
||||
|
||||
$panel = new PHUIObjectBoxView();
|
||||
$panel->setHeaderText($header);
|
||||
$panel->setTable($table);
|
||||
|
||||
return $panel;
|
||||
return $nav;
|
||||
}
|
||||
|
||||
protected function getExtraPackageViews(AphrontSideNavFilterView $view) {
|
||||
if ($this->view == 'search') {
|
||||
$view->addFilter('view/search', pht('Search Results'));
|
||||
}
|
||||
public function buildApplicationMenu() {
|
||||
return $this->buildSideNavView(true)->getMenu();
|
||||
}
|
||||
|
||||
protected function buildApplicationCrumbs() {
|
||||
$crumbs = parent::buildApplicationCrumbs();
|
||||
|
||||
$crumbs->addAction(
|
||||
id(new PHUIListItemView())
|
||||
->setName(pht('Create Package'))
|
||||
->setHref($this->getApplicationURI('new/'))
|
||||
->setIcon('fa-plus-square'));
|
||||
|
||||
return $crumbs;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorOwnersPathsController
|
||||
extends PhabricatorOwnersController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $request->getUser();
|
||||
|
||||
$package = id(new PhabricatorOwnersPackageQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($request->getURIData('id')))
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
// TODO: Support this capability.
|
||||
// PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->executeOne();
|
||||
if (!$package) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$paths = $request->getArr('path');
|
||||
$repos = $request->getArr('repo');
|
||||
$excludes = $request->getArr('exclude');
|
||||
|
||||
$path_refs = array();
|
||||
foreach ($paths as $key => $path) {
|
||||
if (!isset($repos[$key])) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'No repository PHID for path "%s"!',
|
||||
$key));
|
||||
}
|
||||
|
||||
if (!isset($excludes[$key])) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'No exclusion value for path "%s"!',
|
||||
$key));
|
||||
}
|
||||
|
||||
$path_refs[] = array(
|
||||
'repositoryPHID' => $repos[$key],
|
||||
'path' => $path,
|
||||
'excluded' => (int)$excludes[$key],
|
||||
);
|
||||
}
|
||||
|
||||
$type_paths = PhabricatorOwnersPackageTransaction::TYPE_PATHS;
|
||||
|
||||
$xactions = array();
|
||||
$xactions[] = id(new PhabricatorOwnersPackageTransaction())
|
||||
->setTransactionType($type_paths)
|
||||
->setNewValue($path_refs);
|
||||
|
||||
$editor = id(new PhabricatorOwnersPackageTransactionEditor())
|
||||
->setActor($viewer)
|
||||
->setContentSourceFromRequest($request)
|
||||
->setContinueOnNoEffect(true)
|
||||
->setContinueOnMissingFields(true);
|
||||
|
||||
$editor->applyTransactions($package, $xactions);
|
||||
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI('/owners/package/'.$package->getID().'/');
|
||||
} else {
|
||||
$paths = $package->loadPaths();
|
||||
$path_refs = mpull($paths, 'getRef');
|
||||
}
|
||||
|
||||
$repos = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer($viewer)
|
||||
->execute();
|
||||
|
||||
$default_paths = array();
|
||||
foreach ($repos as $repo) {
|
||||
$default_path = $repo->getDetail('default-owners-path');
|
||||
if ($default_path) {
|
||||
$default_paths[$repo->getPHID()] = $default_path;
|
||||
}
|
||||
}
|
||||
|
||||
$repos = mpull($repos, 'getCallsign', 'getPHID');
|
||||
asort($repos);
|
||||
|
||||
$template = new AphrontTypeaheadTemplateView();
|
||||
$template = $template->render();
|
||||
|
||||
Javelin::initBehavior(
|
||||
'owners-path-editor',
|
||||
array(
|
||||
'root' => 'path-editor',
|
||||
'table' => 'paths',
|
||||
'add_button' => 'addpath',
|
||||
'repositories' => $repos,
|
||||
'input_template' => $template,
|
||||
'pathRefs' => $path_refs,
|
||||
|
||||
'completeURI' => '/diffusion/services/path/complete/',
|
||||
'validateURI' => '/diffusion/services/path/validate/',
|
||||
|
||||
'repositoryDefaultPaths' => $default_paths,
|
||||
));
|
||||
|
||||
require_celerity_resource('owners-path-editor-css');
|
||||
|
||||
$cancel_uri = '/owners/package/'.$package->getID().'/';
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($viewer)
|
||||
->appendChild(
|
||||
id(new PHUIFormInsetView())
|
||||
->setTitle(pht('Paths'))
|
||||
->addDivAttributes(array('id' => 'path-editor'))
|
||||
->setRightButton(javelin_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '#',
|
||||
'class' => 'button green',
|
||||
'sigil' => 'addpath',
|
||||
'mustcapture' => true,
|
||||
),
|
||||
pht('Add New Path')))
|
||||
->setDescription(
|
||||
pht(
|
||||
'Specify the files and directories which comprise '.
|
||||
'this package.'))
|
||||
->setContent(javelin_tag(
|
||||
'table',
|
||||
array(
|
||||
'class' => 'owners-path-editor-table',
|
||||
'sigil' => 'paths',
|
||||
),
|
||||
'')))
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->addCancelButton($cancel_uri)
|
||||
->setValue(pht('Save Paths')));
|
||||
|
||||
$form_box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Edit Paths'))
|
||||
->setForm($form);
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb(
|
||||
$package->getName(),
|
||||
$this->getApplicationURI('package/'.$package->getID().'/'));
|
||||
$crumbs->addTextCrumb(pht('Edit Paths'));
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
array(
|
||||
$crumbs,
|
||||
$form_box,
|
||||
),
|
||||
array(
|
||||
'title' => array(
|
||||
$package->getName(),
|
||||
pht('Edit Paths'),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,198 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorOwnersPackageEditor extends PhabricatorEditor {
|
||||
|
||||
private $package;
|
||||
|
||||
public function setPackage(PhabricatorOwnersPackage $package) {
|
||||
$this->package = $package;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPackage() {
|
||||
return $this->package;
|
||||
}
|
||||
|
||||
public function save() {
|
||||
$actor = $this->getActor();
|
||||
$package = $this->getPackage();
|
||||
$package->attachActorPHID($actor->getPHID());
|
||||
|
||||
if ($package->getID()) {
|
||||
$is_new = false;
|
||||
} else {
|
||||
$is_new = true;
|
||||
}
|
||||
|
||||
$package->openTransaction();
|
||||
|
||||
$ret = $package->save();
|
||||
|
||||
$add_owners = array();
|
||||
$remove_owners = array();
|
||||
$all_owners = array();
|
||||
if ($package->getUnsavedOwners()) {
|
||||
$new_owners = array_fill_keys($package->getUnsavedOwners(), true);
|
||||
$cur_owners = array();
|
||||
foreach ($package->loadOwners() as $owner) {
|
||||
if (empty($new_owners[$owner->getUserPHID()])) {
|
||||
$remove_owners[$owner->getUserPHID()] = true;
|
||||
$owner->delete();
|
||||
continue;
|
||||
}
|
||||
$cur_owners[$owner->getUserPHID()] = true;
|
||||
}
|
||||
|
||||
$add_owners = array_diff_key($new_owners, $cur_owners);
|
||||
$all_owners = array_merge(
|
||||
array($package->getPrimaryOwnerPHID() => true),
|
||||
$new_owners,
|
||||
$remove_owners);
|
||||
foreach ($add_owners as $phid => $ignored) {
|
||||
$owner = new PhabricatorOwnersOwner();
|
||||
$owner->setPackageID($package->getID());
|
||||
$owner->setUserPHID($phid);
|
||||
$owner->save();
|
||||
}
|
||||
$package->attachUnsavedOwners(array());
|
||||
}
|
||||
|
||||
$add_paths = array();
|
||||
$remove_paths = array();
|
||||
$touched_repos = array();
|
||||
if ($package->getUnsavedPaths()) {
|
||||
$new_paths = igroup(
|
||||
$package->getUnsavedPaths(),
|
||||
'repositoryPHID',
|
||||
'path');
|
||||
$cur_paths = $package->loadPaths();
|
||||
foreach ($cur_paths as $key => $path) {
|
||||
$repository_phid = $path->getRepositoryPHID();
|
||||
$new_path = head(idx(
|
||||
idx($new_paths, $repository_phid, array()),
|
||||
$path->getPath(),
|
||||
array()));
|
||||
$excluded = $path->getExcluded();
|
||||
if ($new_path === false ||
|
||||
idx($new_path, 'excluded') != $excluded) {
|
||||
$touched_repos[$repository_phid] = true;
|
||||
$remove_paths[$repository_phid][$path->getPath()] = $excluded;
|
||||
$path->delete();
|
||||
unset($cur_paths[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$cur_paths = mgroup($cur_paths, 'getRepositoryPHID', 'getPath');
|
||||
$repositories = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer($actor)
|
||||
->withPHIDs(array_keys($cur_paths))
|
||||
->execute();
|
||||
$repositories = mpull($repositories, null, 'getPHID');
|
||||
foreach ($new_paths as $repository_phid => $paths) {
|
||||
$repository = idx($repositories, $repository_phid);
|
||||
if (!$repository) {
|
||||
continue;
|
||||
}
|
||||
foreach ($paths as $path => $dicts) {
|
||||
$path = ltrim($path, '/');
|
||||
// build query to validate path
|
||||
$drequest = DiffusionRequest::newFromDictionary(
|
||||
array(
|
||||
'user' => $actor,
|
||||
'repository' => $repository,
|
||||
'path' => $path,
|
||||
));
|
||||
$results = DiffusionBrowseResultSet::newFromConduit(
|
||||
DiffusionQuery::callConduitWithDiffusionRequest(
|
||||
$actor,
|
||||
$drequest,
|
||||
'diffusion.browsequery',
|
||||
array(
|
||||
'commit' => $drequest->getCommit(),
|
||||
'path' => $path,
|
||||
'needValidityOnly' => true,
|
||||
)));
|
||||
$valid = $results->isValidResults();
|
||||
$is_directory = true;
|
||||
if (!$valid) {
|
||||
switch ($results->getReasonForEmptyResultSet()) {
|
||||
case DiffusionBrowseResultSet::REASON_IS_FILE:
|
||||
$valid = true;
|
||||
$is_directory = false;
|
||||
break;
|
||||
case DiffusionBrowseResultSet::REASON_IS_EMPTY:
|
||||
$valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($is_directory && substr($path, -1) != '/') {
|
||||
$path .= '/';
|
||||
}
|
||||
if (substr($path, 0, 1) != '/') {
|
||||
$path = '/'.$path;
|
||||
}
|
||||
if (empty($cur_paths[$repository_phid][$path]) && $valid) {
|
||||
$touched_repos[$repository_phid] = true;
|
||||
$excluded = idx(reset($dicts), 'excluded', 0);
|
||||
$add_paths[$repository_phid][$path] = $excluded;
|
||||
$obj = new PhabricatorOwnersPath();
|
||||
$obj->setPackageID($package->getID());
|
||||
$obj->setRepositoryPHID($repository_phid);
|
||||
$obj->setPath($path);
|
||||
$obj->setExcluded($excluded);
|
||||
$obj->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
$package->attachUnsavedPaths(array());
|
||||
}
|
||||
|
||||
$package->saveTransaction();
|
||||
|
||||
if ($is_new) {
|
||||
$mail = new PackageCreateMail($package);
|
||||
} else {
|
||||
$mail = new PackageModifyMail(
|
||||
$package,
|
||||
array_keys($add_owners),
|
||||
array_keys($remove_owners),
|
||||
array_keys($all_owners),
|
||||
array_keys($touched_repos),
|
||||
$add_paths,
|
||||
$remove_paths);
|
||||
}
|
||||
$mail->setActor($actor);
|
||||
$mail->send();
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function delete() {
|
||||
$actor = $this->getActor();
|
||||
$package = $this->getPackage();
|
||||
$package->attachActorPHID($actor->getPHID());
|
||||
|
||||
$mails = id(new PackageDeleteMail($package))
|
||||
->setActor($actor)
|
||||
->prepareMails();
|
||||
|
||||
$package->openTransaction();
|
||||
|
||||
foreach ($package->loadOwners() as $owner) {
|
||||
$owner->delete();
|
||||
}
|
||||
foreach ($package->loadPaths() as $path) {
|
||||
$path->delete();
|
||||
}
|
||||
$ret = $package->delete();
|
||||
|
||||
$package->saveTransaction();
|
||||
|
||||
foreach ($mails as $mail) {
|
||||
$mail->saveAndSend();
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,290 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorOwnersPackageTransactionEditor
|
||||
extends PhabricatorApplicationTransactionEditor {
|
||||
|
||||
public function getEditorApplicationClass() {
|
||||
return 'PhabricatorOwnersApplication';
|
||||
}
|
||||
|
||||
public function getEditorObjectsDescription() {
|
||||
return pht('Owners Packages');
|
||||
}
|
||||
|
||||
public function getTransactionTypes() {
|
||||
$types = parent::getTransactionTypes();
|
||||
|
||||
$types[] = PhabricatorOwnersPackageTransaction::TYPE_NAME;
|
||||
$types[] = PhabricatorOwnersPackageTransaction::TYPE_PRIMARY;
|
||||
$types[] = PhabricatorOwnersPackageTransaction::TYPE_OWNERS;
|
||||
$types[] = PhabricatorOwnersPackageTransaction::TYPE_AUDITING;
|
||||
$types[] = PhabricatorOwnersPackageTransaction::TYPE_DESCRIPTION;
|
||||
$types[] = PhabricatorOwnersPackageTransaction::TYPE_PATHS;
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
protected function getCustomTransactionOldValue(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorOwnersPackageTransaction::TYPE_NAME:
|
||||
return $object->getName();
|
||||
case PhabricatorOwnersPackageTransaction::TYPE_PRIMARY:
|
||||
return $object->getPrimaryOwnerPHID();
|
||||
case PhabricatorOwnersPackageTransaction::TYPE_OWNERS:
|
||||
// TODO: needOwners() this on the Query.
|
||||
$phids = mpull($object->loadOwners(), 'getUserPHID');
|
||||
$phids = array_values($phids);
|
||||
return $phids;
|
||||
case PhabricatorOwnersPackageTransaction::TYPE_AUDITING:
|
||||
return (int)$object->getAuditingEnabled();
|
||||
case PhabricatorOwnersPackageTransaction::TYPE_DESCRIPTION:
|
||||
return $object->getDescription();
|
||||
case PhabricatorOwnersPackageTransaction::TYPE_PATHS:
|
||||
// TODO: needPaths() this on the query
|
||||
$paths = $object->loadPaths();
|
||||
return mpull($paths, 'getRef');
|
||||
}
|
||||
}
|
||||
|
||||
protected function getCustomTransactionNewValue(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorOwnersPackageTransaction::TYPE_NAME:
|
||||
case PhabricatorOwnersPackageTransaction::TYPE_PRIMARY:
|
||||
case PhabricatorOwnersPackageTransaction::TYPE_DESCRIPTION:
|
||||
case PhabricatorOwnersPackageTransaction::TYPE_PATHS:
|
||||
return $xaction->getNewValue();
|
||||
case PhabricatorOwnersPackageTransaction::TYPE_AUDITING:
|
||||
return (int)$xaction->getNewValue();
|
||||
case PhabricatorOwnersPackageTransaction::TYPE_OWNERS:
|
||||
$phids = $xaction->getNewValue();
|
||||
$phids = array_unique($phids);
|
||||
$phids = array_values($phids);
|
||||
return $phids;
|
||||
}
|
||||
}
|
||||
|
||||
protected function transactionHasEffect(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorOwnersPackageTransaction::TYPE_PATHS:
|
||||
$old = $xaction->getOldValue();
|
||||
$new = $xaction->getNewValue();
|
||||
|
||||
$diffs = PhabricatorOwnersPath::getTransactionValueChanges($old, $new);
|
||||
list($rem, $add) = $diffs;
|
||||
|
||||
return ($rem || $add);
|
||||
}
|
||||
|
||||
return parent::transactionHasEffect($object, $xaction);
|
||||
}
|
||||
|
||||
protected function applyCustomInternalTransaction(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorOwnersPackageTransaction::TYPE_NAME:
|
||||
$object->setName($xaction->getNewValue());
|
||||
return;
|
||||
case PhabricatorOwnersPackageTransaction::TYPE_PRIMARY:
|
||||
$object->setPrimaryOwnerPHID($xaction->getNewValue());
|
||||
return;
|
||||
case PhabricatorOwnersPackageTransaction::TYPE_DESCRIPTION:
|
||||
$object->setDescription($xaction->getNewValue());
|
||||
return;
|
||||
case PhabricatorOwnersPackageTransaction::TYPE_AUDITING:
|
||||
$object->setAuditingEnabled($xaction->getNewValue());
|
||||
return;
|
||||
case PhabricatorOwnersPackageTransaction::TYPE_OWNERS:
|
||||
case PhabricatorOwnersPackageTransaction::TYPE_PATHS:
|
||||
return;
|
||||
}
|
||||
|
||||
return parent::applyCustomInternalTransaction($object, $xaction);
|
||||
}
|
||||
|
||||
protected function applyCustomExternalTransaction(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorOwnersPackageTransaction::TYPE_NAME:
|
||||
case PhabricatorOwnersPackageTransaction::TYPE_PRIMARY:
|
||||
case PhabricatorOwnersPackageTransaction::TYPE_DESCRIPTION:
|
||||
case PhabricatorOwnersPackageTransaction::TYPE_AUDITING:
|
||||
return;
|
||||
case PhabricatorOwnersPackageTransaction::TYPE_OWNERS:
|
||||
$old = $xaction->getOldValue();
|
||||
$new = $xaction->getNewValue();
|
||||
|
||||
// TODO: needOwners this
|
||||
$owners = $object->loadOwners();
|
||||
$owners = mpull($owners, null, 'getUserPHID');
|
||||
|
||||
$rem = array_diff($old, $new);
|
||||
foreach ($rem as $phid) {
|
||||
if (isset($owners[$phid])) {
|
||||
$owners[$phid]->delete();
|
||||
unset($owners[$phid]);
|
||||
}
|
||||
}
|
||||
|
||||
$add = array_diff($new, $old);
|
||||
foreach ($add as $phid) {
|
||||
$owners[$phid] = id(new PhabricatorOwnersOwner())
|
||||
->setPackageID($object->getID())
|
||||
->setUserPHID($phid)
|
||||
->save();
|
||||
}
|
||||
|
||||
// TODO: Attach owners here
|
||||
return;
|
||||
case PhabricatorOwnersPackageTransaction::TYPE_PATHS:
|
||||
$old = $xaction->getOldValue();
|
||||
$new = $xaction->getNewValue();
|
||||
|
||||
// TODO: needPaths this
|
||||
$paths = $object->loadPaths();
|
||||
|
||||
$diffs = PhabricatorOwnersPath::getTransactionValueChanges($old, $new);
|
||||
list($rem, $add) = $diffs;
|
||||
|
||||
$set = PhabricatorOwnersPath::getSetFromTransactionValue($rem);
|
||||
foreach ($paths as $path) {
|
||||
$ref = $path->getRef();
|
||||
if (PhabricatorOwnersPath::isRefInSet($ref, $set)) {
|
||||
$path->delete();
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($add as $ref) {
|
||||
$path = PhabricatorOwnersPath::newFromRef($ref)
|
||||
->setPackageID($object->getID())
|
||||
->save();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
return parent::applyCustomExternalTransaction($object, $xaction);
|
||||
}
|
||||
|
||||
protected function validateTransaction(
|
||||
PhabricatorLiskDAO $object,
|
||||
$type,
|
||||
array $xactions) {
|
||||
|
||||
$errors = parent::validateTransaction($object, $type, $xactions);
|
||||
|
||||
switch ($type) {
|
||||
case PhabricatorOwnersPackageTransaction::TYPE_NAME:
|
||||
$missing = $this->validateIsEmptyTextField(
|
||||
$object->getName(),
|
||||
$xactions);
|
||||
|
||||
if ($missing) {
|
||||
$error = new PhabricatorApplicationTransactionValidationError(
|
||||
$type,
|
||||
pht('Required'),
|
||||
pht('Package name is required.'),
|
||||
nonempty(last($xactions), null));
|
||||
|
||||
$error->setIsMissingFieldError(true);
|
||||
$errors[] = $error;
|
||||
}
|
||||
break;
|
||||
case PhabricatorOwnersPackageTransaction::TYPE_PRIMARY:
|
||||
$missing = $this->validateIsEmptyTextField(
|
||||
$object->getPrimaryOwnerPHID(),
|
||||
$xactions);
|
||||
|
||||
if ($missing) {
|
||||
$error = new PhabricatorApplicationTransactionValidationError(
|
||||
$type,
|
||||
pht('Required'),
|
||||
pht('Packages must have a primary owner.'),
|
||||
nonempty(last($xactions), null));
|
||||
|
||||
$error->setIsMissingFieldError(true);
|
||||
$errors[] = $error;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
protected function extractFilePHIDsFromCustomTransaction(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorOwnersPackageTransaction::TYPE_DESCRIPTION:
|
||||
return array($xaction->getNewValue());
|
||||
}
|
||||
|
||||
return parent::extractFilePHIDsFromCustomTransaction($object, $xaction);
|
||||
}
|
||||
|
||||
protected function shouldSendMail(
|
||||
PhabricatorLiskDAO $object,
|
||||
array $xactions) {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function getMailSubjectPrefix() {
|
||||
return PhabricatorEnv::getEnvConfig('metamta.package.subject-prefix');
|
||||
}
|
||||
|
||||
protected function getMailTo(PhabricatorLiskDAO $object) {
|
||||
return array(
|
||||
$object->getPrimaryOwnerPHID(),
|
||||
$this->requireActor()->getPHID(),
|
||||
);
|
||||
}
|
||||
|
||||
protected function getMailCC(PhabricatorLiskDAO $object) {
|
||||
// TODO: needOwners() this
|
||||
return mpull($object->loadOwners(), 'getUserPHID');
|
||||
}
|
||||
|
||||
protected function buildReplyHandler(PhabricatorLiskDAO $object) {
|
||||
return id(new OwnersPackageReplyHandler())
|
||||
->setMailReceiver($object);
|
||||
}
|
||||
|
||||
protected function buildMailTemplate(PhabricatorLiskDAO $object) {
|
||||
$id = $object->getID();
|
||||
$name = $object->getName();
|
||||
|
||||
return id(new PhabricatorMetaMTAMail())
|
||||
->setSubject($name)
|
||||
->addHeader('Thread-Topic', $object->getPHID());
|
||||
}
|
||||
|
||||
protected function buildMailBody(
|
||||
PhabricatorLiskDAO $object,
|
||||
array $xactions) {
|
||||
|
||||
$body = parent::buildMailBody($object, $xactions);
|
||||
|
||||
$detail_uri = PhabricatorEnv::getProductionURI(
|
||||
'/owners/package/'.$object->getID().'/');
|
||||
|
||||
$body->addLinkSection(
|
||||
pht('PACKAGE DETAIL'),
|
||||
$detail_uri);
|
||||
|
||||
return $body;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class PackageCreateMail extends PackageMail {
|
||||
|
||||
protected function isNewThread() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function getVerb() {
|
||||
return pht('Created');
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class PackageDeleteMail extends PackageMail {
|
||||
|
||||
protected function getVerb() {
|
||||
return pht('Deleted');
|
||||
}
|
||||
|
||||
protected function isNewThread() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,212 +0,0 @@
|
|||
<?php
|
||||
|
||||
abstract class PackageMail extends PhabricatorMail {
|
||||
|
||||
protected $package;
|
||||
protected $handles;
|
||||
protected $owners;
|
||||
protected $paths;
|
||||
protected $mailTo;
|
||||
|
||||
public function __construct(PhabricatorOwnersPackage $package) {
|
||||
$this->package = $package;
|
||||
}
|
||||
|
||||
abstract protected function getVerb();
|
||||
|
||||
abstract protected function isNewThread();
|
||||
|
||||
final protected function getPackage() {
|
||||
return $this->package;
|
||||
}
|
||||
|
||||
final protected function getHandles() {
|
||||
return $this->handles;
|
||||
}
|
||||
|
||||
final protected function getOwners() {
|
||||
return $this->owners;
|
||||
}
|
||||
|
||||
final protected function getPaths() {
|
||||
return $this->paths;
|
||||
}
|
||||
|
||||
final protected function getMailTo() {
|
||||
return $this->mailTo;
|
||||
}
|
||||
|
||||
final protected function renderPackageTitle() {
|
||||
return $this->getPackage()->getName();
|
||||
}
|
||||
|
||||
final protected function renderRepoSubSection($repository_phid, $paths) {
|
||||
$handles = $this->getHandles();
|
||||
$section = array();
|
||||
$section[] = ' '.
|
||||
pht('In repository %s', $handles[$repository_phid]->getName()).
|
||||
' - '.PhabricatorEnv::getProductionURI($handles[$repository_phid]
|
||||
->getURI());
|
||||
foreach ($paths as $path => $excluded) {
|
||||
$section[] = ' '.
|
||||
($excluded ? pht('Excluded') : pht('Included')).' '.$path;
|
||||
}
|
||||
|
||||
return implode("\n", $section);
|
||||
}
|
||||
|
||||
protected function needSend() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function loadData() {
|
||||
$package = $this->getPackage();
|
||||
$owners = $package->loadOwners();
|
||||
$this->owners = $owners;
|
||||
|
||||
$owner_phids = mpull($owners, 'getUserPHID');
|
||||
$primary_owner_phid = $package->getPrimaryOwnerPHID();
|
||||
$mail_to = $owner_phids;
|
||||
if (!in_array($primary_owner_phid, $owner_phids)) {
|
||||
$mail_to[] = $primary_owner_phid;
|
||||
}
|
||||
$this->mailTo = $mail_to;
|
||||
|
||||
$this->paths = array();
|
||||
$repository_paths = mgroup($package->loadPaths(), 'getRepositoryPHID');
|
||||
foreach ($repository_paths as $repository_phid => $paths) {
|
||||
$this->paths[$repository_phid] = mpull($paths, 'getExcluded', 'getPath');
|
||||
}
|
||||
|
||||
$phids = array_merge(
|
||||
$this->mailTo,
|
||||
array($package->getActorPHID()),
|
||||
array_keys($this->paths));
|
||||
$this->handles = id(new PhabricatorHandleQuery())
|
||||
->setViewer($this->getActor())
|
||||
->withPHIDs($phids)
|
||||
->execute();
|
||||
}
|
||||
|
||||
final protected function renderSummarySection() {
|
||||
$package = $this->getPackage();
|
||||
$handles = $this->getHandles();
|
||||
$section = array();
|
||||
$section[] = $handles[$package->getActorPHID()]->getName().' '.
|
||||
strtolower($this->getVerb()).' '.$this->renderPackageTitle().'.';
|
||||
$section[] = '';
|
||||
|
||||
$section[] = pht('PACKAGE DETAIL');
|
||||
$section[] = ' '.PhabricatorEnv::getProductionURI(
|
||||
'/owners/package/'.$package->getID().'/');
|
||||
|
||||
return implode("\n", $section);
|
||||
}
|
||||
|
||||
protected function renderDescriptionSection() {
|
||||
return pht('PACKAGE DESCRIPTION')."\n ".
|
||||
$this->getPackage()->getDescription();
|
||||
}
|
||||
|
||||
protected function renderPrimaryOwnerSection() {
|
||||
$handles = $this->getHandles();
|
||||
return pht('PRIMARY OWNER')."\n ".
|
||||
$handles[$this->getPackage()->getPrimaryOwnerPHID()]->getName();
|
||||
}
|
||||
|
||||
protected function renderOwnersSection() {
|
||||
$handles = $this->getHandles();
|
||||
$owners = $this->getOwners();
|
||||
if (!$owners) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$owners = mpull($owners, 'getUserPHID');
|
||||
$owners = array_select_keys($handles, $owners);
|
||||
$owners = mpull($owners, 'getName');
|
||||
return pht('OWNERS')."\n ".implode(', ', $owners);
|
||||
}
|
||||
|
||||
protected function renderAuditingEnabledSection() {
|
||||
return pht('AUDITING ENABLED STATUS')."\n ".
|
||||
($this->getPackage()->getAuditingEnabled()
|
||||
? pht('Enabled')
|
||||
: pht('Disabled'));
|
||||
}
|
||||
|
||||
protected function renderPathsSection() {
|
||||
$section = array();
|
||||
$section[] = pht('PATHS');
|
||||
foreach ($this->paths as $repository_phid => $paths) {
|
||||
$section[] = $this->renderRepoSubSection($repository_phid, $paths);
|
||||
}
|
||||
|
||||
return implode("\n", $section);
|
||||
}
|
||||
|
||||
final protected function renderBody() {
|
||||
$body = array();
|
||||
$body[] = $this->renderSummarySection();
|
||||
$body[] = $this->renderDescriptionSection();
|
||||
$body[] = $this->renderPrimaryOwnerSection();
|
||||
$body[] = $this->renderOwnersSection();
|
||||
$body[] = $this->renderAuditingEnabledSection();
|
||||
$body[] = $this->renderPathsSection();
|
||||
$body = array_filter($body);
|
||||
return implode("\n\n", $body)."\n";
|
||||
}
|
||||
|
||||
final public function send() {
|
||||
$mails = $this->prepareMails();
|
||||
|
||||
foreach ($mails as $mail) {
|
||||
$mail->saveAndSend();
|
||||
}
|
||||
}
|
||||
|
||||
final public function prepareMails() {
|
||||
if (!$this->needSend()) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$this->loadData();
|
||||
|
||||
$package = $this->getPackage();
|
||||
$prefix = PhabricatorEnv::getEnvConfig('metamta.package.subject-prefix');
|
||||
$verb = $this->getVerb();
|
||||
$threading = $this->getMailThreading();
|
||||
list($thread_id, $thread_topic) = $threading;
|
||||
|
||||
$template = id(new PhabricatorMetaMTAMail())
|
||||
->setSubject($this->renderPackageTitle())
|
||||
->setSubjectPrefix($prefix)
|
||||
->setVarySubjectPrefix("[{$verb}]")
|
||||
->setFrom($package->getActorPHID())
|
||||
->setThreadID($thread_id, $this->isNewThread())
|
||||
->addHeader('Thread-Topic', $thread_topic)
|
||||
->setRelatedPHID($package->getPHID())
|
||||
->setIsBulk(true)
|
||||
->setBody($this->renderBody());
|
||||
|
||||
$reply_handler = $this->newReplyHandler();
|
||||
$mails = $reply_handler->multiplexMail(
|
||||
$template,
|
||||
array_select_keys($this->getHandles(), $this->getMailTo()),
|
||||
array());
|
||||
return $mails;
|
||||
}
|
||||
|
||||
private function getMailThreading() {
|
||||
return array(
|
||||
'package-'.$this->getPackage()->getPHID(),
|
||||
'Package '.$this->getPackage()->getOriginalName(),
|
||||
);
|
||||
}
|
||||
|
||||
private function newReplyHandler() {
|
||||
$reply_handler = new OwnersPackageReplyHandler();
|
||||
$reply_handler->setMailReceiver($this->getPackage());
|
||||
return $reply_handler;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,160 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class PackageModifyMail extends PackageMail {
|
||||
|
||||
protected $addOwners;
|
||||
protected $removeOwners;
|
||||
protected $allOwners;
|
||||
protected $touchedRepos;
|
||||
protected $addPaths;
|
||||
protected $removePaths;
|
||||
|
||||
public function __construct(
|
||||
PhabricatorOwnersPackage $package,
|
||||
$add_owners,
|
||||
$remove_owners,
|
||||
$all_owners,
|
||||
$touched_repos,
|
||||
$add_paths,
|
||||
$remove_paths) {
|
||||
|
||||
$this->package = $package;
|
||||
|
||||
$this->addOwners = $add_owners;
|
||||
$this->removeOwners = $remove_owners;
|
||||
$this->allOwners = $all_owners;
|
||||
$this->touchedRepos = $touched_repos;
|
||||
$this->addPaths = $add_paths;
|
||||
$this->removePaths = $remove_paths;
|
||||
}
|
||||
|
||||
protected function getVerb() {
|
||||
return pht('Modified');
|
||||
}
|
||||
|
||||
protected function isNewThread() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function needSend() {
|
||||
$package = $this->getPackage();
|
||||
if ($package->getOldPrimaryOwnerPHID() !== $package->getPrimaryOwnerPHID()
|
||||
|| $package->getOldAuditingEnabled() != $package->getAuditingEnabled()
|
||||
|| $this->addOwners
|
||||
|| $this->removeOwners
|
||||
|| $this->addPaths
|
||||
|| $this->removePaths) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected function loadData() {
|
||||
$this->mailTo = $this->allOwners;
|
||||
|
||||
$phids = array_merge(
|
||||
$this->allOwners,
|
||||
$this->touchedRepos,
|
||||
array(
|
||||
$this->getPackage()->getActorPHID(),
|
||||
));
|
||||
$this->handles = id(new PhabricatorHandleQuery())
|
||||
->setViewer($this->getActor())
|
||||
->withPHIDs($phids)
|
||||
->execute();
|
||||
}
|
||||
|
||||
protected function renderDescriptionSection() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function renderPrimaryOwnerSection() {
|
||||
$package = $this->getPackage();
|
||||
$handles = $this->getHandles();
|
||||
|
||||
$old_primary_owner_phid = $package->getOldPrimaryOwnerPHID();
|
||||
$primary_owner_phid = $package->getPrimaryOwnerPHID();
|
||||
if ($old_primary_owner_phid == $primary_owner_phid) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$section = array();
|
||||
$section[] = pht('PRIMARY OWNER CHANGE');
|
||||
$section[] = ' '.pht('Old owner:').' '.
|
||||
$handles[$old_primary_owner_phid]->getName();
|
||||
$section[] = ' '.pht('New owner:').' '.
|
||||
$handles[$primary_owner_phid]->getName();
|
||||
|
||||
return implode("\n", $section);
|
||||
}
|
||||
|
||||
protected function renderOwnersSection() {
|
||||
$section = array();
|
||||
$add_owners = $this->addOwners;
|
||||
$remove_owners = $this->removeOwners;
|
||||
$handles = $this->getHandles();
|
||||
|
||||
if ($add_owners) {
|
||||
$add_owners = array_select_keys($handles, $add_owners);
|
||||
$add_owners = mpull($add_owners, 'getName');
|
||||
$section[] = pht('ADDED OWNERS');
|
||||
$section[] = ' '.implode(', ', $add_owners);
|
||||
}
|
||||
|
||||
if ($remove_owners) {
|
||||
if ($add_owners) {
|
||||
$section[] = '';
|
||||
}
|
||||
$remove_owners = array_select_keys($handles, $remove_owners);
|
||||
$remove_owners = mpull($remove_owners, 'getName');
|
||||
$section[] = pht('REMOVED OWNERS');
|
||||
$section[] = ' '.implode(', ', $remove_owners);
|
||||
}
|
||||
|
||||
if ($section) {
|
||||
return implode("\n", $section);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected function renderAuditingEnabledSection() {
|
||||
$package = $this->getPackage();
|
||||
$old_auditing_enabled = $package->getOldAuditingEnabled();
|
||||
$auditing_enabled = $package->getAuditingEnabled();
|
||||
if ($old_auditing_enabled == $auditing_enabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$section = array();
|
||||
$section[] = pht('AUDITING ENABLED STATUS CHANGE');
|
||||
$section[] = ' '.pht('Old value:').' '.
|
||||
($old_auditing_enabled ? pht('Enabled') : pht('Disabled'));
|
||||
$section[] = ' '.pht('New value:').' '.
|
||||
($auditing_enabled ? pht('Enabled') : pht('Disabled'));
|
||||
return implode("\n", $section);
|
||||
}
|
||||
|
||||
protected function renderPathsSection() {
|
||||
$section = array();
|
||||
if ($this->addPaths) {
|
||||
$section[] = pht('ADDED PATHS');
|
||||
foreach ($this->addPaths as $repository_phid => $paths) {
|
||||
$section[] = $this->renderRepoSubSection($repository_phid, $paths);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->removePaths) {
|
||||
if ($this->addPaths) {
|
||||
$section[] = '';
|
||||
}
|
||||
$section[] = pht('REMOVED PATHS');
|
||||
foreach ($this->removePaths as $repository_phid => $paths) {
|
||||
$section[] = $this->renderRepoSubSection($repository_phid, $paths);
|
||||
}
|
||||
}
|
||||
return implode("\n", $section);
|
||||
}
|
||||
|
||||
}
|
|
@ -3,8 +3,10 @@
|
|||
final class PhabricatorOwnersPackageQuery
|
||||
extends PhabricatorCursorPagedPolicyAwareQuery {
|
||||
|
||||
private $ids;
|
||||
private $phids;
|
||||
private $ownerPHIDs;
|
||||
private $repositoryPHIDs;
|
||||
|
||||
/**
|
||||
* Owners are direct owners, and members of owning projects.
|
||||
|
@ -19,6 +21,16 @@ final class PhabricatorOwnersPackageQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function withIDs(array $ids) {
|
||||
$this->ids = $ids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withRepositoryPHIDs(array $phids) {
|
||||
$this->repositoryPHIDs = $phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function loadPage() {
|
||||
$table = new PhabricatorOwnersPackage();
|
||||
$conn_r = $table->establishConnection('r');
|
||||
|
@ -38,27 +50,48 @@ final class PhabricatorOwnersPackageQuery
|
|||
protected function buildJoinClause(AphrontDatabaseConnection $conn_r) {
|
||||
$joins = array();
|
||||
|
||||
if ($this->ownerPHIDs) {
|
||||
if ($this->ownerPHIDs !== null) {
|
||||
$joins[] = qsprintf(
|
||||
$conn_r,
|
||||
'JOIN %T o ON o.packageID = p.id',
|
||||
id(new PhabricatorOwnersOwner())->getTableName());
|
||||
}
|
||||
|
||||
if ($this->repositoryPHIDs !== null) {
|
||||
$joins[] = qsprintf(
|
||||
$conn_r,
|
||||
'JOIN %T rpath ON rpath.packageID = p.id',
|
||||
id(new PhabricatorOwnersPath())->getTableName());
|
||||
}
|
||||
|
||||
return implode(' ', $joins);
|
||||
}
|
||||
|
||||
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
|
||||
$where = array();
|
||||
|
||||
if ($this->phids) {
|
||||
if ($this->phids !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'p.phid IN (%Ls)',
|
||||
$this->phids);
|
||||
}
|
||||
|
||||
if ($this->ownerPHIDs) {
|
||||
if ($this->ids !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'p.id IN (%Ld)',
|
||||
$this->ids);
|
||||
}
|
||||
|
||||
if ($this->repositoryPHIDs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'rpath.repositoryPHID IN (%Ls)',
|
||||
$this->repositoryPHIDs);
|
||||
}
|
||||
|
||||
if ($this->ownerPHIDs !== null) {
|
||||
$base_phids = $this->ownerPHIDs;
|
||||
|
||||
$query = new PhabricatorProjectQuery();
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorOwnersPackageSearchEngine
|
||||
extends PhabricatorApplicationSearchEngine {
|
||||
|
||||
public function getResultTypeDescription() {
|
||||
return pht('Owners Packages');
|
||||
}
|
||||
|
||||
public function getApplicationClassName() {
|
||||
return 'PhabricatorOwnersApplication';
|
||||
}
|
||||
|
||||
public function buildSavedQueryFromRequest(AphrontRequest $request) {
|
||||
$saved = new PhabricatorSavedQuery();
|
||||
|
||||
$saved->setParameter(
|
||||
'ownerPHIDs',
|
||||
$this->readUsersFromRequest(
|
||||
$request,
|
||||
'owners',
|
||||
array(
|
||||
PhabricatorProjectProjectPHIDType::TYPECONST,
|
||||
)));
|
||||
|
||||
$saved->setParameter(
|
||||
'repositoryPHIDs',
|
||||
$this->readPHIDsFromRequest(
|
||||
$request,
|
||||
'repositories',
|
||||
array(
|
||||
PhabricatorRepositoryRepositoryPHIDType::TYPECONST,
|
||||
)));
|
||||
|
||||
return $saved;
|
||||
}
|
||||
|
||||
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
|
||||
$query = id(new PhabricatorOwnersPackageQuery());
|
||||
|
||||
$owner_phids = $saved->getParameter('ownerPHIDs', array());
|
||||
if ($owner_phids) {
|
||||
$query->withOwnerPHIDs($owner_phids);
|
||||
}
|
||||
|
||||
$repository_phids = $saved->getParameter('repositoryPHIDs', array());
|
||||
if ($repository_phids) {
|
||||
$query->withRepositoryPHIDs($repository_phids);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
public function buildSearchForm(
|
||||
AphrontFormView $form,
|
||||
PhabricatorSavedQuery $saved) {
|
||||
|
||||
$owner_phids = $saved->getParameter('ownerPHIDs', array());
|
||||
$repository_phids = $saved->getParameter('repositoryPHIDs', array());
|
||||
|
||||
$form
|
||||
->appendControl(
|
||||
id(new AphrontFormTokenizerControl())
|
||||
->setDatasource(new PhabricatorProjectOrUserDatasource())
|
||||
->setName('owners')
|
||||
->setLabel(pht('Owners'))
|
||||
->setValue($owner_phids))
|
||||
->appendControl(
|
||||
id(new AphrontFormTokenizerControl())
|
||||
->setDatasource(new DiffusionRepositoryDatasource())
|
||||
->setName('repositories')
|
||||
->setLabel(pht('Repositories'))
|
||||
->setValue($repository_phids));
|
||||
}
|
||||
|
||||
protected function getURI($path) {
|
||||
return '/owners/'.$path;
|
||||
}
|
||||
|
||||
protected function getBuiltinQueryNames() {
|
||||
$names = array();
|
||||
|
||||
if ($this->requireViewer()->isLoggedIn()) {
|
||||
$names['owned'] = pht('Owned');
|
||||
}
|
||||
|
||||
$names += array(
|
||||
'all' => pht('All Packages'),
|
||||
);
|
||||
|
||||
return $names;
|
||||
}
|
||||
|
||||
public function buildSavedQueryFromBuiltin($query_key) {
|
||||
$query = $this->newSavedQuery();
|
||||
$query->setQueryKey($query_key);
|
||||
|
||||
switch ($query_key) {
|
||||
case 'all':
|
||||
return $query;
|
||||
case 'owned':
|
||||
return $query->setParameter(
|
||||
'ownerPHIDs',
|
||||
array($this->requireViewer()->getPHID()));
|
||||
}
|
||||
|
||||
return parent::buildSavedQueryFromBuiltin($query_key);
|
||||
}
|
||||
|
||||
protected function renderResultList(
|
||||
array $packages,
|
||||
PhabricatorSavedQuery $query,
|
||||
array $handles) {
|
||||
assert_instances_of($packages, 'PhabricatorOwnersPackage');
|
||||
|
||||
$viewer = $this->requireViewer();
|
||||
|
||||
$list = id(new PHUIObjectItemListView())
|
||||
->setUser($viewer);
|
||||
foreach ($packages as $package) {
|
||||
$id = $package->getID();
|
||||
|
||||
$item = id(new PHUIObjectItemView())
|
||||
->setObject($package)
|
||||
->setObjectName(pht('Package %d', $id))
|
||||
->setHeader($package->getName())
|
||||
->setHref('/owners/package/'.$id.'/');
|
||||
|
||||
$list->addItem($item);
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorOwnersPackageTransactionQuery
|
||||
extends PhabricatorApplicationTransactionQuery {
|
||||
|
||||
public function getTemplateApplicationTransaction() {
|
||||
return new PhabricatorOwnersPackageTransaction();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,19 +1,23 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorOwnersPackage extends PhabricatorOwnersDAO
|
||||
implements PhabricatorPolicyInterface {
|
||||
final class PhabricatorOwnersPackage
|
||||
extends PhabricatorOwnersDAO
|
||||
implements
|
||||
PhabricatorPolicyInterface,
|
||||
PhabricatorApplicationTransactionInterface {
|
||||
|
||||
protected $name;
|
||||
protected $originalName;
|
||||
protected $auditingEnabled;
|
||||
protected $description;
|
||||
protected $primaryOwnerPHID;
|
||||
protected $mailKey;
|
||||
|
||||
private $unsavedOwners = self::ATTACHABLE;
|
||||
private $unsavedPaths = self::ATTACHABLE;
|
||||
private $actorPHID;
|
||||
private $oldPrimaryOwnerPHID;
|
||||
private $oldAuditingEnabled;
|
||||
public static function initializeNewPackage(PhabricatorUser $actor) {
|
||||
return id(new PhabricatorOwnersPackage())
|
||||
->setAuditingEnabled(0)
|
||||
->setPrimaryOwnerPHID($actor->getPHID());
|
||||
}
|
||||
|
||||
public function getCapabilities() {
|
||||
return array(
|
||||
|
@ -37,13 +41,14 @@ final class PhabricatorOwnersPackage extends PhabricatorOwnersDAO
|
|||
return array(
|
||||
// This information is better available from the history table.
|
||||
self::CONFIG_TIMESTAMPS => false,
|
||||
self::CONFIG_AUX_PHID => true,
|
||||
self::CONFIG_AUX_PHID => true,
|
||||
self::CONFIG_COLUMN_SCHEMA => array(
|
||||
'name' => 'text128',
|
||||
'originalName' => 'text255',
|
||||
'description' => 'text',
|
||||
'primaryOwnerPHID' => 'phid?',
|
||||
'auditingEnabled' => 'bool',
|
||||
'mailKey' => 'bytes20',
|
||||
),
|
||||
self::CONFIG_KEY_SCHEMA => array(
|
||||
'key_phid' => null,
|
||||
|
@ -60,52 +65,16 @@ final class PhabricatorOwnersPackage extends PhabricatorOwnersDAO
|
|||
}
|
||||
|
||||
public function generatePHID() {
|
||||
return PhabricatorPHID::generateNewPHID('OPKG');
|
||||
return PhabricatorPHID::generateNewPHID(
|
||||
PhabricatorOwnersPackagePHIDType::TYPECONST);
|
||||
}
|
||||
|
||||
public function attachUnsavedOwners(array $owners) {
|
||||
$this->unsavedOwners = $owners;
|
||||
return $this;
|
||||
}
|
||||
public function save() {
|
||||
if (!$this->getMailKey()) {
|
||||
$this->setMailKey(Filesystem::readRandomCharacters(20));
|
||||
}
|
||||
|
||||
public function getUnsavedOwners() {
|
||||
return $this->assertAttached($this->unsavedOwners);
|
||||
}
|
||||
|
||||
public function attachUnsavedPaths(array $paths) {
|
||||
$this->unsavedPaths = $paths;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getUnsavedPaths() {
|
||||
return $this->assertAttached($this->unsavedPaths);
|
||||
}
|
||||
|
||||
public function attachActorPHID($actor_phid) {
|
||||
$this->actorPHID = $actor_phid;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getActorPHID() {
|
||||
return $this->actorPHID;
|
||||
}
|
||||
|
||||
public function attachOldPrimaryOwnerPHID($old_primary) {
|
||||
$this->oldPrimaryOwnerPHID = $old_primary;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getOldPrimaryOwnerPHID() {
|
||||
return $this->oldPrimaryOwnerPHID;
|
||||
}
|
||||
|
||||
public function attachOldAuditingEnabled($auditing_enabled) {
|
||||
$this->oldAuditingEnabled = $auditing_enabled;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getOldAuditingEnabled() {
|
||||
return $this->oldAuditingEnabled;
|
||||
return parent::save();
|
||||
}
|
||||
|
||||
public function setName($name) {
|
||||
|
@ -143,15 +112,15 @@ final class PhabricatorOwnersPackage extends PhabricatorOwnersDAO
|
|||
}
|
||||
|
||||
return self::loadPackagesForPaths($repository, $paths);
|
||||
}
|
||||
}
|
||||
|
||||
public static function loadOwningPackages($repository, $path) {
|
||||
public static function loadOwningPackages($repository, $path) {
|
||||
if (empty($path)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
return self::loadPackagesForPaths($repository, array($path), 1);
|
||||
}
|
||||
}
|
||||
|
||||
private static function loadPackagesForPaths(
|
||||
PhabricatorRepository $repository,
|
||||
|
@ -268,4 +237,27 @@ final class PhabricatorOwnersPackage extends PhabricatorOwnersDAO
|
|||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
|
||||
|
||||
|
||||
public function getApplicationTransactionEditor() {
|
||||
return new PhabricatorOwnersPackageTransactionEditor();
|
||||
}
|
||||
|
||||
public function getApplicationTransactionObject() {
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getApplicationTransactionTemplate() {
|
||||
return new PhabricatorOwnersPackageTransaction();
|
||||
}
|
||||
|
||||
public function willRenderTimeline(
|
||||
PhabricatorApplicationTransactionView $timeline,
|
||||
AphrontRequest $request) {
|
||||
return $timeline;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,211 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorOwnersPackageTransaction
|
||||
extends PhabricatorApplicationTransaction {
|
||||
|
||||
const TYPE_NAME = 'owners.name';
|
||||
const TYPE_PRIMARY = 'owners.primary';
|
||||
const TYPE_OWNERS = 'owners.owners';
|
||||
const TYPE_AUDITING = 'owners.auditing';
|
||||
const TYPE_DESCRIPTION = 'owners.description';
|
||||
const TYPE_PATHS = 'owners.paths';
|
||||
|
||||
public function getApplicationName() {
|
||||
return 'owners';
|
||||
}
|
||||
|
||||
public function getApplicationTransactionType() {
|
||||
return PhabricatorOwnersPackagePHIDType::TYPECONST;
|
||||
}
|
||||
|
||||
public function getRequiredHandlePHIDs() {
|
||||
$phids = parent::getRequiredHandlePHIDs();
|
||||
|
||||
$old = $this->getOldValue();
|
||||
$new = $this->getNewValue();
|
||||
|
||||
switch ($this->getTransactionType()) {
|
||||
case self::TYPE_PRIMARY:
|
||||
if ($old) {
|
||||
$phids[] = $old;
|
||||
}
|
||||
if ($new) {
|
||||
$phids[] = $new;
|
||||
}
|
||||
break;
|
||||
case self::TYPE_OWNERS:
|
||||
$add = array_diff($new, $old);
|
||||
foreach ($add as $phid) {
|
||||
$phids[] = $phid;
|
||||
}
|
||||
$rem = array_diff($old, $new);
|
||||
foreach ($rem as $phid) {
|
||||
$phids[] = $phid;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return $phids;
|
||||
}
|
||||
|
||||
public function shouldHide() {
|
||||
$old = $this->getOldValue();
|
||||
$new = $this->getNewValue();
|
||||
|
||||
switch ($this->getTransactionType()) {
|
||||
case self::TYPE_DESCRIPTION:
|
||||
return ($old === null);
|
||||
}
|
||||
}
|
||||
|
||||
public function getTitle() {
|
||||
$old = $this->getOldValue();
|
||||
$new = $this->getNewValue();
|
||||
$author_phid = $this->getAuthorPHID();
|
||||
|
||||
switch ($this->getTransactionType()) {
|
||||
case self::TYPE_NAME:
|
||||
if ($old === null) {
|
||||
return pht(
|
||||
'%s created this package.',
|
||||
$this->renderHandleLink($author_phid));
|
||||
} else {
|
||||
return pht(
|
||||
'%s renamed this package from "%s" to "%s".',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$old,
|
||||
$new);
|
||||
}
|
||||
case self::TYPE_PRIMARY:
|
||||
return pht(
|
||||
'%s changed the primary owner for this package from %s to %s.',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$this->renderHandleLink($old),
|
||||
$this->renderHandleLink($new));
|
||||
case self::TYPE_OWNERS:
|
||||
$add = array_diff($new, $old);
|
||||
$rem = array_diff($old, $new);
|
||||
if ($add && !$rem) {
|
||||
return pht(
|
||||
'%s added %s owner(s): %s.',
|
||||
$this->renderHandleLink($author_phid),
|
||||
count($add),
|
||||
$this->renderHandleList($add));
|
||||
} else if ($rem && !$add) {
|
||||
return pht(
|
||||
'%s removed %s owner(s): %s.',
|
||||
$this->renderHandleLink($author_phid),
|
||||
count($rem),
|
||||
$this->renderHandleList($rem));
|
||||
} else {
|
||||
return pht(
|
||||
'%s changed %s package owner(s), added %s: %s; removed %s: %s.',
|
||||
$this->renderHandleLink($author_phid),
|
||||
count($add) + count($rem),
|
||||
count($add),
|
||||
$this->renderHandleList($add),
|
||||
count($rem),
|
||||
$this->renderHandleList($rem));
|
||||
}
|
||||
case self::TYPE_AUDITING:
|
||||
if ($new) {
|
||||
return pht(
|
||||
'%s enabled auditing for this package.',
|
||||
$this->renderHandleLink($author_phid));
|
||||
} else {
|
||||
return pht(
|
||||
'%s disabled auditing for this package.',
|
||||
$this->renderHandleLink($author_phid));
|
||||
}
|
||||
case self::TYPE_DESCRIPTION:
|
||||
return pht(
|
||||
'%s updated the description for this package.',
|
||||
$this->renderHandleLink($author_phid));
|
||||
case self::TYPE_PATHS:
|
||||
// TODO: Flesh this out.
|
||||
return pht(
|
||||
'%s updated paths for this package.',
|
||||
$this->renderHandleLink($author_phid));
|
||||
}
|
||||
|
||||
return parent::getTitle();
|
||||
}
|
||||
|
||||
public function hasChangeDetails() {
|
||||
switch ($this->getTransactionType()) {
|
||||
case self::TYPE_DESCRIPTION:
|
||||
return ($this->getOldValue() !== null);
|
||||
case self::TYPE_PATHS:
|
||||
return true;
|
||||
}
|
||||
|
||||
return parent::hasChangeDetails();
|
||||
}
|
||||
|
||||
public function renderChangeDetails(PhabricatorUser $viewer) {
|
||||
switch ($this->getTransactionType()) {
|
||||
case self::TYPE_DESCRIPTION:
|
||||
$old = $this->getOldValue();
|
||||
$new = $this->getNewValue();
|
||||
|
||||
return $this->renderTextCorpusChangeDetails(
|
||||
$viewer,
|
||||
$old,
|
||||
$new);
|
||||
case self::TYPE_PATHS:
|
||||
$old = $this->getOldValue();
|
||||
$new = $this->getNewValue();
|
||||
|
||||
$diffs = PhabricatorOwnersPath::getTransactionValueChanges($old, $new);
|
||||
list($rem, $add) = $diffs;
|
||||
|
||||
$rows = array();
|
||||
foreach ($rem as $ref) {
|
||||
$rows[] = array(
|
||||
'class' => 'diff-removed',
|
||||
'change' => '-',
|
||||
) + $ref;
|
||||
}
|
||||
|
||||
foreach ($add as $ref) {
|
||||
$rows[] = array(
|
||||
'class' => 'diff-added',
|
||||
'change' => '+',
|
||||
) + $ref;
|
||||
}
|
||||
|
||||
$rowc = array();
|
||||
foreach ($rows as $key => $row) {
|
||||
$rowc[] = $row['class'];
|
||||
$rows[$key] = array(
|
||||
$row['change'],
|
||||
$row['excluded'] ? pht('Exclude') : pht('Include'),
|
||||
$viewer->renderHandle($row['repositoryPHID']),
|
||||
$row['path'],
|
||||
);
|
||||
}
|
||||
|
||||
$table = id(new AphrontTableView($rows))
|
||||
->setRowClasses($rowc)
|
||||
->setHeaders(
|
||||
array(
|
||||
null,
|
||||
pht('Type'),
|
||||
pht('Repository'),
|
||||
pht('Path'),
|
||||
))
|
||||
->setColumnClasses(
|
||||
array(
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
'wide',
|
||||
));
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
return parent::renderChangeDetails($viewer);
|
||||
}
|
||||
|
||||
}
|
|
@ -22,4 +22,52 @@ final class PhabricatorOwnersPath extends PhabricatorOwnersDAO {
|
|||
) + parent::getConfiguration();
|
||||
}
|
||||
|
||||
|
||||
public static function newFromRef(array $ref) {
|
||||
$path = new PhabricatorOwnersPath();
|
||||
$path->repositoryPHID = $ref['repositoryPHID'];
|
||||
$path->path = $ref['path'];
|
||||
$path->excluded = $ref['excluded'];
|
||||
return $path;
|
||||
}
|
||||
|
||||
public function getRef() {
|
||||
return array(
|
||||
'repositoryPHID' => $this->getRepositoryPHID(),
|
||||
'path' => $this->getPath(),
|
||||
'excluded' => (int)$this->getExcluded(),
|
||||
);
|
||||
}
|
||||
|
||||
public static function getTransactionValueChanges(array $old, array $new) {
|
||||
return array(
|
||||
self::getTransactionValueDiff($old, $new),
|
||||
self::getTransactionValueDiff($new, $old),
|
||||
);
|
||||
}
|
||||
|
||||
private static function getTransactionValueDiff(array $u, array $v) {
|
||||
$set = self::getSetFromTransactionValue($v);
|
||||
|
||||
foreach ($u as $key => $ref) {
|
||||
if (self::isRefInSet($ref, $set)) {
|
||||
unset($u[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
return $u;
|
||||
}
|
||||
|
||||
public static function getSetFromTransactionValue(array $v) {
|
||||
$set = array();
|
||||
foreach ($v as $ref) {
|
||||
$set[$ref['repositoryPHID']][$ref['path']][$ref['excluded']] = true;
|
||||
}
|
||||
return $set;
|
||||
}
|
||||
|
||||
public static function isRefInSet(array $ref, array $set) {
|
||||
return isset($set[$ref['repositoryPHID']][$ref['path']][$ref['excluded']]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,100 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class ReleephProjectInfoConduitAPIMethod extends ReleephConduitAPIMethod {
|
||||
|
||||
public function getAPIMethodName() {
|
||||
return 'releeph.projectinfo';
|
||||
}
|
||||
|
||||
public function getMethodDescription() {
|
||||
return pht(
|
||||
'Fetch information about all Releeph projects '.
|
||||
'for a given Arcanist project.');
|
||||
}
|
||||
|
||||
protected function defineParamTypes() {
|
||||
return array(
|
||||
'arcProjectName' => 'optional string',
|
||||
);
|
||||
}
|
||||
|
||||
protected function defineReturnType() {
|
||||
return 'dict<string, wild>';
|
||||
}
|
||||
|
||||
protected function defineErrorTypes() {
|
||||
return array(
|
||||
'ERR_UNKNOWN_ARC' => pht(
|
||||
"The given Arcanist project name doesn't exist in the ".
|
||||
"installation of Phabricator you are accessing."),
|
||||
);
|
||||
}
|
||||
|
||||
protected function execute(ConduitAPIRequest $request) {
|
||||
$arc_project_name = $request->getValue('arcProjectName');
|
||||
if ($arc_project_name) {
|
||||
$arc_project = id(new PhabricatorRepositoryArcanistProject())
|
||||
->loadOneWhere('name = %s', $arc_project_name);
|
||||
if (!$arc_project) {
|
||||
throw id(new ConduitException('ERR_UNKNOWN_ARC'))
|
||||
->setErrorDescription(
|
||||
pht(
|
||||
"Unknown Arcanist project '%s': ".
|
||||
"are you using the correct Conduit URI?",
|
||||
$arc_project_name));
|
||||
}
|
||||
|
||||
$releeph_projects = id(new ReleephProject())
|
||||
->loadAllWhere('arcanistProjectID = %d', $arc_project->getID());
|
||||
} else {
|
||||
$releeph_projects = id(new ReleephProject())->loadAll();
|
||||
}
|
||||
|
||||
$releeph_projects = mfilter($releeph_projects, 'getIsActive');
|
||||
|
||||
$result = array();
|
||||
foreach ($releeph_projects as $releeph_project) {
|
||||
$selector = $releeph_project->getReleephFieldSelector();
|
||||
$fields = $selector->getFieldSpecifications();
|
||||
|
||||
$fields_info = array();
|
||||
foreach ($fields as $field) {
|
||||
$field->setReleephProject($releeph_project);
|
||||
if ($field->isEditable()) {
|
||||
$key = $field->getKeyForConduit();
|
||||
$fields_info[$key] = array(
|
||||
'class' => get_class($field),
|
||||
'name' => $field->getName(),
|
||||
'key' => $key,
|
||||
'arcHelp' => $field->renderHelpForArcanist(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$releeph_branches = mfilter(
|
||||
id(new ReleephBranch())
|
||||
->loadAllWhere('releephProjectID = %d', $releeph_project->getID()),
|
||||
'getIsActive');
|
||||
|
||||
$releeph_branches_struct = array();
|
||||
foreach ($releeph_branches as $branch) {
|
||||
$releeph_branches_struct[] = array(
|
||||
'branchName' => $branch->getName(),
|
||||
'projectName' => $releeph_project->getName(),
|
||||
'projectPHID' => $releeph_project->getPHID(),
|
||||
'branchPHID' => $branch->getPHID(),
|
||||
);
|
||||
}
|
||||
|
||||
$result[] = array(
|
||||
'projectName' => $releeph_project->getName(),
|
||||
'projectPHID' => $releeph_project->getPHID(),
|
||||
'branches' => $releeph_branches_struct,
|
||||
'fields' => $fields_info,
|
||||
);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
|
@ -13,10 +13,10 @@ final class ReleephBranchNamePreviewController
|
|||
$template = ReleephBranchTemplate::getDefaultTemplate();
|
||||
}
|
||||
|
||||
$arc_project_id = $request->getInt('arcProjectID');
|
||||
$repository_phid = $request->getInt('repositoryPHID');
|
||||
$fake_commit_handle =
|
||||
ReleephBranchTemplate::getFakeCommitHandleFor(
|
||||
$arc_project_id,
|
||||
$repository_phid,
|
||||
$request->getUser());
|
||||
|
||||
list($name, $errors) = id(new ReleephBranchTemplate())
|
||||
|
|
|
@ -6,9 +6,7 @@ final class ReleephProductCreateController extends ReleephProductController {
|
|||
$request = $this->getRequest();
|
||||
$name = trim($request->getStr('name'));
|
||||
$trunk_branch = trim($request->getStr('trunkBranch'));
|
||||
$arc_pr_id = $request->getInt('arcPrID');
|
||||
|
||||
$arc_projects = $this->loadArcProjects();
|
||||
$repository_phid = $request->getStr('repositoryPHID');
|
||||
|
||||
$e_name = true;
|
||||
$e_trunk_branch = true;
|
||||
|
@ -27,14 +25,10 @@ final class ReleephProductCreateController extends ReleephProductController {
|
|||
'You must specify which branch you will be picking from.');
|
||||
}
|
||||
|
||||
$arc_project = $arc_projects[$arc_pr_id];
|
||||
$pr_repository = null;
|
||||
if ($arc_project->getRepositoryID()) {
|
||||
$pr_repository = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer($request->getUser())
|
||||
->withIDs(array($arc_project->getRepositoryID()))
|
||||
->executeOne();
|
||||
}
|
||||
$pr_repository = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer($request->getUser())
|
||||
->withPHIDs(array($repository_phid))
|
||||
->executeOne();
|
||||
|
||||
|
||||
if (!$errors) {
|
||||
|
@ -42,7 +36,6 @@ final class ReleephProductCreateController extends ReleephProductController {
|
|||
->setName($name)
|
||||
->setTrunkBranch($trunk_branch)
|
||||
->setRepositoryPHID($pr_repository->getPHID())
|
||||
->setArcanistProjectID($arc_project->getID())
|
||||
->setCreatedByUserPHID($request->getUser()->getPHID())
|
||||
->setIsActive(1);
|
||||
|
||||
|
@ -58,7 +51,7 @@ final class ReleephProductCreateController extends ReleephProductController {
|
|||
}
|
||||
}
|
||||
|
||||
$arc_project_options = $this->getArcProjectSelectOptions($arc_projects);
|
||||
$repo_options = $this->getRepositorySelectOptions();
|
||||
|
||||
$product_name_input = id(new AphrontFormTextControl())
|
||||
->setLabel(pht('Name'))
|
||||
|
@ -68,32 +61,23 @@ final class ReleephProductCreateController extends ReleephProductController {
|
|||
->setError($e_name)
|
||||
->setCaption(pht('A name like "Thrift" but not "Thrift releases".'));
|
||||
|
||||
$arc_project_input = id(new AphrontFormSelectControl())
|
||||
->setLabel(pht('Arc Project'))
|
||||
->setName('arcPrID')
|
||||
->setValue($arc_pr_id)
|
||||
->setCaption(pht(
|
||||
"If your Arc project isn't listed, associate it with a repository %s.",
|
||||
phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '/repository/',
|
||||
'target' => '_blank',
|
||||
),
|
||||
'here')))
|
||||
->setOptions($arc_project_options);
|
||||
$repository_input = id(new AphrontFormSelectControl())
|
||||
->setLabel(pht('Repository'))
|
||||
->setName('repositoryPHID')
|
||||
->setValue($repository_phid)
|
||||
->setOptions($repo_options);
|
||||
|
||||
$branch_name_preview = id(new ReleephBranchPreviewView())
|
||||
->setLabel(pht('Example Branch'))
|
||||
->addControl('projectName', $product_name_input)
|
||||
->addControl('arcProjectID', $arc_project_input)
|
||||
->addControl('repositoryPHID', $repository_input)
|
||||
->addStatic('template', '')
|
||||
->addStatic('isSymbolic', false);
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($request->getUser())
|
||||
->appendChild($product_name_input)
|
||||
->appendChild($arc_project_input)
|
||||
->appendChild($repository_input)
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setLabel(pht('Trunk'))
|
||||
|
@ -126,43 +110,23 @@ final class ReleephProductCreateController extends ReleephProductController {
|
|||
));
|
||||
}
|
||||
|
||||
private function loadArcProjects() {
|
||||
$viewer = $this->getRequest()->getUser();
|
||||
|
||||
$projects = id(new PhabricatorRepositoryArcanistProjectQuery())
|
||||
->setViewer($viewer)
|
||||
->needRepositories(true)
|
||||
private function getRepositorySelectOptions() {
|
||||
$repos = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer($this->getRequest()->getUser())
|
||||
->execute();
|
||||
|
||||
$projects = mfilter($projects, 'getRepository');
|
||||
$projects = msort($projects, 'getName');
|
||||
|
||||
return $projects;
|
||||
}
|
||||
|
||||
private function getArcProjectSelectOptions(array $arc_projects) {
|
||||
assert_instances_of($arc_projects, 'PhabricatorRepositoryArcanistProject');
|
||||
|
||||
$repos = mpull($arc_projects, 'getRepository');
|
||||
$repos = msort($repos, 'getName');
|
||||
$repos = mpull($repos, null, 'getID');
|
||||
|
||||
$groups = array();
|
||||
foreach ($arc_projects as $arc_project) {
|
||||
$id = $arc_project->getID();
|
||||
$repo_id = $arc_project->getRepository()->getID();
|
||||
$groups[$repo_id][$id] = $arc_project->getName();
|
||||
}
|
||||
|
||||
$choices = array();
|
||||
foreach ($groups as $repo_id => $group) {
|
||||
$repo_name = $repos[$repo_id]->getName();
|
||||
$callsign = $repos[$repo_id]->getCallsign();
|
||||
$name = "r{$callsign} ({$repo_name})";
|
||||
$choices[$name] = $group;
|
||||
|
||||
foreach ($repos as $repo_id => $repo) {
|
||||
$repo_name = $repo->getName();
|
||||
$callsign = $repo->getCallsign();
|
||||
$choices[$repo->getPHID()] = "r{$callsign} ({$repo_name})";
|
||||
}
|
||||
|
||||
ksort($choices);
|
||||
|
||||
return $choices;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@ final class ReleephProductEditController extends ReleephProductController {
|
|||
$product = id(new ReleephProductQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($this->productID))
|
||||
->needArcanistProjects(true)
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
|
@ -48,7 +47,7 @@ final class ReleephProductEditController extends ReleephProductController {
|
|||
$test_paths = $product->getDetail('testPaths', array());
|
||||
}
|
||||
|
||||
$arc_project_id = $product->getArcanistProjectID();
|
||||
$repository_phid = $product->getRepositoryPHID();
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$pusher_phids = $request->getArr('pushers');
|
||||
|
@ -92,8 +91,9 @@ final class ReleephProductEditController extends ReleephProductController {
|
|||
->setDetail('branchTemplate', $branch_template)
|
||||
->setDetail('testPaths', $test_paths);
|
||||
|
||||
$fake_commit_handle =
|
||||
ReleephBranchTemplate::getFakeCommitHandleFor($arc_project_id, $viewer);
|
||||
$fake_commit_handle = ReleephBranchTemplate::getFakeCommitHandleFor(
|
||||
$repository_phid,
|
||||
$viewer);
|
||||
|
||||
if ($branch_template) {
|
||||
list($branch_name, $template_errors) = id(new ReleephBranchTemplate())
|
||||
|
@ -136,9 +136,9 @@ final class ReleephProductEditController extends ReleephProductController {
|
|||
$product->getRepository()->getName()))
|
||||
->appendChild(
|
||||
id(new AphrontFormStaticControl())
|
||||
->setLabel(pht('Arc Project'))
|
||||
->setLabel(pht('Repository'))
|
||||
->setValue(
|
||||
$product->getArcanistProject()->getName()))
|
||||
$product->getRepository()->getName()))
|
||||
->appendChild(
|
||||
id(new AphrontFormStaticControl())
|
||||
->setLabel(pht('Releeph Project PHID'))
|
||||
|
@ -179,7 +179,7 @@ final class ReleephProductEditController extends ReleephProductController {
|
|||
$branch_template_preview = id(new ReleephBranchPreviewView())
|
||||
->setLabel(pht('Preview'))
|
||||
->addControl('template', $branch_template_input)
|
||||
->addStatic('arcProjectID', $arc_project_id)
|
||||
->addStatic('repositoryPHID', $repository_phid)
|
||||
->addStatic('isSymbolic', false)
|
||||
->addStatic('projectName', $product->getName());
|
||||
|
||||
|
|
|
@ -25,19 +25,18 @@ final class ReleephRequestDifferentialCreateController
|
|||
}
|
||||
$this->revision = $diff_rev;
|
||||
|
||||
$arc_project = id(new PhabricatorRepositoryArcanistProject())
|
||||
->loadOneWhere('phid = %s', $this->revision->getArcanistProjectPHID());
|
||||
$repository = $this->revision->getRepository();
|
||||
|
||||
$projects = id(new ReleephProject())->loadAllWhere(
|
||||
'arcanistProjectID = %d AND isActive = 1',
|
||||
$arc_project->getID());
|
||||
'repositoryPHID = %s AND isActive = 1',
|
||||
$repository->getPHID());
|
||||
if (!$projects) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
"%s belongs to the '%s' Arcanist project, ".
|
||||
"%s belongs to the '%s' repository, ".
|
||||
"which is not part of any Releeph project!",
|
||||
'D'.$this->revision->getID(),
|
||||
$arc_project->getName()));
|
||||
$repository->getMonogram()));
|
||||
}
|
||||
|
||||
$branches = id(new ReleephBranch())->loadAllWhere(
|
||||
|
|
|
@ -8,8 +8,6 @@ final class ReleephProductQuery
|
|||
private $phids;
|
||||
private $repositoryPHIDs;
|
||||
|
||||
private $needArcanistProjects;
|
||||
|
||||
const ORDER_ID = 'order-id';
|
||||
const ORDER_NAME = 'order-name';
|
||||
|
||||
|
@ -47,11 +45,6 @@ final class ReleephProductQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function needArcanistProjects($need) {
|
||||
$this->needArcanistProjects = $need;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function loadPage() {
|
||||
$table = new ReleephProject();
|
||||
$conn_r = $table->establishConnection('r');
|
||||
|
@ -90,27 +83,6 @@ final class ReleephProductQuery
|
|||
return $projects;
|
||||
}
|
||||
|
||||
protected function didFilterPage(array $products) {
|
||||
if ($this->needArcanistProjects) {
|
||||
$project_ids = array_filter(mpull($products, 'getArcanistProjectID'));
|
||||
if ($project_ids) {
|
||||
$projects = id(new PhabricatorRepositoryArcanistProject())
|
||||
->loadAllWhere('id IN (%Ld)', $project_ids);
|
||||
$projects = mpull($projects, null, 'getID');
|
||||
} else {
|
||||
$projects = array();
|
||||
}
|
||||
|
||||
foreach ($products as $product) {
|
||||
$project_id = $product->getArcanistProjectID();
|
||||
$project = idx($projects, $project_id);
|
||||
$product->attachArcanistProject($project);
|
||||
}
|
||||
}
|
||||
|
||||
return $products;
|
||||
}
|
||||
|
||||
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
|
||||
$where = array();
|
||||
|
||||
|
|
|
@ -21,8 +21,7 @@ final class ReleephProductSearchEngine
|
|||
|
||||
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
|
||||
$query = id(new ReleephProductQuery())
|
||||
->setOrder(ReleephProductQuery::ORDER_NAME)
|
||||
->needArcanistProjects(true);
|
||||
->setOrder(ReleephProductQuery::ORDER_NAME);
|
||||
|
||||
$active = $saved->getParameter('active');
|
||||
$value = idx($this->getActiveValues(), $active);
|
||||
|
@ -119,11 +118,6 @@ final class ReleephProductSearchEngine
|
|||
),
|
||||
'r'.$repo->getCallsign()));
|
||||
|
||||
$arc = $product->getArcanistProject();
|
||||
if ($arc) {
|
||||
$item->addAttribute($arc->getName());
|
||||
}
|
||||
|
||||
$list->addItem($item);
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ final class ReleephProject extends ReleephDAO
|
|||
'name' => 'text128',
|
||||
'trunkBranch' => 'text255',
|
||||
'isActive' => 'bool',
|
||||
'arcanistProjectID' => 'id?',
|
||||
),
|
||||
self::CONFIG_KEY_SCHEMA => array(
|
||||
'projectName' => array(
|
||||
|
|
|
@ -24,7 +24,7 @@ final class ReleephBranchPreviewView extends AphrontFormControl {
|
|||
|
||||
protected function renderInput() {
|
||||
static $required_params = array(
|
||||
'arcProjectID',
|
||||
'repositoryPHID',
|
||||
'projectName',
|
||||
'isSymbolic',
|
||||
'template',
|
||||
|
@ -43,9 +43,9 @@ final class ReleephBranchPreviewView extends AphrontFormControl {
|
|||
$output_id = celerity_generate_unique_node_id();
|
||||
|
||||
Javelin::initBehavior('releeph-preview-branch', array(
|
||||
'uri' => '/releeph/branch/preview/',
|
||||
'outputID' => $output_id,
|
||||
'params' => array(
|
||||
'uri' => '/releeph/branch/preview/',
|
||||
'outputID' => $output_id,
|
||||
'params' => array(
|
||||
'static' => $this->statics,
|
||||
'dynamic' => $this->dynamics,
|
||||
),
|
||||
|
|
|
@ -20,25 +20,14 @@ final class ReleephBranchTemplate {
|
|||
}
|
||||
|
||||
public static function getFakeCommitHandleFor(
|
||||
$arc_project_id,
|
||||
$repository_phid,
|
||||
PhabricatorUser $viewer) {
|
||||
|
||||
$arc_project = id(new PhabricatorRepositoryArcanistProject())
|
||||
->load($arc_project_id);
|
||||
if (!$arc_project) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
"No Arc project found with id '%s'!",
|
||||
$arc_project_id));
|
||||
}
|
||||
$repository = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs(array($repository_phid))
|
||||
->executeOne();
|
||||
|
||||
$repository = null;
|
||||
if ($arc_project->getRepositoryID()) {
|
||||
$repository = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($arc_project->getRepositoryID()))
|
||||
->executeOne();
|
||||
}
|
||||
$fake_handle = 'SOFAKE';
|
||||
if ($repository) {
|
||||
$fake_handle = id(new PhabricatorObjectHandle())
|
||||
|
|
|
@ -30,10 +30,6 @@ final class PhabricatorRepositoriesApplication extends PhabricatorApplication {
|
|||
return array(
|
||||
'/repository/' => array(
|
||||
'' => 'PhabricatorRepositoryListController',
|
||||
'project/edit/(?P<id>[1-9]\d*)/'
|
||||
=> 'PhabricatorRepositoryArcanistProjectEditController',
|
||||
'project/delete/(?P<id>[1-9]\d*)/'
|
||||
=> 'PhabricatorRepositoryArcanistProjectDeleteController',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorRepositoryArcanistProjectDeleteController
|
||||
extends PhabricatorRepositoryController {
|
||||
|
||||
private $id;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->id = $data['id'];
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
|
||||
$arc_project =
|
||||
id(new PhabricatorRepositoryArcanistProject())->load($this->id);
|
||||
if (!$arc_project) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$request = $this->getRequest();
|
||||
|
||||
if ($request->isDialogFormPost()) {
|
||||
$arc_project->delete();
|
||||
return id(new AphrontRedirectResponse())->setURI('/repository/');
|
||||
}
|
||||
|
||||
$dialog = new AphrontDialogView();
|
||||
$dialog
|
||||
->setUser($request->getUser())
|
||||
->setTitle(pht('Really delete this arcanist project?'))
|
||||
->appendChild(
|
||||
pht(
|
||||
'Really delete the "%s" arcanist project? '.
|
||||
'This operation can not be undone.',
|
||||
$arc_project->getName()))
|
||||
->setSubmitURI('/repository/project/delete/'.$this->id.'/')
|
||||
->addSubmitButton(pht('Delete Arcanist Project'))
|
||||
->addCancelButton('/repository/');
|
||||
|
||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
||||
}
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorRepositoryArcanistProjectEditController
|
||||
extends PhabricatorRepositoryController {
|
||||
|
||||
private $id;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->id = $data['id'];
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$project = id(new PhabricatorRepositoryArcanistProject())->load($this->id);
|
||||
if (!$project) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$repositories = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer($user)
|
||||
->execute();
|
||||
$repos = array(
|
||||
0 => 'None',
|
||||
);
|
||||
foreach ($repositories as $repository) {
|
||||
$callsign = $repository->getCallsign();
|
||||
$name = $repository->getname();
|
||||
$repos[$repository->getID()] = "r{$callsign} ({$name})";
|
||||
}
|
||||
// note "None" will still be first thanks to 'r' prefix
|
||||
asort($repos);
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$repo_id = $request->getInt('repository', 0);
|
||||
if (isset($repos[$repo_id])) {
|
||||
$project->setRepositoryID($repo_id);
|
||||
$project->save();
|
||||
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI('/repository/');
|
||||
}
|
||||
}
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($user)
|
||||
->appendChild(
|
||||
id(new AphrontFormStaticControl())
|
||||
->setLabel(pht('Name'))
|
||||
->setValue($project->getName()))
|
||||
->appendChild(
|
||||
id(new AphrontFormStaticControl())
|
||||
->setLabel('PHID')
|
||||
->setValue($project->getPHID()))
|
||||
->appendChild(
|
||||
id(new AphrontFormSelectControl())
|
||||
->setLabel(pht('Repository'))
|
||||
->setOptions($repos)
|
||||
->setName('repository')
|
||||
->setValue($project->getRepositoryID()))
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->addCancelButton('/repository/')
|
||||
->setValue(pht('Save')));
|
||||
|
||||
$panel = new PHUIObjectBoxView();
|
||||
$panel->setHeaderText(pht('Edit Arcanist Project'));
|
||||
$panel->setForm($form);
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb(pht('Edit Project'));
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
array(
|
||||
$crumbs,
|
||||
$panel,
|
||||
),
|
||||
array(
|
||||
'title' => pht('Edit Project'),
|
||||
));
|
||||
}
|
||||
|
||||
}
|
|
@ -85,68 +85,6 @@ final class PhabricatorRepositoryListController
|
|||
$panel->setHeader($header);
|
||||
$panel->setTable($table);
|
||||
|
||||
$projects = id(new PhabricatorRepositoryArcanistProject())->loadAll();
|
||||
|
||||
$rows = array();
|
||||
foreach ($projects as $project) {
|
||||
$repo = idx($repos, $project->getRepositoryID());
|
||||
if ($repo) {
|
||||
$repo_name = $repo->getName();
|
||||
} else {
|
||||
$repo_name = '-';
|
||||
}
|
||||
|
||||
$rows[] = array(
|
||||
$project->getName(),
|
||||
$repo_name,
|
||||
phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '/repository/project/edit/'.$project->getID().'/',
|
||||
'class' => 'button grey small',
|
||||
),
|
||||
pht('Edit')),
|
||||
javelin_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '/repository/project/delete/'.$project->getID().'/',
|
||||
'class' => 'button grey small',
|
||||
'sigil' => 'workflow',
|
||||
),
|
||||
pht('Delete')),
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
$project_table = new AphrontTableView($rows);
|
||||
$project_table->setNoDataString(pht('No Arcanist Projects'));
|
||||
$project_table->setHeaders(
|
||||
array(
|
||||
pht('Project ID'),
|
||||
pht('Repository'),
|
||||
'',
|
||||
'',
|
||||
));
|
||||
$project_table->setColumnClasses(
|
||||
array(
|
||||
'',
|
||||
'wide',
|
||||
'action',
|
||||
'action',
|
||||
));
|
||||
|
||||
$project_table->setColumnVisibility(
|
||||
array(
|
||||
true,
|
||||
true,
|
||||
$is_admin,
|
||||
$is_admin,
|
||||
));
|
||||
|
||||
$project_panel = new PHUIObjectBoxView();
|
||||
$project_panel->setHeaderText(pht('Arcanist Projects'));
|
||||
$project_panel->setTable($project_table);
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb(pht('Repository List'));
|
||||
|
||||
|
@ -154,7 +92,6 @@ final class PhabricatorRepositoryListController
|
|||
array(
|
||||
$crumbs,
|
||||
$panel,
|
||||
$project_panel,
|
||||
),
|
||||
array(
|
||||
'title' => pht('Repository List'),
|
||||
|
|
|
@ -7,13 +7,22 @@ final class PhabricatorCommitBranchesField
|
|||
return 'diffusion:branches';
|
||||
}
|
||||
|
||||
public function shouldAppearInApplicationTransactions() {
|
||||
public function getFieldName() {
|
||||
return pht('Branches');
|
||||
}
|
||||
|
||||
public function getFieldDescription() {
|
||||
return pht('Shows branches a commit appears on in email.');
|
||||
}
|
||||
|
||||
public function shouldAppearInTransactionMail() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function buildApplicationTransactionMailBody(
|
||||
PhabricatorApplicationTransaction $xaction,
|
||||
PhabricatorMetaMTAMailBody $body) {
|
||||
public function updateTransactionMailBody(
|
||||
PhabricatorMetaMTAMailBody $body,
|
||||
PhabricatorApplicationTransactionEditor $editor,
|
||||
array $xactions) {
|
||||
|
||||
$params = array(
|
||||
'contains' => $this->getObject()->getCommitIdentifier(),
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorCommitMergedCommitsField
|
||||
extends PhabricatorCommitCustomField {
|
||||
|
||||
public function getFieldKey() {
|
||||
return 'diffusion:mergedcommits';
|
||||
}
|
||||
|
||||
public function getFieldName() {
|
||||
return pht('Merged Commits');
|
||||
}
|
||||
|
||||
public function getFieldDescription() {
|
||||
return pht('For merge commits, shows merged changes in email.');
|
||||
}
|
||||
|
||||
public function shouldDisableByDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function shouldAppearInTransactionMail() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function updateTransactionMailBody(
|
||||
PhabricatorMetaMTAMailBody $body,
|
||||
PhabricatorApplicationTransactionEditor $editor,
|
||||
array $xactions) {
|
||||
|
||||
// Put all the merged commits info int the mail body if this is a merge
|
||||
$merges_caption = '';
|
||||
// TODO: Make this limit configurable after T6030
|
||||
$limit = 50;
|
||||
$commit = $this->getObject();
|
||||
|
||||
try {
|
||||
$merges = DiffusionPathChange::newFromConduit(
|
||||
id(new ConduitCall('diffusion.mergedcommitsquery', array(
|
||||
'commit' => $commit->getCommitIdentifier(),
|
||||
'limit' => $limit + 1,
|
||||
'callsign' => $commit->getRepository()->getCallsign(),
|
||||
)))
|
||||
->setUser($this->getViewer())
|
||||
->execute());
|
||||
|
||||
if (count($merges) > $limit) {
|
||||
$merges = array_slice($merges, 0, $limit);
|
||||
$merges_caption =
|
||||
pht("This commit merges more than %d changes. Only the first ".
|
||||
"%d are shown.\n", $limit, $limit);
|
||||
}
|
||||
|
||||
if ($merges) {
|
||||
$merge_commits = array();
|
||||
foreach ($merges as $merge) {
|
||||
$merge_commits[] = $merge->getAuthorName().
|
||||
': '.
|
||||
$merge->getSummary();
|
||||
}
|
||||
$body->addTextSection(
|
||||
pht('MERGED COMMITS'),
|
||||
$merges_caption.implode("\n", $merge_commits));
|
||||
}
|
||||
} catch (ConduitException $ex) {
|
||||
// Log the exception into the email body
|
||||
$body->addTextSection(
|
||||
pht('MERGED COMMITS'),
|
||||
pht('Error generating merged commits: ').$ex->getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorCommitRepositoryField
|
||||
extends PhabricatorCommitCustomField {
|
||||
|
||||
public function getFieldKey() {
|
||||
return 'diffusion:repository';
|
||||
}
|
||||
|
||||
public function getFieldName() {
|
||||
return pht('Repository');
|
||||
}
|
||||
|
||||
public function getFieldDescription() {
|
||||
return pht('Shows repository in email.');
|
||||
}
|
||||
|
||||
public function shouldDisableByDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function shouldAppearInTransactionMail() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function updateTransactionMailBody(
|
||||
PhabricatorMetaMTAMailBody $body,
|
||||
PhabricatorApplicationTransactionEditor $editor,
|
||||
array $xactions) {
|
||||
|
||||
$repository = $this->getObject()->getRepository();
|
||||
|
||||
$body->addTextSection(
|
||||
pht('REPOSITORY'),
|
||||
$repository->getMonogram().' '.$repository->getName());
|
||||
}
|
||||
|
||||
}
|
|
@ -7,13 +7,22 @@ final class PhabricatorCommitTagsField
|
|||
return 'diffusion:tags';
|
||||
}
|
||||
|
||||
public function shouldAppearInApplicationTransactions() {
|
||||
public function getFieldName() {
|
||||
return pht('Tags');
|
||||
}
|
||||
|
||||
public function getFieldDescription() {
|
||||
return pht('Shows commit tags in email.');
|
||||
}
|
||||
|
||||
public function shouldAppearInTransactionMail() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function buildApplicationTransactionMailBody(
|
||||
PhabricatorApplicationTransaction $xaction,
|
||||
PhabricatorMetaMTAMailBody $body) {
|
||||
public function updateTransactionMailBody(
|
||||
PhabricatorMetaMTAMailBody $body,
|
||||
PhabricatorApplicationTransactionEditor $editor,
|
||||
array $xactions) {
|
||||
|
||||
$params = array(
|
||||
'commit' => $this->getObject()->getCommitIdentifier(),
|
||||
|
|
|
@ -43,6 +43,7 @@ final class PhabricatorRepositoryEditor
|
|||
$types[] = PhabricatorRepositoryTransaction::TYPE_SERVICE;
|
||||
$types[] = PhabricatorRepositoryTransaction::TYPE_SYMBOLS_LANGUAGE;
|
||||
$types[] = PhabricatorRepositoryTransaction::TYPE_SYMBOLS_SOURCES;
|
||||
$types[] = PhabricatorRepositoryTransaction::TYPE_STAGING_URI;
|
||||
|
||||
$types[] = PhabricatorTransactions::TYPE_EDGE;
|
||||
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
|
||||
|
@ -104,6 +105,8 @@ final class PhabricatorRepositoryEditor
|
|||
return $object->getSymbolLanguages();
|
||||
case PhabricatorRepositoryTransaction::TYPE_SYMBOLS_SOURCES:
|
||||
return $object->getSymbolSources();
|
||||
case PhabricatorRepositoryTransaction::TYPE_STAGING_URI:
|
||||
return $object->getDetail('staging-uri');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,6 +142,7 @@ final class PhabricatorRepositoryEditor
|
|||
case PhabricatorRepositoryTransaction::TYPE_SERVICE:
|
||||
case PhabricatorRepositoryTransaction::TYPE_SYMBOLS_LANGUAGE:
|
||||
case PhabricatorRepositoryTransaction::TYPE_SYMBOLS_SOURCES:
|
||||
case PhabricatorRepositoryTransaction::TYPE_STAGING_URI:
|
||||
return $xaction->getNewValue();
|
||||
case PhabricatorRepositoryTransaction::TYPE_NOTIFY:
|
||||
case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE:
|
||||
|
@ -219,6 +223,9 @@ final class PhabricatorRepositoryEditor
|
|||
case PhabricatorRepositoryTransaction::TYPE_SYMBOLS_SOURCES:
|
||||
$object->setDetail('symbol-sources', $xaction->getNewValue());
|
||||
return;
|
||||
case PhabricatorRepositoryTransaction::TYPE_STAGING_URI:
|
||||
$object->setDetail('staging-uri', $xaction->getNewValue());
|
||||
return;
|
||||
case PhabricatorRepositoryTransaction::TYPE_ENCODING:
|
||||
// Make sure the encoding is valid by converting to UTF-8. This tests
|
||||
// that the user has mbstring installed, and also that they didn't type
|
||||
|
@ -330,6 +337,7 @@ final class PhabricatorRepositoryEditor
|
|||
case PhabricatorRepositoryTransaction::TYPE_SERVICE:
|
||||
case PhabricatorRepositoryTransaction::TYPE_SYMBOLS_SOURCES:
|
||||
case PhabricatorRepositoryTransaction::TYPE_SYMBOLS_LANGUAGE:
|
||||
case PhabricatorRepositoryTransaction::TYPE_STAGING_URI:
|
||||
PhabricatorPolicyFilter::requireCapability(
|
||||
$this->requireActor(),
|
||||
$object,
|
||||
|
|
|
@ -241,8 +241,8 @@ final class PhabricatorRepositoryManagementReparseWorkflow
|
|||
'**NOTE**: This script will queue tasks to reparse the data. Once the '.
|
||||
'tasks have been queued, you need to run Taskmaster daemons to '.
|
||||
'execute them.'."\n\n".
|
||||
"QUEUEING TASKS (%d Commits):",
|
||||
number_format(count($commits))));
|
||||
"QUEUEING TASKS (%s Commits):",
|
||||
new PhutilNumber(count($commits))));
|
||||
}
|
||||
|
||||
$progress = new PhutilConsoleProgressBar();
|
||||
|
|
|
@ -135,6 +135,12 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
|||
'isActive' => $this->isTracked(),
|
||||
'isHosted' => $this->isHosted(),
|
||||
'isImporting' => $this->isImporting(),
|
||||
'encoding' => $this->getDetail('encoding'),
|
||||
'staging' => array(
|
||||
'supported' => $this->supportsStaging(),
|
||||
'prefix' => 'phabricator',
|
||||
'uri' => $this->getStagingURI(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1796,6 +1802,22 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
|||
}
|
||||
|
||||
|
||||
/* -( Staging )-------------------------------------------------------------*/
|
||||
|
||||
|
||||
public function supportsStaging() {
|
||||
return $this->isGit();
|
||||
}
|
||||
|
||||
|
||||
public function getStagingURI() {
|
||||
if (!$this->supportsStaging()) {
|
||||
return null;
|
||||
}
|
||||
return $this->getDetail('staging-uri', null);
|
||||
}
|
||||
|
||||
|
||||
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
|
||||
|
||||
|
||||
|
|
|
@ -349,9 +349,7 @@ final class PhabricatorRepositoryCommit
|
|||
|
||||
|
||||
public function getCustomFieldSpecificationForRole($role) {
|
||||
// TODO: We could make this configurable eventually, but just use the
|
||||
// defaults for now.
|
||||
return array();
|
||||
return PhabricatorEnv::getEnvConfig('diffusion.fields');
|
||||
}
|
||||
|
||||
public function getCustomFieldBaseClass() {
|
||||
|
|
|
@ -27,6 +27,7 @@ final class PhabricatorRepositoryTransaction
|
|||
const TYPE_SERVICE = 'repo:service';
|
||||
const TYPE_SYMBOLS_SOURCES = 'repo:symbol-source';
|
||||
const TYPE_SYMBOLS_LANGUAGE = 'repo:symbol-language';
|
||||
const TYPE_STAGING_URI = 'repo:staging-uri';
|
||||
|
||||
// TODO: Clean up these legacy transaction types.
|
||||
const TYPE_SSH_LOGIN = 'repo:ssh-login';
|
||||
|
@ -412,9 +413,29 @@ final class PhabricatorRepositoryTransaction
|
|||
|
||||
case self::TYPE_SYMBOLS_LANGUAGE:
|
||||
return pht('%s changed indexed languages from %s to %s.',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$old ? implode(', ', $old) : pht('Any'),
|
||||
$new ? implode(', ', $new) : pht('Any'));
|
||||
|
||||
case self::TYPE_STAGING_URI:
|
||||
if (!$old) {
|
||||
return pht(
|
||||
'%s set "%s" as the staging area for this repository.',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$old ? implode(', ', $old) : pht('Any'),
|
||||
$new ? implode(', ', $new) : pht('Any'));
|
||||
$new);
|
||||
} else if (!$new) {
|
||||
return pht(
|
||||
'%s removed "%s" as the staging area for this repository.',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$old);
|
||||
} else {
|
||||
return pht(
|
||||
'%s changed the staging area for this repository from '.
|
||||
'"%s" to "%s".',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$old,
|
||||
$new);
|
||||
}
|
||||
}
|
||||
|
||||
return parent::getTitle();
|
||||
|
|
|
@ -1,108 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorOwnersPackagePathValidator {
|
||||
|
||||
/*
|
||||
* If a file/directory was moved the paths in owners package become stale.
|
||||
* This method updates the stale paths in the owners packages to their new
|
||||
* paths.
|
||||
*/
|
||||
public static function updateOwnersPackagePaths(
|
||||
PhabricatorRepositoryCommit $commit,
|
||||
PhabricatorUser $actor) {
|
||||
|
||||
$repository = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer($actor)
|
||||
->withIDs(array($commit->getRepositoryID()))
|
||||
->executeOne();
|
||||
if (!$repository) {
|
||||
return;
|
||||
}
|
||||
$changes = self::loadDiffusionChangesForCommit(
|
||||
$repository,
|
||||
$commit,
|
||||
$actor);
|
||||
|
||||
if (!$changes) {
|
||||
return;
|
||||
}
|
||||
|
||||
$move_map = array();
|
||||
foreach ($changes as $change) {
|
||||
if ($change->getChangeType() == DifferentialChangeType::TYPE_MOVE_HERE) {
|
||||
$from_path = '/'.$change->getTargetPath();
|
||||
$to_path = '/'.$change->getPath();
|
||||
if ($change->getFileType() == DifferentialChangeType::FILE_DIRECTORY) {
|
||||
$to_path = $to_path.'/';
|
||||
$from_path = $from_path.'/';
|
||||
}
|
||||
$move_map[$from_path] = $to_path;
|
||||
}
|
||||
}
|
||||
|
||||
if ($move_map) {
|
||||
self::updateAffectedPackages($repository, $move_map);
|
||||
}
|
||||
}
|
||||
|
||||
private static function updateAffectedPackages($repository, array $move_map) {
|
||||
$paths = array_keys($move_map);
|
||||
if ($paths) {
|
||||
$packages = PhabricatorOwnersPackage::loadAffectedPackages($repository,
|
||||
$paths);
|
||||
foreach ($packages as $package) {
|
||||
self::updatePackagePaths($package, $move_map);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static function updatePackagePaths($package, array $move_map) {
|
||||
$paths = array_keys($move_map);
|
||||
$pkg_paths = $package->loadPaths();
|
||||
$new_paths = array();
|
||||
foreach ($pkg_paths as $pkg_path) {
|
||||
$path_changed = false;
|
||||
|
||||
foreach ($paths as $old_path) {
|
||||
if (strncmp($pkg_path->getPath(), $old_path, strlen($old_path)) === 0) {
|
||||
$new_paths[] = array (
|
||||
'packageID' => $package->getID(),
|
||||
'repositoryPHID' => $pkg_path->getRepositoryPHID(),
|
||||
'path' => str_replace($pkg_path->getPath(), $old_path,
|
||||
$move_map[$old_path]),
|
||||
);
|
||||
$path_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$path_changed) {
|
||||
$new_paths[] = array (
|
||||
'packageID' => $package->getID(),
|
||||
'repositoryPHID' => $pkg_path->getRepositoryPHID(),
|
||||
'path' => $pkg_path->getPath(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ($new_paths) {
|
||||
$package->attachOldPrimaryOwnerPHID($package->getPrimaryOwnerPHID());
|
||||
$package->attachUnsavedPaths($new_paths);
|
||||
$package->save(); // save the changes and notify the owners.
|
||||
}
|
||||
}
|
||||
|
||||
private static function loadDiffusionChangesForCommit(
|
||||
PhabricatorRepository $repository,
|
||||
PhabricatorRepositoryCommit $commit,
|
||||
PhabricatorUser $actor) {
|
||||
$data = array(
|
||||
'user' => $actor,
|
||||
'repository' => $repository,
|
||||
'commit' => $commit->getCommitIdentifier(),
|
||||
);
|
||||
$drequest = DiffusionRequest::newFromDictionary($data);
|
||||
$change_query =
|
||||
DiffusionPathChangeQuery::newFromDiffusionRequest($drequest);
|
||||
return $change_query->loadChanges();
|
||||
}
|
||||
}
|
|
@ -96,9 +96,6 @@ abstract class PhabricatorRepositoryCommitChangeParserWorker
|
|||
id(new PhabricatorSearchIndexer())
|
||||
->queueDocumentForIndexing($commit->getPHID());
|
||||
|
||||
PhabricatorOwnersPackagePathValidator::updateOwnersPackagePaths(
|
||||
$commit,
|
||||
PhabricatorUser::getOmnipotentUser());
|
||||
if ($this->shouldQueueFollowupTasks()) {
|
||||
$this->queueTask(
|
||||
'PhabricatorRepositoryCommitOwnersWorker',
|
||||
|
|
|
@ -49,10 +49,6 @@ Other options include:
|
|||
See below for details about path resolution, or see
|
||||
@{article:libphutil Libraries User Guide} for a general introduction to
|
||||
libphutil libraries.
|
||||
- **project.name**: name an "Arcanist Project" to associate this working
|
||||
copy (Git, Mercurial) or directory (SVN) with. Previously, this was a
|
||||
required option, but `arc` can now usually operate without it in Git and
|
||||
Mercurial. This option was previously called `project_id`.
|
||||
- **https.cabundle**: specifies the path to an alternate certificate bundle
|
||||
for use when making HTTPS connections.
|
||||
- **lint.engine**: the name of a subclass of
|
||||
|
|
|
@ -44,12 +44,9 @@ Create a `.arcconfig` file in your project's working copy:
|
|||
yourproject/ $ $EDITOR .arcconfig
|
||||
yourproject/ $ cat .arcconfig
|
||||
{
|
||||
"project.name" : "yourprojectname",
|
||||
"phabricator.uri" : "https://phabricator.example.com/"
|
||||
}
|
||||
|
||||
Set `project.name` to a string that identifies the project.
|
||||
|
||||
Set `phabricator.uri` to the URI for your Phabricator install (where `arc`
|
||||
should send changes to).
|
||||
|
||||
|
|
|
@ -83,8 +83,7 @@ Phabricator. For example, you might write this file to
|
|||
`libcustom/.arcconfig`:
|
||||
|
||||
{
|
||||
"project.name" : "libcustom",
|
||||
"load" : [
|
||||
"load": [
|
||||
"phabricator/src/"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -12,9 +12,6 @@ final class PhabricatorCustomFieldConfigOptionType
|
|||
$storage_value = $request->getStr('value');
|
||||
|
||||
$in_value = phutil_json_decode($storage_value);
|
||||
if (!is_array($in_value)) {
|
||||
$in_value = array();
|
||||
}
|
||||
|
||||
// When we submit from JS, we submit a list (since maps are not guaranteed
|
||||
// to retain order). Convert it into a map for storage (since it's far more
|
||||
|
@ -37,20 +34,16 @@ final class PhabricatorCustomFieldConfigOptionType
|
|||
$field_spec = PhabricatorEnv::getEnvConfig($option->getKey());
|
||||
}
|
||||
|
||||
// Get all of the fields (including disabled fields) by querying for them
|
||||
// with a faux spec where no fields are disabled.
|
||||
$faux_spec = $field_spec;
|
||||
foreach ($faux_spec as $key => $spec) {
|
||||
unset($faux_spec[$key]['disabled']);
|
||||
}
|
||||
|
||||
// TODO: We might need to build a real object here eventually.
|
||||
$faux_object = null;
|
||||
|
||||
$fields = PhabricatorCustomField::buildFieldList(
|
||||
$field_base_class,
|
||||
$faux_spec,
|
||||
$faux_object);
|
||||
$field_spec,
|
||||
$faux_object,
|
||||
array(
|
||||
'withDisabled' => true,
|
||||
));
|
||||
|
||||
$list_id = celerity_generate_unique_node_id();
|
||||
$input_id = celerity_generate_unique_node_id();
|
||||
|
@ -66,7 +59,8 @@ final class PhabricatorCustomFieldConfigOptionType
|
|||
->addAttribute($field->getFieldDescription())
|
||||
->setHeader($field->getFieldName());
|
||||
|
||||
$is_disabled = !empty($field_spec[$key]['disabled']);
|
||||
$spec = idx($field_spec, $key, array());
|
||||
$is_disabled = idx($spec, 'disabled', $field->shouldDisableByDefault());
|
||||
|
||||
$disabled_item = clone $item;
|
||||
$enabled_item = clone $item;
|
||||
|
@ -113,7 +107,7 @@ final class PhabricatorCustomFieldConfigOptionType
|
|||
'id' => $input_id,
|
||||
'type' => 'hidden',
|
||||
'name' => 'value',
|
||||
'value' => json_encode($display_value),
|
||||
'value' => '',
|
||||
));
|
||||
|
||||
Javelin::initBehavior(
|
||||
|
|
|
@ -105,7 +105,18 @@ abstract class PhabricatorCustomField {
|
|||
/**
|
||||
* @task apps
|
||||
*/
|
||||
public static function buildFieldList($base_class, array $spec, $object) {
|
||||
public static function buildFieldList(
|
||||
$base_class,
|
||||
array $spec,
|
||||
$object,
|
||||
array $options = array()) {
|
||||
|
||||
PhutilTypeSpec::checkMap(
|
||||
$options,
|
||||
array(
|
||||
'withDisabled' => 'optional bool',
|
||||
));
|
||||
|
||||
$field_objects = id(new PhutilSymbolLoader())
|
||||
->setAncestorClass($base_class)
|
||||
->loadObjects();
|
||||
|
@ -135,13 +146,16 @@ abstract class PhabricatorCustomField {
|
|||
|
||||
$fields = array_select_keys($fields, array_keys($spec)) + $fields;
|
||||
|
||||
foreach ($spec as $key => $config) {
|
||||
if (empty($fields[$key])) {
|
||||
continue;
|
||||
}
|
||||
if (!empty($config['disabled'])) {
|
||||
if ($fields[$key]->canDisableField()) {
|
||||
unset($fields[$key]);
|
||||
if (empty($options['withDisabled'])) {
|
||||
foreach ($fields as $key => $field) {
|
||||
$config = idx($spec, $key, array()) + array(
|
||||
'disabled' => $field->shouldDisableByDefault(),
|
||||
);
|
||||
|
||||
if (!empty($config['disabled'])) {
|
||||
if ($field->canDisableField()) {
|
||||
unset($fields[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1055,22 +1069,6 @@ abstract class PhabricatorCustomField {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: this is only used by Diffusion right now and everything is completely
|
||||
* faked since Diffusion doesn't use ApplicationTransactions yet. This should
|
||||
* get fleshed out as we have more use cases.
|
||||
*
|
||||
* @task appxaction
|
||||
*/
|
||||
public function buildApplicationTransactionMailBody(
|
||||
PhabricatorApplicationTransaction $xaction,
|
||||
PhabricatorMetaMTAMailBody $body) {
|
||||
if ($this->proxy) {
|
||||
return $this->proxy->buildApplicationTransactionMailBody($xaction, $body);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* -( Transaction Mail )--------------------------------------------------- */
|
||||
|
||||
|
|
|
@ -15,6 +15,14 @@ abstract class PhabricatorInlineCommentController
|
|||
abstract protected function saveComment(
|
||||
PhabricatorInlineCommentInterface $inline);
|
||||
|
||||
protected function hideComments(array $ids) {
|
||||
throw new PhutilMethodNotImplementedException();
|
||||
}
|
||||
|
||||
protected function showComments(array $ids) {
|
||||
throw new PhutilMethodNotImplementedException();
|
||||
}
|
||||
|
||||
private $changesetID;
|
||||
private $isNewFile;
|
||||
private $isOnRight;
|
||||
|
@ -84,6 +92,22 @@ abstract class PhabricatorInlineCommentController
|
|||
|
||||
$op = $this->getOperation();
|
||||
switch ($op) {
|
||||
case 'hide':
|
||||
case 'show':
|
||||
if (!$request->validateCSRF()) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$ids = $request->getStrList('ids');
|
||||
if ($ids) {
|
||||
if ($op == 'hide') {
|
||||
$this->hideComments($ids);
|
||||
} else {
|
||||
$this->showComments($ids);
|
||||
}
|
||||
}
|
||||
|
||||
return id(new AphrontAjaxResponse())->setContent(array());
|
||||
case 'done':
|
||||
if (!$request->validateCSRF()) {
|
||||
return new Aphront404Response();
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue