mirror of
https://we.phorge.it/source/phorge.git
synced 2025-01-10 14:51:06 +01:00
(stable) Promote 2018 Week 35
This commit is contained in:
commit
b0130f6d4e
93 changed files with 1544 additions and 681 deletions
|
@ -9,8 +9,8 @@ return array(
|
||||||
'names' => array(
|
'names' => array(
|
||||||
'conpherence.pkg.css' => 'e68cf1fa',
|
'conpherence.pkg.css' => 'e68cf1fa',
|
||||||
'conpherence.pkg.js' => '15191c65',
|
'conpherence.pkg.js' => '15191c65',
|
||||||
'core.pkg.css' => 'fc4839c8',
|
'core.pkg.css' => 'badf3f16',
|
||||||
'core.pkg.js' => '2058ec09',
|
'core.pkg.js' => 'b5a949ca',
|
||||||
'differential.pkg.css' => '06dc617c',
|
'differential.pkg.css' => '06dc617c',
|
||||||
'differential.pkg.js' => 'c1cfa143',
|
'differential.pkg.js' => 'c1cfa143',
|
||||||
'diffusion.pkg.css' => 'a2d17c7d',
|
'diffusion.pkg.css' => 'a2d17c7d',
|
||||||
|
@ -75,7 +75,7 @@ return array(
|
||||||
'rsrc/css/application/feed/feed.css' => 'ecd4ec57',
|
'rsrc/css/application/feed/feed.css' => 'ecd4ec57',
|
||||||
'rsrc/css/application/files/global-drag-and-drop.css' => 'b556a948',
|
'rsrc/css/application/files/global-drag-and-drop.css' => 'b556a948',
|
||||||
'rsrc/css/application/flag/flag.css' => 'bba8f811',
|
'rsrc/css/application/flag/flag.css' => 'bba8f811',
|
||||||
'rsrc/css/application/harbormaster/harbormaster.css' => '730a4a3c',
|
'rsrc/css/application/harbormaster/harbormaster.css' => '7446ce72',
|
||||||
'rsrc/css/application/herald/herald-test.css' => 'a52e323e',
|
'rsrc/css/application/herald/herald-test.css' => 'a52e323e',
|
||||||
'rsrc/css/application/herald/herald.css' => 'cd8d0134',
|
'rsrc/css/application/herald/herald.css' => 'cd8d0134',
|
||||||
'rsrc/css/application/maniphest/report.css' => '9b9580b7',
|
'rsrc/css/application/maniphest/report.css' => '9b9580b7',
|
||||||
|
@ -146,15 +146,15 @@ return array(
|
||||||
'rsrc/css/phui/phui-comment-panel.css' => 'f50152ad',
|
'rsrc/css/phui/phui-comment-panel.css' => 'f50152ad',
|
||||||
'rsrc/css/phui/phui-crumbs-view.css' => '10728aaa',
|
'rsrc/css/phui/phui-crumbs-view.css' => '10728aaa',
|
||||||
'rsrc/css/phui/phui-curtain-view.css' => '2bdaf026',
|
'rsrc/css/phui/phui-curtain-view.css' => '2bdaf026',
|
||||||
'rsrc/css/phui/phui-document-pro.css' => '8af7ea27',
|
'rsrc/css/phui/phui-document-pro.css' => '0e41dd91',
|
||||||
'rsrc/css/phui/phui-document-summary.css' => '9ca48bdf',
|
'rsrc/css/phui/phui-document-summary.css' => '9ca48bdf',
|
||||||
'rsrc/css/phui/phui-document.css' => '878c2f52',
|
'rsrc/css/phui/phui-document.css' => 'c4ac41f9',
|
||||||
'rsrc/css/phui/phui-feed-story.css' => '44a9c8e9',
|
'rsrc/css/phui/phui-feed-story.css' => '44a9c8e9',
|
||||||
'rsrc/css/phui/phui-fontkit.css' => '1320ed01',
|
'rsrc/css/phui/phui-fontkit.css' => '1320ed01',
|
||||||
'rsrc/css/phui/phui-form-view.css' => 'f808e5be',
|
'rsrc/css/phui/phui-form-view.css' => 'f808e5be',
|
||||||
'rsrc/css/phui/phui-form.css' => '7aaa04e3',
|
'rsrc/css/phui/phui-form.css' => '7aaa04e3',
|
||||||
'rsrc/css/phui/phui-head-thing.css' => 'fd311e5f',
|
'rsrc/css/phui/phui-head-thing.css' => 'fd311e5f',
|
||||||
'rsrc/css/phui/phui-header-view.css' => 'edeb9252',
|
'rsrc/css/phui/phui-header-view.css' => '1ba8b707',
|
||||||
'rsrc/css/phui/phui-hovercard.css' => 'f0592bcf',
|
'rsrc/css/phui/phui-hovercard.css' => 'f0592bcf',
|
||||||
'rsrc/css/phui/phui-icon-set-selector.css' => '87db8fee',
|
'rsrc/css/phui/phui-icon-set-selector.css' => '87db8fee',
|
||||||
'rsrc/css/phui/phui-icon.css' => 'cf24ceec',
|
'rsrc/css/phui/phui-icon.css' => 'cf24ceec',
|
||||||
|
@ -473,7 +473,7 @@ return array(
|
||||||
'rsrc/js/core/behavior-more.js' => 'a80d0378',
|
'rsrc/js/core/behavior-more.js' => 'a80d0378',
|
||||||
'rsrc/js/core/behavior-object-selector.js' => '77c1f0b0',
|
'rsrc/js/core/behavior-object-selector.js' => '77c1f0b0',
|
||||||
'rsrc/js/core/behavior-oncopy.js' => '2926fff2',
|
'rsrc/js/core/behavior-oncopy.js' => '2926fff2',
|
||||||
'rsrc/js/core/behavior-phabricator-nav.js' => '94b7c320',
|
'rsrc/js/core/behavior-phabricator-nav.js' => '9d32bc88',
|
||||||
'rsrc/js/core/behavior-phabricator-remarkup-assist.js' => 'acd29eee',
|
'rsrc/js/core/behavior-phabricator-remarkup-assist.js' => 'acd29eee',
|
||||||
'rsrc/js/core/behavior-read-only-warning.js' => 'ba158207',
|
'rsrc/js/core/behavior-read-only-warning.js' => 'ba158207',
|
||||||
'rsrc/js/core/behavior-redirect.js' => '0213259f',
|
'rsrc/js/core/behavior-redirect.js' => '0213259f',
|
||||||
|
@ -554,7 +554,7 @@ return array(
|
||||||
'font-fontawesome' => 'e838e088',
|
'font-fontawesome' => 'e838e088',
|
||||||
'font-lato' => 'c7ccd872',
|
'font-lato' => 'c7ccd872',
|
||||||
'global-drag-and-drop-css' => 'b556a948',
|
'global-drag-and-drop-css' => 'b556a948',
|
||||||
'harbormaster-css' => '730a4a3c',
|
'harbormaster-css' => '7446ce72',
|
||||||
'herald-css' => 'cd8d0134',
|
'herald-css' => 'cd8d0134',
|
||||||
'herald-rule-editor' => 'dca75c0e',
|
'herald-rule-editor' => 'dca75c0e',
|
||||||
'herald-test-css' => 'a52e323e',
|
'herald-test-css' => 'a52e323e',
|
||||||
|
@ -631,7 +631,7 @@ return array(
|
||||||
'javelin-behavior-phabricator-keyboard-pager' => 'a8da01f0',
|
'javelin-behavior-phabricator-keyboard-pager' => 'a8da01f0',
|
||||||
'javelin-behavior-phabricator-keyboard-shortcuts' => '01fca1f0',
|
'javelin-behavior-phabricator-keyboard-shortcuts' => '01fca1f0',
|
||||||
'javelin-behavior-phabricator-line-linker' => '66a62306',
|
'javelin-behavior-phabricator-line-linker' => '66a62306',
|
||||||
'javelin-behavior-phabricator-nav' => '94b7c320',
|
'javelin-behavior-phabricator-nav' => '9d32bc88',
|
||||||
'javelin-behavior-phabricator-notification-example' => '8ce821c5',
|
'javelin-behavior-phabricator-notification-example' => '8ce821c5',
|
||||||
'javelin-behavior-phabricator-object-selector' => '77c1f0b0',
|
'javelin-behavior-phabricator-object-selector' => '77c1f0b0',
|
||||||
'javelin-behavior-phabricator-oncopy' => '2926fff2',
|
'javelin-behavior-phabricator-oncopy' => '2926fff2',
|
||||||
|
@ -813,15 +813,15 @@ return array(
|
||||||
'phui-crumbs-view-css' => '10728aaa',
|
'phui-crumbs-view-css' => '10728aaa',
|
||||||
'phui-curtain-view-css' => '2bdaf026',
|
'phui-curtain-view-css' => '2bdaf026',
|
||||||
'phui-document-summary-view-css' => '9ca48bdf',
|
'phui-document-summary-view-css' => '9ca48bdf',
|
||||||
'phui-document-view-css' => '878c2f52',
|
'phui-document-view-css' => 'c4ac41f9',
|
||||||
'phui-document-view-pro-css' => '8af7ea27',
|
'phui-document-view-pro-css' => '0e41dd91',
|
||||||
'phui-feed-story-css' => '44a9c8e9',
|
'phui-feed-story-css' => '44a9c8e9',
|
||||||
'phui-font-icon-base-css' => '870a7360',
|
'phui-font-icon-base-css' => '870a7360',
|
||||||
'phui-fontkit-css' => '1320ed01',
|
'phui-fontkit-css' => '1320ed01',
|
||||||
'phui-form-css' => '7aaa04e3',
|
'phui-form-css' => '7aaa04e3',
|
||||||
'phui-form-view-css' => 'f808e5be',
|
'phui-form-view-css' => 'f808e5be',
|
||||||
'phui-head-thing-view-css' => 'fd311e5f',
|
'phui-head-thing-view-css' => 'fd311e5f',
|
||||||
'phui-header-view-css' => 'edeb9252',
|
'phui-header-view-css' => '1ba8b707',
|
||||||
'phui-hovercard' => '1bd28176',
|
'phui-hovercard' => '1bd28176',
|
||||||
'phui-hovercard-view-css' => 'f0592bcf',
|
'phui-hovercard-view-css' => 'f0592bcf',
|
||||||
'phui-icon-set-selector-css' => '87db8fee',
|
'phui-icon-set-selector-css' => '87db8fee',
|
||||||
|
@ -1628,16 +1628,6 @@ return array(
|
||||||
'javelin-resource',
|
'javelin-resource',
|
||||||
'javelin-routable',
|
'javelin-routable',
|
||||||
),
|
),
|
||||||
'94b7c320' => array(
|
|
||||||
'javelin-behavior',
|
|
||||||
'javelin-behavior-device',
|
|
||||||
'javelin-stratcom',
|
|
||||||
'javelin-dom',
|
|
||||||
'javelin-magical-init',
|
|
||||||
'javelin-vector',
|
|
||||||
'javelin-request',
|
|
||||||
'javelin-util',
|
|
||||||
),
|
|
||||||
'960f6a39' => array(
|
'960f6a39' => array(
|
||||||
'javelin-behavior',
|
'javelin-behavior',
|
||||||
'javelin-dom',
|
'javelin-dom',
|
||||||
|
@ -1658,6 +1648,16 @@ return array(
|
||||||
'javelin-workflow',
|
'javelin-workflow',
|
||||||
'javelin-stratcom',
|
'javelin-stratcom',
|
||||||
),
|
),
|
||||||
|
'9d32bc88' => array(
|
||||||
|
'javelin-behavior',
|
||||||
|
'javelin-behavior-device',
|
||||||
|
'javelin-stratcom',
|
||||||
|
'javelin-dom',
|
||||||
|
'javelin-magical-init',
|
||||||
|
'javelin-vector',
|
||||||
|
'javelin-request',
|
||||||
|
'javelin-util',
|
||||||
|
),
|
||||||
'9d9685d6' => array(
|
'9d9685d6' => array(
|
||||||
'phui-oi-list-view-css',
|
'phui-oi-list-view-css',
|
||||||
),
|
),
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_drydock.drydock_lease
|
||||||
|
ADD acquiredEpoch INT UNSIGNED;
|
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_drydock.drydock_lease
|
||||||
|
ADD activatedEpoch INT UNSIGNED;
|
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_phriction.phriction_document
|
||||||
|
ADD contentPHID VARBINARY(64) NOT NULL;
|
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_phriction.phriction_content
|
||||||
|
ADD documentPHID VARBINARY(64) NOT NULL;
|
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_phriction.phriction_document
|
||||||
|
ADD editedEpoch INT UNSIGNED NOT NULL;
|
57
resources/sql/autopatches/20180828.phriction.04.migrate.php
Normal file
57
resources/sql/autopatches/20180828.phriction.04.migrate.php
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// Update the PhrictionDocument and PhrictionContent tables to refer to one
|
||||||
|
// another by PHID instead of by ID.
|
||||||
|
|
||||||
|
$document_table = new PhrictionDocument();
|
||||||
|
$content_table = new PhrictionContent();
|
||||||
|
|
||||||
|
$conn = $document_table->establishConnection('w');
|
||||||
|
|
||||||
|
$document_iterator = new LiskRawMigrationIterator(
|
||||||
|
$conn,
|
||||||
|
$document_table->getTableName());
|
||||||
|
foreach ($document_iterator as $row) {
|
||||||
|
$content_id = $row['contentID'];
|
||||||
|
|
||||||
|
$content_row = queryfx_one(
|
||||||
|
$conn,
|
||||||
|
'SELECT phid, dateCreated FROM %T WHERE id = %d',
|
||||||
|
$content_table->getTableName(),
|
||||||
|
$content_id);
|
||||||
|
|
||||||
|
if (!$content_row) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
queryfx(
|
||||||
|
$conn,
|
||||||
|
'UPDATE %T SET contentPHID = %s, editedEpoch = %d WHERE id = %d',
|
||||||
|
$document_table->getTableName(),
|
||||||
|
$content_row['phid'],
|
||||||
|
$content_row['dateCreated'],
|
||||||
|
$row['id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$content_iterator = new LiskRawMigrationIterator(
|
||||||
|
$conn,
|
||||||
|
$content_table->getTableName());
|
||||||
|
foreach ($content_iterator as $row) {
|
||||||
|
$document_id = $row['documentID'];
|
||||||
|
|
||||||
|
$document_row = queryfx_one(
|
||||||
|
$conn,
|
||||||
|
'SELECT phid FROM %T WHERE id = %d',
|
||||||
|
$document_table->getTableName(),
|
||||||
|
$document_id);
|
||||||
|
if (!$document_row) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
queryfx(
|
||||||
|
$conn,
|
||||||
|
'UPDATE %T SET documentPHID = %s WHERE id = %d',
|
||||||
|
$content_table->getTableName(),
|
||||||
|
$document_row['phid'],
|
||||||
|
$row['id']);
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_phriction.phriction_document
|
||||||
|
DROP contentID;
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// See T13193. We're about to drop the "documentID" column, which is part of
|
||||||
|
// a UNIQUE KEY. In MariaDB, we must first drop the "documentID" key or we get
|
||||||
|
// into deep trouble.
|
||||||
|
|
||||||
|
// There's no "IF EXISTS" modifier for "ALTER TABLE" so run this as a PHP patch
|
||||||
|
// instead of an SQL patch.
|
||||||
|
|
||||||
|
$table = new PhrictionContent();
|
||||||
|
$conn = $table->establishConnection('w');
|
||||||
|
|
||||||
|
try {
|
||||||
|
queryfx(
|
||||||
|
$conn,
|
||||||
|
'ALTER TABLE %T DROP KEY documentID',
|
||||||
|
$table->getTableName());
|
||||||
|
} catch (AphrontQueryException $ex) {
|
||||||
|
// Ignore.
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_phriction.phriction_content
|
||||||
|
DROP documentID;
|
|
@ -0,0 +1 @@
|
||||||
|
DELETE FROM {$NAMESPACE}_phriction.phriction_content WHERE documentPHID = '';
|
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_phriction.phriction_content
|
||||||
|
ADD UNIQUE KEY `key_version` (documentPHID, version);
|
26
resources/sql/autopatches/20180829.phriction.01.mailkey.php
Normal file
26
resources/sql/autopatches/20180829.phriction.01.mailkey.php
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$document_table = new PhrictionDocument();
|
||||||
|
$document_conn = $document_table->establishConnection('w');
|
||||||
|
$document_name = $document_table->getTableName();
|
||||||
|
|
||||||
|
$properties_table = new PhabricatorMetaMTAMailProperties();
|
||||||
|
$conn = $properties_table->establishConnection('w');
|
||||||
|
|
||||||
|
$iterator = new LiskRawMigrationIterator($document_conn, $document_name);
|
||||||
|
foreach ($iterator as $row) {
|
||||||
|
queryfx(
|
||||||
|
$conn,
|
||||||
|
'INSERT IGNORE INTO %T
|
||||||
|
(objectPHID, mailProperties, dateCreated, dateModified)
|
||||||
|
VALUES
|
||||||
|
(%s, %s, %d, %d)',
|
||||||
|
$properties_table->getTableName(),
|
||||||
|
$row['phid'],
|
||||||
|
phutil_json_encode(
|
||||||
|
array(
|
||||||
|
'mailKey' => $row['mailKey'],
|
||||||
|
)),
|
||||||
|
PhabricatorTime::getNow(),
|
||||||
|
PhabricatorTime::getNow());
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_phriction.phriction_document
|
||||||
|
DROP mailKey;
|
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_phriction.phriction_document
|
||||||
|
ADD maxVersion INT UNSIGNED NOT NULL;
|
30
resources/sql/autopatches/20180830.phriction.02.maxes.php
Normal file
30
resources/sql/autopatches/20180830.phriction.02.maxes.php
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// Populate the "maxVersion" column by copying the maximum "version" from the
|
||||||
|
// content table.
|
||||||
|
|
||||||
|
$document_table = new PhrictionDocument();
|
||||||
|
$content_table = new PhrictionContent();
|
||||||
|
|
||||||
|
$conn = $document_table->establishConnection('w');
|
||||||
|
|
||||||
|
$iterator = new LiskRawMigrationIterator(
|
||||||
|
$conn,
|
||||||
|
$document_table->getTableName());
|
||||||
|
foreach ($iterator as $row) {
|
||||||
|
$content = queryfx_one(
|
||||||
|
$conn,
|
||||||
|
'SELECT MAX(version) max FROM %T WHERE documentPHID = %s',
|
||||||
|
$content_table->getTableName(),
|
||||||
|
$row['phid']);
|
||||||
|
if (!$content) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
queryfx(
|
||||||
|
$conn,
|
||||||
|
'UPDATE %T SET maxVersion = %d WHERE id = %d',
|
||||||
|
$document_table->getTableName(),
|
||||||
|
$content['max'],
|
||||||
|
$row['id']);
|
||||||
|
}
|
|
@ -644,6 +644,7 @@ phutil_register_library_map(array(
|
||||||
'DifferentialRevisionStatusTransaction' => 'applications/differential/xaction/DifferentialRevisionStatusTransaction.php',
|
'DifferentialRevisionStatusTransaction' => 'applications/differential/xaction/DifferentialRevisionStatusTransaction.php',
|
||||||
'DifferentialRevisionSummaryHeraldField' => 'applications/differential/herald/DifferentialRevisionSummaryHeraldField.php',
|
'DifferentialRevisionSummaryHeraldField' => 'applications/differential/herald/DifferentialRevisionSummaryHeraldField.php',
|
||||||
'DifferentialRevisionSummaryTransaction' => 'applications/differential/xaction/DifferentialRevisionSummaryTransaction.php',
|
'DifferentialRevisionSummaryTransaction' => 'applications/differential/xaction/DifferentialRevisionSummaryTransaction.php',
|
||||||
|
'DifferentialRevisionTestPlanHeraldField' => 'applications/differential/herald/DifferentialRevisionTestPlanHeraldField.php',
|
||||||
'DifferentialRevisionTestPlanTransaction' => 'applications/differential/xaction/DifferentialRevisionTestPlanTransaction.php',
|
'DifferentialRevisionTestPlanTransaction' => 'applications/differential/xaction/DifferentialRevisionTestPlanTransaction.php',
|
||||||
'DifferentialRevisionTitleHeraldField' => 'applications/differential/herald/DifferentialRevisionTitleHeraldField.php',
|
'DifferentialRevisionTitleHeraldField' => 'applications/differential/herald/DifferentialRevisionTitleHeraldField.php',
|
||||||
'DifferentialRevisionTitleTransaction' => 'applications/differential/xaction/DifferentialRevisionTitleTransaction.php',
|
'DifferentialRevisionTitleTransaction' => 'applications/differential/xaction/DifferentialRevisionTitleTransaction.php',
|
||||||
|
@ -1912,7 +1913,7 @@ phutil_register_library_map(array(
|
||||||
'PHUIDiffTableOfContentsListView' => 'infrastructure/diff/view/PHUIDiffTableOfContentsListView.php',
|
'PHUIDiffTableOfContentsListView' => 'infrastructure/diff/view/PHUIDiffTableOfContentsListView.php',
|
||||||
'PHUIDiffTwoUpInlineCommentRowScaffold' => 'infrastructure/diff/view/PHUIDiffTwoUpInlineCommentRowScaffold.php',
|
'PHUIDiffTwoUpInlineCommentRowScaffold' => 'infrastructure/diff/view/PHUIDiffTwoUpInlineCommentRowScaffold.php',
|
||||||
'PHUIDocumentSummaryView' => 'view/phui/PHUIDocumentSummaryView.php',
|
'PHUIDocumentSummaryView' => 'view/phui/PHUIDocumentSummaryView.php',
|
||||||
'PHUIDocumentViewPro' => 'view/phui/PHUIDocumentViewPro.php',
|
'PHUIDocumentView' => 'view/phui/PHUIDocumentView.php',
|
||||||
'PHUIFeedStoryExample' => 'applications/uiexample/examples/PHUIFeedStoryExample.php',
|
'PHUIFeedStoryExample' => 'applications/uiexample/examples/PHUIFeedStoryExample.php',
|
||||||
'PHUIFeedStoryView' => 'view/phui/PHUIFeedStoryView.php',
|
'PHUIFeedStoryView' => 'view/phui/PHUIFeedStoryView.php',
|
||||||
'PHUIFormDividerControl' => 'view/form/control/PHUIFormDividerControl.php',
|
'PHUIFormDividerControl' => 'view/form/control/PHUIFormDividerControl.php',
|
||||||
|
@ -2042,6 +2043,7 @@ phutil_register_library_map(array(
|
||||||
'PasteSearchConduitAPIMethod' => 'applications/paste/conduit/PasteSearchConduitAPIMethod.php',
|
'PasteSearchConduitAPIMethod' => 'applications/paste/conduit/PasteSearchConduitAPIMethod.php',
|
||||||
'PeopleBrowseUserDirectoryCapability' => 'applications/people/capability/PeopleBrowseUserDirectoryCapability.php',
|
'PeopleBrowseUserDirectoryCapability' => 'applications/people/capability/PeopleBrowseUserDirectoryCapability.php',
|
||||||
'PeopleCreateUsersCapability' => 'applications/people/capability/PeopleCreateUsersCapability.php',
|
'PeopleCreateUsersCapability' => 'applications/people/capability/PeopleCreateUsersCapability.php',
|
||||||
|
'PeopleDisableUsersCapability' => 'applications/people/capability/PeopleDisableUsersCapability.php',
|
||||||
'PeopleHovercardEngineExtension' => 'applications/people/engineextension/PeopleHovercardEngineExtension.php',
|
'PeopleHovercardEngineExtension' => 'applications/people/engineextension/PeopleHovercardEngineExtension.php',
|
||||||
'PeopleMainMenuBarExtension' => 'applications/people/engineextension/PeopleMainMenuBarExtension.php',
|
'PeopleMainMenuBarExtension' => 'applications/people/engineextension/PeopleMainMenuBarExtension.php',
|
||||||
'PeopleUserLogGarbageCollector' => 'applications/people/garbagecollector/PeopleUserLogGarbageCollector.php',
|
'PeopleUserLogGarbageCollector' => 'applications/people/garbagecollector/PeopleUserLogGarbageCollector.php',
|
||||||
|
@ -5028,6 +5030,7 @@ phutil_register_library_map(array(
|
||||||
'PhrictionDocumentPHIDType' => 'applications/phriction/phid/PhrictionDocumentPHIDType.php',
|
'PhrictionDocumentPHIDType' => 'applications/phriction/phid/PhrictionDocumentPHIDType.php',
|
||||||
'PhrictionDocumentPathHeraldField' => 'applications/phriction/herald/PhrictionDocumentPathHeraldField.php',
|
'PhrictionDocumentPathHeraldField' => 'applications/phriction/herald/PhrictionDocumentPathHeraldField.php',
|
||||||
'PhrictionDocumentPolicyCodex' => 'applications/phriction/codex/PhrictionDocumentPolicyCodex.php',
|
'PhrictionDocumentPolicyCodex' => 'applications/phriction/codex/PhrictionDocumentPolicyCodex.php',
|
||||||
|
'PhrictionDocumentPublishTransaction' => 'applications/phriction/xaction/PhrictionDocumentPublishTransaction.php',
|
||||||
'PhrictionDocumentQuery' => 'applications/phriction/query/PhrictionDocumentQuery.php',
|
'PhrictionDocumentQuery' => 'applications/phriction/query/PhrictionDocumentQuery.php',
|
||||||
'PhrictionDocumentSearchConduitAPIMethod' => 'applications/phriction/conduit/PhrictionDocumentSearchConduitAPIMethod.php',
|
'PhrictionDocumentSearchConduitAPIMethod' => 'applications/phriction/conduit/PhrictionDocumentSearchConduitAPIMethod.php',
|
||||||
'PhrictionDocumentSearchEngine' => 'applications/phriction/query/PhrictionDocumentSearchEngine.php',
|
'PhrictionDocumentSearchEngine' => 'applications/phriction/query/PhrictionDocumentSearchEngine.php',
|
||||||
|
@ -5035,6 +5038,7 @@ phutil_register_library_map(array(
|
||||||
'PhrictionDocumentTitleHeraldField' => 'applications/phriction/herald/PhrictionDocumentTitleHeraldField.php',
|
'PhrictionDocumentTitleHeraldField' => 'applications/phriction/herald/PhrictionDocumentTitleHeraldField.php',
|
||||||
'PhrictionDocumentTitleTransaction' => 'applications/phriction/xaction/PhrictionDocumentTitleTransaction.php',
|
'PhrictionDocumentTitleTransaction' => 'applications/phriction/xaction/PhrictionDocumentTitleTransaction.php',
|
||||||
'PhrictionDocumentTransactionType' => 'applications/phriction/xaction/PhrictionDocumentTransactionType.php',
|
'PhrictionDocumentTransactionType' => 'applications/phriction/xaction/PhrictionDocumentTransactionType.php',
|
||||||
|
'PhrictionDocumentVersionTransaction' => 'applications/phriction/xaction/PhrictionDocumentVersionTransaction.php',
|
||||||
'PhrictionEditConduitAPIMethod' => 'applications/phriction/conduit/PhrictionEditConduitAPIMethod.php',
|
'PhrictionEditConduitAPIMethod' => 'applications/phriction/conduit/PhrictionEditConduitAPIMethod.php',
|
||||||
'PhrictionEditController' => 'applications/phriction/controller/PhrictionEditController.php',
|
'PhrictionEditController' => 'applications/phriction/controller/PhrictionEditController.php',
|
||||||
'PhrictionHistoryConduitAPIMethod' => 'applications/phriction/conduit/PhrictionHistoryConduitAPIMethod.php',
|
'PhrictionHistoryConduitAPIMethod' => 'applications/phriction/conduit/PhrictionHistoryConduitAPIMethod.php',
|
||||||
|
@ -5044,6 +5048,7 @@ phutil_register_library_map(array(
|
||||||
'PhrictionMarkupPreviewController' => 'applications/phriction/controller/PhrictionMarkupPreviewController.php',
|
'PhrictionMarkupPreviewController' => 'applications/phriction/controller/PhrictionMarkupPreviewController.php',
|
||||||
'PhrictionMoveController' => 'applications/phriction/controller/PhrictionMoveController.php',
|
'PhrictionMoveController' => 'applications/phriction/controller/PhrictionMoveController.php',
|
||||||
'PhrictionNewController' => 'applications/phriction/controller/PhrictionNewController.php',
|
'PhrictionNewController' => 'applications/phriction/controller/PhrictionNewController.php',
|
||||||
|
'PhrictionPublishController' => 'applications/phriction/controller/PhrictionPublishController.php',
|
||||||
'PhrictionRemarkupRule' => 'applications/phriction/markup/PhrictionRemarkupRule.php',
|
'PhrictionRemarkupRule' => 'applications/phriction/markup/PhrictionRemarkupRule.php',
|
||||||
'PhrictionReplyHandler' => 'applications/phriction/mail/PhrictionReplyHandler.php',
|
'PhrictionReplyHandler' => 'applications/phriction/mail/PhrictionReplyHandler.php',
|
||||||
'PhrictionSchemaSpec' => 'applications/phriction/storage/PhrictionSchemaSpec.php',
|
'PhrictionSchemaSpec' => 'applications/phriction/storage/PhrictionSchemaSpec.php',
|
||||||
|
@ -6000,6 +6005,7 @@ phutil_register_library_map(array(
|
||||||
'DifferentialRevisionStatusTransaction' => 'DifferentialRevisionTransactionType',
|
'DifferentialRevisionStatusTransaction' => 'DifferentialRevisionTransactionType',
|
||||||
'DifferentialRevisionSummaryHeraldField' => 'DifferentialRevisionHeraldField',
|
'DifferentialRevisionSummaryHeraldField' => 'DifferentialRevisionHeraldField',
|
||||||
'DifferentialRevisionSummaryTransaction' => 'DifferentialRevisionTransactionType',
|
'DifferentialRevisionSummaryTransaction' => 'DifferentialRevisionTransactionType',
|
||||||
|
'DifferentialRevisionTestPlanHeraldField' => 'DifferentialRevisionHeraldField',
|
||||||
'DifferentialRevisionTestPlanTransaction' => 'DifferentialRevisionTransactionType',
|
'DifferentialRevisionTestPlanTransaction' => 'DifferentialRevisionTransactionType',
|
||||||
'DifferentialRevisionTitleHeraldField' => 'DifferentialRevisionHeraldField',
|
'DifferentialRevisionTitleHeraldField' => 'DifferentialRevisionHeraldField',
|
||||||
'DifferentialRevisionTitleTransaction' => 'DifferentialRevisionTransactionType',
|
'DifferentialRevisionTitleTransaction' => 'DifferentialRevisionTransactionType',
|
||||||
|
@ -7452,7 +7458,7 @@ phutil_register_library_map(array(
|
||||||
'PHUIDiffTableOfContentsListView' => 'AphrontView',
|
'PHUIDiffTableOfContentsListView' => 'AphrontView',
|
||||||
'PHUIDiffTwoUpInlineCommentRowScaffold' => 'PHUIDiffInlineCommentRowScaffold',
|
'PHUIDiffTwoUpInlineCommentRowScaffold' => 'PHUIDiffInlineCommentRowScaffold',
|
||||||
'PHUIDocumentSummaryView' => 'AphrontTagView',
|
'PHUIDocumentSummaryView' => 'AphrontTagView',
|
||||||
'PHUIDocumentViewPro' => 'AphrontTagView',
|
'PHUIDocumentView' => 'AphrontTagView',
|
||||||
'PHUIFeedStoryExample' => 'PhabricatorUIExample',
|
'PHUIFeedStoryExample' => 'PhabricatorUIExample',
|
||||||
'PHUIFeedStoryView' => 'AphrontView',
|
'PHUIFeedStoryView' => 'AphrontView',
|
||||||
'PHUIFormDividerControl' => 'AphrontFormControl',
|
'PHUIFormDividerControl' => 'AphrontFormControl',
|
||||||
|
@ -7592,6 +7598,7 @@ phutil_register_library_map(array(
|
||||||
'PasteSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod',
|
'PasteSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod',
|
||||||
'PeopleBrowseUserDirectoryCapability' => 'PhabricatorPolicyCapability',
|
'PeopleBrowseUserDirectoryCapability' => 'PhabricatorPolicyCapability',
|
||||||
'PeopleCreateUsersCapability' => 'PhabricatorPolicyCapability',
|
'PeopleCreateUsersCapability' => 'PhabricatorPolicyCapability',
|
||||||
|
'PeopleDisableUsersCapability' => 'PhabricatorPolicyCapability',
|
||||||
'PeopleHovercardEngineExtension' => 'PhabricatorHovercardEngineExtension',
|
'PeopleHovercardEngineExtension' => 'PhabricatorHovercardEngineExtension',
|
||||||
'PeopleMainMenuBarExtension' => 'PhabricatorMainMenuBarExtension',
|
'PeopleMainMenuBarExtension' => 'PhabricatorMainMenuBarExtension',
|
||||||
'PeopleUserLogGarbageCollector' => 'PhabricatorGarbageCollector',
|
'PeopleUserLogGarbageCollector' => 'PhabricatorGarbageCollector',
|
||||||
|
@ -8288,10 +8295,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorConfigManualActivity' => 'PhabricatorConfigEntryDAO',
|
'PhabricatorConfigManualActivity' => 'PhabricatorConfigEntryDAO',
|
||||||
'PhabricatorConfigModule' => 'Phobject',
|
'PhabricatorConfigModule' => 'Phobject',
|
||||||
'PhabricatorConfigModuleController' => 'PhabricatorConfigController',
|
'PhabricatorConfigModuleController' => 'PhabricatorConfigController',
|
||||||
'PhabricatorConfigOption' => array(
|
'PhabricatorConfigOption' => 'Phobject',
|
||||||
'Phobject',
|
|
||||||
'PhabricatorMarkupInterface',
|
|
||||||
),
|
|
||||||
'PhabricatorConfigOptionType' => 'Phobject',
|
'PhabricatorConfigOptionType' => 'Phobject',
|
||||||
'PhabricatorConfigPHIDModule' => 'PhabricatorConfigModule',
|
'PhabricatorConfigPHIDModule' => 'PhabricatorConfigModule',
|
||||||
'PhabricatorConfigProxySource' => 'PhabricatorConfigSource',
|
'PhabricatorConfigProxySource' => 'PhabricatorConfigSource',
|
||||||
|
@ -11130,27 +11134,29 @@ phutil_register_library_map(array(
|
||||||
),
|
),
|
||||||
'PhrictionDocumentAuthorHeraldField' => 'PhrictionDocumentHeraldField',
|
'PhrictionDocumentAuthorHeraldField' => 'PhrictionDocumentHeraldField',
|
||||||
'PhrictionDocumentContentHeraldField' => 'PhrictionDocumentHeraldField',
|
'PhrictionDocumentContentHeraldField' => 'PhrictionDocumentHeraldField',
|
||||||
'PhrictionDocumentContentTransaction' => 'PhrictionDocumentTransactionType',
|
'PhrictionDocumentContentTransaction' => 'PhrictionDocumentVersionTransaction',
|
||||||
'PhrictionDocumentController' => 'PhrictionController',
|
'PhrictionDocumentController' => 'PhrictionController',
|
||||||
'PhrictionDocumentDatasource' => 'PhabricatorTypeaheadDatasource',
|
'PhrictionDocumentDatasource' => 'PhabricatorTypeaheadDatasource',
|
||||||
'PhrictionDocumentDeleteTransaction' => 'PhrictionDocumentTransactionType',
|
'PhrictionDocumentDeleteTransaction' => 'PhrictionDocumentVersionTransaction',
|
||||||
'PhrictionDocumentFerretEngine' => 'PhabricatorFerretEngine',
|
'PhrictionDocumentFerretEngine' => 'PhabricatorFerretEngine',
|
||||||
'PhrictionDocumentFulltextEngine' => 'PhabricatorFulltextEngine',
|
'PhrictionDocumentFulltextEngine' => 'PhabricatorFulltextEngine',
|
||||||
'PhrictionDocumentHeraldAdapter' => 'HeraldAdapter',
|
'PhrictionDocumentHeraldAdapter' => 'HeraldAdapter',
|
||||||
'PhrictionDocumentHeraldField' => 'HeraldField',
|
'PhrictionDocumentHeraldField' => 'HeraldField',
|
||||||
'PhrictionDocumentHeraldFieldGroup' => 'HeraldFieldGroup',
|
'PhrictionDocumentHeraldFieldGroup' => 'HeraldFieldGroup',
|
||||||
'PhrictionDocumentMoveAwayTransaction' => 'PhrictionDocumentTransactionType',
|
'PhrictionDocumentMoveAwayTransaction' => 'PhrictionDocumentVersionTransaction',
|
||||||
'PhrictionDocumentMoveToTransaction' => 'PhrictionDocumentTransactionType',
|
'PhrictionDocumentMoveToTransaction' => 'PhrictionDocumentVersionTransaction',
|
||||||
'PhrictionDocumentPHIDType' => 'PhabricatorPHIDType',
|
'PhrictionDocumentPHIDType' => 'PhabricatorPHIDType',
|
||||||
'PhrictionDocumentPathHeraldField' => 'PhrictionDocumentHeraldField',
|
'PhrictionDocumentPathHeraldField' => 'PhrictionDocumentHeraldField',
|
||||||
'PhrictionDocumentPolicyCodex' => 'PhabricatorPolicyCodex',
|
'PhrictionDocumentPolicyCodex' => 'PhabricatorPolicyCodex',
|
||||||
|
'PhrictionDocumentPublishTransaction' => 'PhrictionDocumentTransactionType',
|
||||||
'PhrictionDocumentQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
'PhrictionDocumentQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
'PhrictionDocumentSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod',
|
'PhrictionDocumentSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod',
|
||||||
'PhrictionDocumentSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
'PhrictionDocumentSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||||
'PhrictionDocumentStatus' => 'PhabricatorObjectStatus',
|
'PhrictionDocumentStatus' => 'PhabricatorObjectStatus',
|
||||||
'PhrictionDocumentTitleHeraldField' => 'PhrictionDocumentHeraldField',
|
'PhrictionDocumentTitleHeraldField' => 'PhrictionDocumentHeraldField',
|
||||||
'PhrictionDocumentTitleTransaction' => 'PhrictionDocumentTransactionType',
|
'PhrictionDocumentTitleTransaction' => 'PhrictionDocumentVersionTransaction',
|
||||||
'PhrictionDocumentTransactionType' => 'PhabricatorModularTransactionType',
|
'PhrictionDocumentTransactionType' => 'PhabricatorModularTransactionType',
|
||||||
|
'PhrictionDocumentVersionTransaction' => 'PhrictionDocumentTransactionType',
|
||||||
'PhrictionEditConduitAPIMethod' => 'PhrictionConduitAPIMethod',
|
'PhrictionEditConduitAPIMethod' => 'PhrictionConduitAPIMethod',
|
||||||
'PhrictionEditController' => 'PhrictionController',
|
'PhrictionEditController' => 'PhrictionController',
|
||||||
'PhrictionHistoryConduitAPIMethod' => 'PhrictionConduitAPIMethod',
|
'PhrictionHistoryConduitAPIMethod' => 'PhrictionConduitAPIMethod',
|
||||||
|
@ -11160,6 +11166,7 @@ phutil_register_library_map(array(
|
||||||
'PhrictionMarkupPreviewController' => 'PhabricatorController',
|
'PhrictionMarkupPreviewController' => 'PhabricatorController',
|
||||||
'PhrictionMoveController' => 'PhrictionController',
|
'PhrictionMoveController' => 'PhrictionController',
|
||||||
'PhrictionNewController' => 'PhrictionController',
|
'PhrictionNewController' => 'PhrictionController',
|
||||||
|
'PhrictionPublishController' => 'PhrictionController',
|
||||||
'PhrictionRemarkupRule' => 'PhutilRemarkupRule',
|
'PhrictionRemarkupRule' => 'PhutilRemarkupRule',
|
||||||
'PhrictionReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler',
|
'PhrictionReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler',
|
||||||
'PhrictionSchemaSpec' => 'PhabricatorConfigSchemaSpec',
|
'PhrictionSchemaSpec' => 'PhabricatorConfigSchemaSpec',
|
||||||
|
|
|
@ -153,30 +153,16 @@ final class PhabricatorConfigEditController
|
||||||
$e_value);
|
$e_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
$engine = new PhabricatorMarkupEngine();
|
|
||||||
$engine->setViewer($viewer);
|
|
||||||
$engine->addObject($option, 'description');
|
|
||||||
$engine->process();
|
|
||||||
$description = phutil_tag(
|
|
||||||
'div',
|
|
||||||
array(
|
|
||||||
'class' => 'phabricator-remarkup',
|
|
||||||
),
|
|
||||||
$engine->getOutput($option, 'description'));
|
|
||||||
|
|
||||||
$form
|
$form
|
||||||
->setUser($viewer)
|
->setUser($viewer)
|
||||||
->addHiddenInput('issue', $request->getStr('issue'));
|
->addHiddenInput('issue', $request->getStr('issue'));
|
||||||
|
|
||||||
$description = $option->getDescription();
|
$description = $option->newDescriptionRemarkupView($viewer);
|
||||||
if (strlen($description)) {
|
if ($description) {
|
||||||
$description_view = new PHUIRemarkupView($viewer, $description);
|
$form->appendChild(
|
||||||
|
id(new AphrontFormMarkupControl())
|
||||||
$form
|
->setLabel(pht('Description'))
|
||||||
->appendChild(
|
->setValue($description));
|
||||||
id(new AphrontFormMarkupControl())
|
|
||||||
->setLabel(pht('Description'))
|
|
||||||
->setValue($description_view));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($group) {
|
if ($group) {
|
||||||
|
|
|
@ -60,17 +60,10 @@ final class PhabricatorConfigGroupController
|
||||||
$db_values = mpull($db_values, null, 'getConfigKey');
|
$db_values = mpull($db_values, null, 'getConfigKey');
|
||||||
}
|
}
|
||||||
|
|
||||||
$engine = id(new PhabricatorMarkupEngine())
|
|
||||||
->setViewer($this->getRequest()->getUser());
|
|
||||||
foreach ($options as $option) {
|
|
||||||
$engine->addObject($option, 'summary');
|
|
||||||
}
|
|
||||||
$engine->process();
|
|
||||||
|
|
||||||
$list = new PHUIObjectItemListView();
|
$list = new PHUIObjectItemListView();
|
||||||
$list->setBig(true);
|
$list->setBig(true);
|
||||||
foreach ($options as $option) {
|
foreach ($options as $option) {
|
||||||
$summary = $engine->getOutput($option, 'summary');
|
$summary = $option->getSummary();
|
||||||
|
|
||||||
$item = id(new PHUIObjectItemView())
|
$item = id(new PHUIObjectItemView())
|
||||||
->setHeader($option->getKey())
|
->setHeader($option->getKey())
|
||||||
|
|
|
@ -33,27 +33,26 @@ final class PhabricatorConfigIssueListController
|
||||||
PhabricatorSetupCheck::GROUP_OTHER,
|
PhabricatorSetupCheck::GROUP_OTHER,
|
||||||
'fa-question-circle');
|
'fa-question-circle');
|
||||||
|
|
||||||
$no_issues = null;
|
$title = pht('Setup Issues');
|
||||||
if (empty($issues)) {
|
$header = $this->buildHeaderView($title);
|
||||||
$no_issues = id(new PHUIInfoView())
|
|
||||||
|
if (!$issues) {
|
||||||
|
$issue_list = id(new PHUIInfoView())
|
||||||
->setTitle(pht('No Issues'))
|
->setTitle(pht('No Issues'))
|
||||||
->appendChild(
|
->appendChild(
|
||||||
pht('Your install has no current setup issues to resolve.'))
|
pht('Your install has no current setup issues to resolve.'))
|
||||||
->setSeverity(PHUIInfoView::SEVERITY_NOTICE);
|
->setSeverity(PHUIInfoView::SEVERITY_NOTICE);
|
||||||
|
} else {
|
||||||
|
$issue_list = array(
|
||||||
|
$important,
|
||||||
|
$php,
|
||||||
|
$mysql,
|
||||||
|
$other,
|
||||||
|
);
|
||||||
|
|
||||||
|
$issue_list = $this->buildConfigBoxView(pht('Issues'), $issue_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
$title = pht('Setup Issues');
|
|
||||||
$header = $this->buildHeaderView($title);
|
|
||||||
|
|
||||||
$issue_list = array(
|
|
||||||
$important,
|
|
||||||
$php,
|
|
||||||
$mysql,
|
|
||||||
$other,
|
|
||||||
);
|
|
||||||
|
|
||||||
$issue_list = $this->buildConfigBoxView(pht('Issues'), $issue_list);
|
|
||||||
|
|
||||||
$crumbs = $this->buildApplicationCrumbs()
|
$crumbs = $this->buildApplicationCrumbs()
|
||||||
->addTextCrumb($title)
|
->addTextCrumb($title)
|
||||||
->setBorder(true);
|
->setBorder(true);
|
||||||
|
@ -62,10 +61,7 @@ final class PhabricatorConfigIssueListController
|
||||||
->setHeader($header)
|
->setHeader($header)
|
||||||
->setNavigation($nav)
|
->setNavigation($nav)
|
||||||
->setFixed(true)
|
->setFixed(true)
|
||||||
->setMainColumn(array(
|
->setMainColumn($issue_list);
|
||||||
$no_issues,
|
|
||||||
$issue_list,
|
|
||||||
));
|
|
||||||
|
|
||||||
return $this->newPage()
|
return $this->newPage()
|
||||||
->setTitle($title)
|
->setTitle($title)
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
final class PhabricatorConfigOption
|
final class PhabricatorConfigOption
|
||||||
extends Phobject
|
extends Phobject {
|
||||||
implements PhabricatorMarkupInterface {
|
|
||||||
|
|
||||||
private $key;
|
private $key;
|
||||||
private $default;
|
private $default;
|
||||||
|
@ -204,43 +203,19 @@ final class PhabricatorConfigOption
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -( PhabricatorMarkupInterface )----------------------------------------- */
|
public function newDescriptionRemarkupView(PhabricatorUser $viewer) {
|
||||||
|
$description = $this->getDescription();
|
||||||
public function getMarkupFieldKey($field) {
|
if (!strlen($description)) {
|
||||||
return $this->getKey().':'.$field;
|
return null;
|
||||||
}
|
|
||||||
|
|
||||||
public function newMarkupEngine($field) {
|
|
||||||
return PhabricatorMarkupEngine::newMarkupEngine(array());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getMarkupText($field) {
|
|
||||||
switch ($field) {
|
|
||||||
case 'description':
|
|
||||||
$text = $this->getDescription();
|
|
||||||
break;
|
|
||||||
case 'summary':
|
|
||||||
$text = $this->getSummary();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: We should probably implement this as a real Markup rule, but
|
// TODO: Some day, we should probably implement this as a real rule.
|
||||||
// markup rules are a bit of a mess right now and it doesn't hurt us to
|
$description = preg_replace(
|
||||||
// fake this.
|
|
||||||
$text = preg_replace(
|
|
||||||
'/{{([^}]+)}}/',
|
'/{{([^}]+)}}/',
|
||||||
'[[/config/edit/\\1/ | \\1]]',
|
'[[/config/edit/\\1/ | \\1]]',
|
||||||
$text);
|
$description);
|
||||||
|
|
||||||
return $text;
|
return new PHUIRemarkupView($viewer, $description);
|
||||||
}
|
|
||||||
|
|
||||||
public function didMarkupText($field, $output, PhutilMarkupEngine $engine) {
|
|
||||||
return $output;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function shouldUseMarkupCache($field) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,49 +146,6 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
|
||||||
return $xactions;
|
return $xactions;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function requireCapabilities(
|
|
||||||
PhabricatorLiskDAO $object,
|
|
||||||
PhabricatorApplicationTransaction $xaction) {
|
|
||||||
|
|
||||||
parent::requireCapabilities($object, $xaction);
|
|
||||||
|
|
||||||
switch ($xaction->getTransactionType()) {
|
|
||||||
case ConpherenceThreadParticipantsTransaction::TRANSACTIONTYPE:
|
|
||||||
$old_map = array_fuse($xaction->getOldValue());
|
|
||||||
$new_map = array_fuse($xaction->getNewValue());
|
|
||||||
|
|
||||||
$add = array_keys(array_diff_key($new_map, $old_map));
|
|
||||||
$rem = array_keys(array_diff_key($old_map, $new_map));
|
|
||||||
|
|
||||||
$actor_phid = $this->getActingAsPHID();
|
|
||||||
|
|
||||||
$is_join = (($add === array($actor_phid)) && !$rem);
|
|
||||||
$is_leave = (($rem === array($actor_phid)) && !$add);
|
|
||||||
|
|
||||||
if ($is_join) {
|
|
||||||
// Anyone can join a thread they can see.
|
|
||||||
} else if ($is_leave) {
|
|
||||||
// Anyone can leave a thread.
|
|
||||||
} else {
|
|
||||||
// You need CAN_EDIT to add or remove participants. For additional
|
|
||||||
// discussion, see D17696 and T4411.
|
|
||||||
PhabricatorPolicyFilter::requireCapability(
|
|
||||||
$this->requireActor(),
|
|
||||||
$object,
|
|
||||||
PhabricatorPolicyCapability::CAN_EDIT);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ConpherenceThreadTitleTransaction::TRANSACTIONTYPE:
|
|
||||||
case ConpherenceThreadTopicTransaction::TRANSACTIONTYPE:
|
|
||||||
PhabricatorPolicyFilter::requireCapability(
|
|
||||||
$this->requireActor(),
|
|
||||||
$object,
|
|
||||||
PhabricatorPolicyCapability::CAN_EDIT);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function shouldSendMail(
|
protected function shouldSendMail(
|
||||||
PhabricatorLiskDAO $object,
|
PhabricatorLiskDAO $object,
|
||||||
array $xactions) {
|
array $xactions) {
|
||||||
|
|
|
@ -114,4 +114,34 @@ final class ConpherenceThreadParticipantsTransaction
|
||||||
return $errors;
|
return $errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getRequiredCapabilities(
|
||||||
|
$object,
|
||||||
|
PhabricatorApplicationTransaction $xaction) {
|
||||||
|
|
||||||
|
$old_map = array_fuse($xaction->getOldValue());
|
||||||
|
$new_map = array_fuse($xaction->getNewValue());
|
||||||
|
|
||||||
|
$add = array_keys(array_diff_key($new_map, $old_map));
|
||||||
|
$rem = array_keys(array_diff_key($old_map, $new_map));
|
||||||
|
|
||||||
|
$actor_phid = $this->getActingAsPHID();
|
||||||
|
|
||||||
|
$is_join = (($add === array($actor_phid)) && !$rem);
|
||||||
|
$is_leave = (($rem === array($actor_phid)) && !$add);
|
||||||
|
|
||||||
|
if ($is_join) {
|
||||||
|
// Anyone can join a thread they can see.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($is_leave) {
|
||||||
|
// Anyone can leave a thread.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// You need CAN_EDIT to add or remove participants. For additional
|
||||||
|
// discussion, see D17696 and T4411.
|
||||||
|
return PhabricatorPolicyCapability::CAN_EDIT;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1315,7 +1315,7 @@ final class DifferentialRevisionViewController
|
||||||
}
|
}
|
||||||
|
|
||||||
return id(new HarbormasterUnitSummaryView())
|
return id(new HarbormasterUnitSummaryView())
|
||||||
->setUser($viewer)
|
->setViewer($viewer)
|
||||||
->setExcuse($excuse)
|
->setExcuse($excuse)
|
||||||
->setBuildable($diff->getBuildable())
|
->setBuildable($diff->getBuildable())
|
||||||
->setUnitMessages($diff->getUnitMessages())
|
->setUnitMessages($diff->getUnitMessages())
|
||||||
|
|
|
@ -54,4 +54,28 @@ final class DifferentialBuildableEngine
|
||||||
$this->applyTransactions(array($xaction));
|
$this->applyTransactions(array($xaction));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getAuthorIdentity() {
|
||||||
|
$object = $this->getObject();
|
||||||
|
|
||||||
|
if ($object instanceof DifferentialRevision) {
|
||||||
|
$object = $object->loadActiveDiff();
|
||||||
|
}
|
||||||
|
|
||||||
|
$authorship = $object->getDiffAuthorshipDict();
|
||||||
|
if (!isset($authorship['authorName'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$name = $authorship['authorName'];
|
||||||
|
$address = idx($authorship, 'authorEmail');
|
||||||
|
|
||||||
|
$full = id(new PhutilEmailAddress())
|
||||||
|
->setDisplayName($name)
|
||||||
|
->setAddress($address);
|
||||||
|
|
||||||
|
return id(new PhabricatorRepositoryIdentity())
|
||||||
|
->setIdentityName((string)$full)
|
||||||
|
->makeEphemeral();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,10 +10,7 @@ final class DifferentialRevisionSummaryHeraldField
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHeraldFieldValue($object) {
|
public function getHeraldFieldValue($object) {
|
||||||
// NOTE: For historical reasons, this field includes the test plan. We
|
return $object->getSummary();
|
||||||
// could maybe try to fix this some day, but it probably aligns reasonably
|
|
||||||
// well with user expectation without harming anything.
|
|
||||||
return $object->getSummary()."\n\n".$object->getTestPlan();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getHeraldFieldStandardType() {
|
protected function getHeraldFieldStandardType() {
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class DifferentialRevisionTestPlanHeraldField
|
||||||
|
extends DifferentialRevisionHeraldField {
|
||||||
|
|
||||||
|
const FIELDCONST = 'differential.revision.test-plan';
|
||||||
|
|
||||||
|
public function getHeraldFieldName() {
|
||||||
|
return pht('Revision test plan');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHeraldFieldValue($object) {
|
||||||
|
return $object->getTestPlan();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getHeraldFieldStandardType() {
|
||||||
|
return self::STANDARD_TEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -34,4 +34,10 @@ final class DiffusionBuildableEngine
|
||||||
$this->applyTransactions(array($xaction));
|
$this->applyTransactions(array($xaction));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getAuthorIdentity() {
|
||||||
|
return $this->getObject()
|
||||||
|
->loadIdentities($this->getViewer())
|
||||||
|
->getAuthorIdentity();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,7 +94,7 @@ final class DiffusionReadmeView extends DiffusionView {
|
||||||
}
|
}
|
||||||
|
|
||||||
$readme_content = phutil_tag_div($class, $readme_content);
|
$readme_content = phutil_tag_div($class, $readme_content);
|
||||||
$document = id(new PHUIDocumentViewPro())
|
$document = id(new PHUIDocumentView())
|
||||||
->setFluid(true)
|
->setFluid(true)
|
||||||
->appendChild($readme_content);
|
->appendChild($readme_content);
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ final class DivinerAtomController extends DivinerController {
|
||||||
$prop_list = new PHUIPropertyGroupView();
|
$prop_list = new PHUIPropertyGroupView();
|
||||||
$prop_list->addPropertyList($properties);
|
$prop_list->addPropertyList($properties);
|
||||||
|
|
||||||
$document = id(new PHUIDocumentViewPro())
|
$document = id(new PHUIDocumentView())
|
||||||
->setBook($book->getTitle(), $group_name)
|
->setBook($book->getTitle(), $group_name)
|
||||||
->setHeader($header)
|
->setHeader($header)
|
||||||
->addClass('diviner-view');
|
->addClass('diviner-view');
|
||||||
|
|
|
@ -45,7 +45,7 @@ final class DivinerBookController extends DivinerController {
|
||||||
->setName($book->getRepository()->getMonogram()));
|
->setName($book->getRepository()->getMonogram()));
|
||||||
}
|
}
|
||||||
|
|
||||||
$document = new PHUIDocumentViewPro();
|
$document = new PHUIDocumentView();
|
||||||
$document->setHeader($header);
|
$document->setHeader($header);
|
||||||
$document->addClass('diviner-view');
|
$document->addClass('diviner-view');
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ final class DivinerMainController extends DivinerController {
|
||||||
->setHeader(pht('Documentation Books'))
|
->setHeader(pht('Documentation Books'))
|
||||||
->addActionLink($query_button);
|
->addActionLink($query_button);
|
||||||
|
|
||||||
$document = new PHUIDocumentViewPro();
|
$document = new PHUIDocumentView();
|
||||||
$document->setHeader($header);
|
$document->setHeader($header);
|
||||||
$document->addClass('diviner-view');
|
$document->addClass('diviner-view');
|
||||||
|
|
||||||
|
|
|
@ -163,6 +163,30 @@ final class DrydockLeaseViewController extends DrydockLeaseController {
|
||||||
}
|
}
|
||||||
$view->addProperty(pht('Expires'), $until_display);
|
$view->addProperty(pht('Expires'), $until_display);
|
||||||
|
|
||||||
|
$acquired_epoch = $lease->getAcquiredEpoch();
|
||||||
|
$activated_epoch = $lease->getActivatedEpoch();
|
||||||
|
|
||||||
|
if ($acquired_epoch) {
|
||||||
|
$acquired_display = phabricator_datetime($acquired_epoch, $viewer);
|
||||||
|
} else {
|
||||||
|
if ($activated_epoch) {
|
||||||
|
$acquired_display = phutil_tag(
|
||||||
|
'em',
|
||||||
|
array(),
|
||||||
|
pht('Activated on Acquisition'));
|
||||||
|
} else {
|
||||||
|
$acquired_display = phutil_tag('em', array(), pht('Not Acquired'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$view->addProperty(pht('Acquired'), $acquired_display);
|
||||||
|
|
||||||
|
if ($activated_epoch) {
|
||||||
|
$activated_display = phabricator_datetime($activated_epoch, $viewer);
|
||||||
|
} else {
|
||||||
|
$activated_display = phutil_tag('em', array(), pht('Not Activated'));
|
||||||
|
}
|
||||||
|
$view->addProperty(pht('Activated'), $activated_display);
|
||||||
|
|
||||||
$attributes = $lease->getAttributes();
|
$attributes = $lease->getAttributes();
|
||||||
if ($attributes) {
|
if ($attributes) {
|
||||||
$view->addSectionHeader(
|
$view->addSectionHeader(
|
||||||
|
|
|
@ -10,6 +10,8 @@ final class DrydockLease extends DrydockDAO
|
||||||
protected $authorizingPHID;
|
protected $authorizingPHID;
|
||||||
protected $attributes = array();
|
protected $attributes = array();
|
||||||
protected $status = DrydockLeaseStatus::STATUS_PENDING;
|
protected $status = DrydockLeaseStatus::STATUS_PENDING;
|
||||||
|
protected $acquiredEpoch;
|
||||||
|
protected $activatedEpoch;
|
||||||
|
|
||||||
private $resource = self::ATTACHABLE;
|
private $resource = self::ATTACHABLE;
|
||||||
private $unconsumedCommands = self::ATTACHABLE;
|
private $unconsumedCommands = self::ATTACHABLE;
|
||||||
|
@ -62,6 +64,22 @@ final class DrydockLease extends DrydockDAO
|
||||||
$this->scheduleUpdate();
|
$this->scheduleUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setStatus($status) {
|
||||||
|
if ($status == DrydockLeaseStatus::STATUS_ACQUIRED) {
|
||||||
|
if (!$this->getAcquiredEpoch()) {
|
||||||
|
$this->setAcquiredEpoch(PhabricatorTime::getNow());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($status == DrydockLeaseStatus::STATUS_ACTIVE) {
|
||||||
|
if (!$this->getActivatedEpoch()) {
|
||||||
|
$this->setActivatedEpoch(PhabricatorTime::getNow());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::setStatus($status);
|
||||||
|
}
|
||||||
|
|
||||||
public function getLeaseName() {
|
public function getLeaseName() {
|
||||||
return pht('Lease %d', $this->getID());
|
return pht('Lease %d', $this->getID());
|
||||||
}
|
}
|
||||||
|
@ -78,6 +96,8 @@ final class DrydockLease extends DrydockDAO
|
||||||
'resourceType' => 'text128',
|
'resourceType' => 'text128',
|
||||||
'ownerPHID' => 'phid?',
|
'ownerPHID' => 'phid?',
|
||||||
'resourcePHID' => 'phid?',
|
'resourcePHID' => 'phid?',
|
||||||
|
'acquiredEpoch' => 'epoch?',
|
||||||
|
'activatedEpoch' => 'epoch?',
|
||||||
),
|
),
|
||||||
self::CONFIG_KEY_SCHEMA => array(
|
self::CONFIG_KEY_SCHEMA => array(
|
||||||
'key_resource' => array(
|
'key_resource' => array(
|
||||||
|
|
|
@ -169,7 +169,7 @@ final class PhabricatorGuideInstallModule extends PhabricatorGuideModule {
|
||||||
|
|
||||||
$intro = new PHUIRemarkupView($viewer, $intro);
|
$intro = new PHUIRemarkupView($viewer, $intro);
|
||||||
|
|
||||||
$intro = id(new PHUIDocumentViewPro())
|
$intro = id(new PHUIDocumentView())
|
||||||
->appendChild($intro);
|
->appendChild($intro);
|
||||||
|
|
||||||
return array($intro, $guide_items);
|
return array($intro, $guide_items);
|
||||||
|
|
|
@ -206,7 +206,7 @@ final class PhabricatorGuideQuickStartModule extends PhabricatorGuideModule {
|
||||||
'these features at your own pace.');
|
'these features at your own pace.');
|
||||||
|
|
||||||
$intro = new PHUIRemarkupView($viewer, $intro);
|
$intro = new PHUIRemarkupView($viewer, $intro);
|
||||||
$intro = id(new PHUIDocumentViewPro())
|
$intro = id(new PHUIDocumentView())
|
||||||
->appendChild($intro);
|
->appendChild($intro);
|
||||||
|
|
||||||
return array($intro, $guide_items);
|
return array($intro, $guide_items);
|
||||||
|
|
|
@ -318,7 +318,7 @@ final class HarbormasterBuildableViewController
|
||||||
|
|
||||||
if ($lint_data) {
|
if ($lint_data) {
|
||||||
$lint_table = id(new HarbormasterLintPropertyView())
|
$lint_table = id(new HarbormasterLintPropertyView())
|
||||||
->setUser($viewer)
|
->setViewer($viewer)
|
||||||
->setLimit(10)
|
->setLimit(10)
|
||||||
->setLintMessages($lint_data);
|
->setLintMessages($lint_data);
|
||||||
|
|
||||||
|
@ -343,6 +343,7 @@ final class HarbormasterBuildableViewController
|
||||||
|
|
||||||
if ($unit_data) {
|
if ($unit_data) {
|
||||||
$unit = id(new HarbormasterUnitSummaryView())
|
$unit = id(new HarbormasterUnitSummaryView())
|
||||||
|
->setViewer($viewer)
|
||||||
->setBuildable($buildable)
|
->setBuildable($buildable)
|
||||||
->setUnitMessages($unit_data)
|
->setUnitMessages($unit_data)
|
||||||
->setShowViewAll(true)
|
->setShowViewAll(true)
|
||||||
|
|
|
@ -39,6 +39,7 @@ final class HarbormasterUnitMessageListController
|
||||||
}
|
}
|
||||||
|
|
||||||
$unit = id(new HarbormasterUnitSummaryView())
|
$unit = id(new HarbormasterUnitSummaryView())
|
||||||
|
->setViewer($viewer)
|
||||||
->setBuildable($buildable)
|
->setBuildable($buildable)
|
||||||
->setUnitMessages($unit_data);
|
->setUnitMessages($unit_data);
|
||||||
|
|
||||||
|
|
|
@ -88,23 +88,7 @@ final class HarbormasterUnitMessageViewController
|
||||||
pht('Run At'),
|
pht('Run At'),
|
||||||
phabricator_datetime($message->getDateCreated(), $viewer));
|
phabricator_datetime($message->getDateCreated(), $viewer));
|
||||||
|
|
||||||
$details = $message->getUnitMessageDetails();
|
$details = $message->newUnitMessageDetailsView($viewer);
|
||||||
if (strlen($details)) {
|
|
||||||
// TODO: Use the log view here, once it gets cleaned up.
|
|
||||||
// Shenanigans below.
|
|
||||||
$details = phutil_tag(
|
|
||||||
'div',
|
|
||||||
array(
|
|
||||||
'class' => 'PhabricatorMonospaced',
|
|
||||||
'style' =>
|
|
||||||
'white-space: pre-wrap; '.
|
|
||||||
'color: #666666; '.
|
|
||||||
'overflow-x: auto;',
|
|
||||||
),
|
|
||||||
$details);
|
|
||||||
} else {
|
|
||||||
$details = phutil_tag('em', array(), pht('No details provided.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$view->addSectionHeader(
|
$view->addSectionHeader(
|
||||||
pht('Details'),
|
pht('Details'),
|
||||||
|
|
|
@ -101,5 +101,8 @@ abstract class HarbormasterBuildableEngine
|
||||||
$xactions);
|
$xactions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getAuthorIdentity() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,6 +117,20 @@ EOTEXT
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$engine = HarbormasterBuildableEngine::newForObject(
|
||||||
|
$object,
|
||||||
|
$viewer);
|
||||||
|
|
||||||
|
$author_identity = $engine->getAuthorIdentity();
|
||||||
|
if ($author_identity) {
|
||||||
|
$data_structure += array(
|
||||||
|
'author' => array(
|
||||||
|
'name' => $author_identity->getIdentityDisplayName(),
|
||||||
|
'email' => $author_identity->getIdentityEmailAddress(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
$json_data = phutil_json_encode($data_structure);
|
$json_data = phutil_json_encode($data_structure);
|
||||||
|
|
||||||
$credential_phid = $this->getSetting('token');
|
$credential_phid = $this->getSetting('token');
|
||||||
|
|
|
@ -13,6 +13,9 @@ final class HarbormasterBuildUnitMessage
|
||||||
|
|
||||||
private $buildTarget = self::ATTACHABLE;
|
private $buildTarget = self::ATTACHABLE;
|
||||||
|
|
||||||
|
const FORMAT_TEXT = 'text';
|
||||||
|
const FORMAT_REMARKUP = 'remarkup';
|
||||||
|
|
||||||
public static function initializeNewUnitMessage(
|
public static function initializeNewUnitMessage(
|
||||||
HarbormasterBuildTarget $build_target) {
|
HarbormasterBuildTarget $build_target) {
|
||||||
return id(new HarbormasterBuildUnitMessage())
|
return id(new HarbormasterBuildUnitMessage())
|
||||||
|
@ -66,6 +69,13 @@ final class HarbormasterBuildUnitMessage
|
||||||
'description' => pht(
|
'description' => pht(
|
||||||
'Additional human-readable information about the failure.'),
|
'Additional human-readable information about the failure.'),
|
||||||
),
|
),
|
||||||
|
'format' => array(
|
||||||
|
'type' => 'optional string',
|
||||||
|
'description' => pht(
|
||||||
|
'Format for the text provided in "details". Valid values are '.
|
||||||
|
'"text" (default) or "remarkup". This controls how test details '.
|
||||||
|
'are rendered when shown to users.'),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,6 +114,11 @@ final class HarbormasterBuildUnitMessage
|
||||||
$obj->setProperty('details', $details);
|
$obj->setProperty('details', $details);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$format = idx($dict, 'format');
|
||||||
|
if ($format) {
|
||||||
|
$obj->setProperty('format', $format);
|
||||||
|
}
|
||||||
|
|
||||||
return $obj;
|
return $obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,6 +164,66 @@ final class HarbormasterBuildUnitMessage
|
||||||
return $this->getProperty('details', '');
|
return $this->getProperty('details', '');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getUnitMessageDetailsFormat() {
|
||||||
|
return $this->getProperty('format', self::FORMAT_TEXT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newUnitMessageDetailsView(
|
||||||
|
PhabricatorUser $viewer,
|
||||||
|
$summarize = false) {
|
||||||
|
|
||||||
|
$format = $this->getUnitMessageDetailsFormat();
|
||||||
|
|
||||||
|
$is_text = ($format !== self::FORMAT_REMARKUP);
|
||||||
|
$is_remarkup = ($format === self::FORMAT_REMARKUP);
|
||||||
|
|
||||||
|
$full_details = $this->getUnitMessageDetails();
|
||||||
|
|
||||||
|
if (!strlen($full_details)) {
|
||||||
|
if ($summarize) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$details = phutil_tag('em', array(), pht('No details provided.'));
|
||||||
|
} else if ($summarize) {
|
||||||
|
if ($is_text) {
|
||||||
|
$details = id(new PhutilUTF8StringTruncator())
|
||||||
|
->setMaximumBytes(2048)
|
||||||
|
->truncateString($full_details);
|
||||||
|
$details = phutil_split_lines($details);
|
||||||
|
|
||||||
|
$limit = 3;
|
||||||
|
if (count($details) > $limit) {
|
||||||
|
$details = array_slice($details, 0, $limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
$details = implode('', $details);
|
||||||
|
} else {
|
||||||
|
$details = $full_details;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$details = $full_details;
|
||||||
|
}
|
||||||
|
|
||||||
|
require_celerity_resource('harbormaster-css');
|
||||||
|
|
||||||
|
$classes = array();
|
||||||
|
$classes[] = 'harbormaster-unit-details';
|
||||||
|
|
||||||
|
if ($is_remarkup) {
|
||||||
|
$details = new PHUIRemarkupView($viewer, $details);
|
||||||
|
} else {
|
||||||
|
$classes[] = 'harbormaster-unit-details-text';
|
||||||
|
$classes[] = 'PhabricatorMonospaced';
|
||||||
|
}
|
||||||
|
|
||||||
|
return phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => implode(' ', $classes),
|
||||||
|
),
|
||||||
|
$details);
|
||||||
|
}
|
||||||
|
|
||||||
public function getUnitMessageDisplayName() {
|
public function getUnitMessageDisplayName() {
|
||||||
$name = $this->getName();
|
$name = $this->getName();
|
||||||
|
|
||||||
|
|
|
@ -34,9 +34,8 @@ final class HarbormasterUnitPropertyView extends AphrontView {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function render() {
|
public function render() {
|
||||||
require_celerity_resource('harbormaster-css');
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
$messages = $this->unitMessages;
|
$messages = $this->unitMessages;
|
||||||
$messages = msort($messages, 'getSortKey');
|
$messages = msort($messages, 'getSortKey');
|
||||||
|
@ -84,13 +83,10 @@ final class HarbormasterUnitPropertyView extends AphrontView {
|
||||||
$name);
|
$name);
|
||||||
}
|
}
|
||||||
|
|
||||||
$details = $message->getUnitMessageDetails();
|
$name = array(
|
||||||
if (strlen($details)) {
|
$name,
|
||||||
$name = array(
|
$message->newUnitMessageDetailsView($viewer, true),
|
||||||
$name,
|
);
|
||||||
$this->renderUnitTestDetails($details),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$rows[] = array(
|
$rows[] = array(
|
||||||
$result_icon,
|
$result_icon,
|
||||||
|
@ -158,25 +154,4 @@ final class HarbormasterUnitPropertyView extends AphrontView {
|
||||||
return $table;
|
return $table;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function renderUnitTestDetails($full_details) {
|
|
||||||
$details = id(new PhutilUTF8StringTruncator())
|
|
||||||
->setMaximumBytes(2048)
|
|
||||||
->truncateString($full_details);
|
|
||||||
$details = phutil_split_lines($details);
|
|
||||||
|
|
||||||
$limit = 3;
|
|
||||||
if (count($details) > $limit) {
|
|
||||||
$details = array_slice($details, 0, $limit);
|
|
||||||
}
|
|
||||||
|
|
||||||
$details = implode('', $details);
|
|
||||||
|
|
||||||
return phutil_tag(
|
|
||||||
'div',
|
|
||||||
array(
|
|
||||||
'class' => 'PhabricatorMonospaced harbormaster-unit-details',
|
|
||||||
),
|
|
||||||
$details);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,6 +77,7 @@ final class HarbormasterUnitSummaryView extends AphrontView {
|
||||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);
|
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);
|
||||||
|
|
||||||
$table = id(new HarbormasterUnitPropertyView())
|
$table = id(new HarbormasterUnitPropertyView())
|
||||||
|
->setViewer($this->getViewer())
|
||||||
->setUnitMessages($messages);
|
->setUnitMessages($messages);
|
||||||
|
|
||||||
if ($this->showViewAll) {
|
if ($this->showViewAll) {
|
||||||
|
|
|
@ -272,7 +272,7 @@ final class LegalpadDocumentSignController extends LegalpadController {
|
||||||
$preamble_box->addPropertyList($preamble);
|
$preamble_box->addPropertyList($preamble);
|
||||||
}
|
}
|
||||||
|
|
||||||
$content = id(new PHUIDocumentViewPro())
|
$content = id(new PHUIDocumentView())
|
||||||
->addClass('legalpad')
|
->addClass('legalpad')
|
||||||
->setHeader($header)
|
->setHeader($header)
|
||||||
->appendChild(
|
->appendChild(
|
||||||
|
|
|
@ -132,7 +132,7 @@ final class PhabricatorApplicationEmailCommandsController
|
||||||
$header = id(new PHUIHeaderView())
|
$header = id(new PHUIHeaderView())
|
||||||
->setHeader($title);
|
->setHeader($title);
|
||||||
|
|
||||||
$document = id(new PHUIDocumentViewPro())
|
$document = id(new PHUIDocumentView())
|
||||||
->setHeader($header)
|
->setHeader($header)
|
||||||
->appendChild($info_view)
|
->appendChild($info_view)
|
||||||
->appendChild($content_box);
|
->appendChild($content_box);
|
||||||
|
|
|
@ -97,6 +97,9 @@ final class PhabricatorPeopleApplication extends PhabricatorApplication {
|
||||||
PeopleCreateUsersCapability::CAPABILITY => array(
|
PeopleCreateUsersCapability::CAPABILITY => array(
|
||||||
'default' => PhabricatorPolicies::POLICY_ADMIN,
|
'default' => PhabricatorPolicies::POLICY_ADMIN,
|
||||||
),
|
),
|
||||||
|
PeopleDisableUsersCapability::CAPABILITY => array(
|
||||||
|
'default' => PhabricatorPolicies::POLICY_ADMIN,
|
||||||
|
),
|
||||||
PeopleBrowseUserDirectoryCapability::CAPABILITY => array(),
|
PeopleBrowseUserDirectoryCapability::CAPABILITY => array(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PeopleDisableUsersCapability
|
||||||
|
extends PhabricatorPolicyCapability {
|
||||||
|
|
||||||
|
const CAPABILITY = 'people.disable.users';
|
||||||
|
|
||||||
|
public function getCapabilityName() {
|
||||||
|
return pht('Can Disable Users');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function describeCapabilityRejection() {
|
||||||
|
return pht('You do not have permission to disable or enable users.');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -10,6 +10,14 @@ final class UserDisableConduitAPIMethod extends UserConduitAPIMethod {
|
||||||
return pht('Permanently disable specified users (admin only).');
|
return pht('Permanently disable specified users (admin only).');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getMethodStatus() {
|
||||||
|
return self::METHOD_STATUS_DEPRECATED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMethodStatusDescription() {
|
||||||
|
return pht('Obsoleted by method "user.edit".');
|
||||||
|
}
|
||||||
|
|
||||||
protected function defineParamTypes() {
|
protected function defineParamTypes() {
|
||||||
return array(
|
return array(
|
||||||
'phids' => 'required list<phid>',
|
'phids' => 'required list<phid>',
|
||||||
|
@ -43,11 +51,23 @@ final class UserDisableConduitAPIMethod extends UserConduitAPIMethod {
|
||||||
throw new ConduitException('ERR-BAD-PHID');
|
throw new ConduitException('ERR-BAD-PHID');
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($users as $user) {
|
foreach ($phids as $phid) {
|
||||||
id(new PhabricatorUserEditor())
|
$params = array(
|
||||||
->setActor($actor)
|
'transactions' => array(
|
||||||
->disableUser($user, true);
|
array(
|
||||||
|
'type' => 'disabled',
|
||||||
|
'value' => true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'objectIdentifier' => $phid,
|
||||||
|
);
|
||||||
|
|
||||||
|
id(new ConduitCall('user.edit', $params))
|
||||||
|
->setUser($actor)
|
||||||
|
->execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,14 @@ final class UserEnableConduitAPIMethod extends UserConduitAPIMethod {
|
||||||
return pht('Re-enable specified users (admin only).');
|
return pht('Re-enable specified users (admin only).');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getMethodStatus() {
|
||||||
|
return self::METHOD_STATUS_DEPRECATED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMethodStatusDescription() {
|
||||||
|
return pht('Obsoleted by method "user.edit".');
|
||||||
|
}
|
||||||
|
|
||||||
protected function defineParamTypes() {
|
protected function defineParamTypes() {
|
||||||
return array(
|
return array(
|
||||||
'phids' => 'required list<phid>',
|
'phids' => 'required list<phid>',
|
||||||
|
@ -43,11 +51,23 @@ final class UserEnableConduitAPIMethod extends UserConduitAPIMethod {
|
||||||
throw new ConduitException('ERR-BAD-PHID');
|
throw new ConduitException('ERR-BAD-PHID');
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($users as $user) {
|
foreach ($phids as $phid) {
|
||||||
id(new PhabricatorUserEditor())
|
$params = array(
|
||||||
->setActor($actor)
|
'transactions' => array(
|
||||||
->disableUser($user, false);
|
array(
|
||||||
|
'type' => 'disabled',
|
||||||
|
'value' => false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'objectIdentifier' => $phid,
|
||||||
|
);
|
||||||
|
|
||||||
|
id(new ConduitCall('user.edit', $params))
|
||||||
|
->setUser($actor)
|
||||||
|
->execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,13 @@ final class PhabricatorPeopleApproveController
|
||||||
|
|
||||||
$done_uri = $this->getApplicationURI('query/approval/');
|
$done_uri = $this->getApplicationURI('query/approval/');
|
||||||
|
|
||||||
|
if ($user->getIsApproved()) {
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('Already Approved'))
|
||||||
|
->appendChild(pht('This user has already been approved.'))
|
||||||
|
->addCancelButton($done_uri);
|
||||||
|
}
|
||||||
|
|
||||||
if ($request->isFormPost()) {
|
if ($request->isFormPost()) {
|
||||||
id(new PhabricatorUserEditor())
|
id(new PhabricatorUserEditor())
|
||||||
->setActor($viewer)
|
->setActor($viewer)
|
||||||
|
|
|
@ -3,10 +3,14 @@
|
||||||
final class PhabricatorPeopleDisableController
|
final class PhabricatorPeopleDisableController
|
||||||
extends PhabricatorPeopleController {
|
extends PhabricatorPeopleController {
|
||||||
|
|
||||||
|
public function shouldRequireAdmin() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public function handleRequest(AphrontRequest $request) {
|
public function handleRequest(AphrontRequest $request) {
|
||||||
$viewer = $this->getViewer();
|
$viewer = $this->getViewer();
|
||||||
$id = $request->getURIData('id');
|
$id = $request->getURIData('id');
|
||||||
$via = $request->getURIData('id');
|
$via = $request->getURIData('via');
|
||||||
|
|
||||||
$user = id(new PhabricatorPeopleQuery())
|
$user = id(new PhabricatorPeopleQuery())
|
||||||
->setViewer($viewer)
|
->setViewer($viewer)
|
||||||
|
@ -20,11 +24,36 @@ final class PhabricatorPeopleDisableController
|
||||||
// on profiles and also via the "X" action on the approval queue. We do
|
// on profiles and also via the "X" action on the approval queue. We do
|
||||||
// things slightly differently depending on the context the actor is in.
|
// things slightly differently depending on the context the actor is in.
|
||||||
|
|
||||||
|
// In particular, disabling via "Disapprove" requires you be an
|
||||||
|
// administrator (and bypasses the "Can Disable Users" permission).
|
||||||
|
// Disabling via "Disable" requires the permission only.
|
||||||
|
|
||||||
$is_disapprove = ($via == 'disapprove');
|
$is_disapprove = ($via == 'disapprove');
|
||||||
if ($is_disapprove) {
|
if ($is_disapprove) {
|
||||||
$done_uri = $this->getApplicationURI('query/approval/');
|
$done_uri = $this->getApplicationURI('query/approval/');
|
||||||
|
|
||||||
|
if (!$viewer->getIsAdmin()) {
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('No Permission'))
|
||||||
|
->appendParagraph(pht('Only administrators can disapprove users.'))
|
||||||
|
->addCancelButton($done_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($user->getIsApproved()) {
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('Already Approved'))
|
||||||
|
->appendParagraph(pht('This user has already been approved.'))
|
||||||
|
->addCancelButton($done_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
// On the "Disapprove" flow, bypass the "Can Disable Users" permission.
|
||||||
|
$actor = PhabricatorUser::getOmnipotentUser();
|
||||||
$should_disable = true;
|
$should_disable = true;
|
||||||
} else {
|
} else {
|
||||||
|
$this->requireApplicationCapability(
|
||||||
|
PeopleDisableUsersCapability::CAPABILITY);
|
||||||
|
|
||||||
|
$actor = $viewer;
|
||||||
$done_uri = $this->getApplicationURI("manage/{$id}/");
|
$done_uri = $this->getApplicationURI("manage/{$id}/");
|
||||||
$should_disable = !$user->getIsDisabled();
|
$should_disable = !$user->getIsDisabled();
|
||||||
}
|
}
|
||||||
|
@ -39,9 +68,19 @@ final class PhabricatorPeopleDisableController
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($request->isFormPost()) {
|
if ($request->isFormPost()) {
|
||||||
id(new PhabricatorUserEditor())
|
$xactions = array();
|
||||||
->setActor($viewer)
|
|
||||||
->disableUser($user, $should_disable);
|
$xactions[] = id(new PhabricatorUserTransaction())
|
||||||
|
->setTransactionType(PhabricatorUserDisableTransaction::TRANSACTIONTYPE)
|
||||||
|
->setNewValue($should_disable);
|
||||||
|
|
||||||
|
id(new PhabricatorUserTransactionEditor())
|
||||||
|
->setActor($actor)
|
||||||
|
->setActingAsPHID($viewer->getPHID())
|
||||||
|
->setContentSourceFromRequest($request)
|
||||||
|
->setContinueOnMissingFields(true)
|
||||||
|
->setContinueOnNoEffect(true)
|
||||||
|
->applyTransactions($user, $xactions);
|
||||||
|
|
||||||
return id(new AphrontRedirectResponse())->setURI($done_uri);
|
return id(new AphrontRedirectResponse())->setURI($done_uri);
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,11 +75,22 @@ final class PhabricatorPeopleProfileManageController
|
||||||
private function buildCurtain(PhabricatorUser $user) {
|
private function buildCurtain(PhabricatorUser $user) {
|
||||||
$viewer = $this->getViewer();
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$is_self = ($user->getPHID() === $viewer->getPHID());
|
||||||
|
|
||||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||||
$viewer,
|
$viewer,
|
||||||
$user,
|
$user,
|
||||||
PhabricatorPolicyCapability::CAN_EDIT);
|
PhabricatorPolicyCapability::CAN_EDIT);
|
||||||
|
|
||||||
|
$is_admin = $viewer->getIsAdmin();
|
||||||
|
$can_admin = ($is_admin && !$is_self);
|
||||||
|
|
||||||
|
$has_disable = $this->hasApplicationCapability(
|
||||||
|
PeopleDisableUsersCapability::CAPABILITY);
|
||||||
|
$can_disable = ($has_disable && !$is_self);
|
||||||
|
|
||||||
|
$can_welcome = ($is_admin && $user->canEstablishWebSessions());
|
||||||
|
|
||||||
$curtain = $this->newCurtainView($user);
|
$curtain = $this->newCurtainView($user);
|
||||||
|
|
||||||
$curtain->addAction(
|
$curtain->addAction(
|
||||||
|
@ -114,10 +125,6 @@ final class PhabricatorPeopleProfileManageController
|
||||||
$empower_name = pht('Make Administrator');
|
$empower_name = pht('Make Administrator');
|
||||||
}
|
}
|
||||||
|
|
||||||
$is_admin = $viewer->getIsAdmin();
|
|
||||||
$is_self = ($user->getPHID() === $viewer->getPHID());
|
|
||||||
$can_admin = ($is_admin && !$is_self);
|
|
||||||
|
|
||||||
$curtain->addAction(
|
$curtain->addAction(
|
||||||
id(new PhabricatorActionView())
|
id(new PhabricatorActionView())
|
||||||
->setIcon($empower_icon)
|
->setIcon($empower_icon)
|
||||||
|
@ -146,7 +153,7 @@ final class PhabricatorPeopleProfileManageController
|
||||||
id(new PhabricatorActionView())
|
id(new PhabricatorActionView())
|
||||||
->setIcon($disable_icon)
|
->setIcon($disable_icon)
|
||||||
->setName($disable_name)
|
->setName($disable_name)
|
||||||
->setDisabled(!$can_admin)
|
->setDisabled(!$can_disable)
|
||||||
->setWorkflow(true)
|
->setWorkflow(true)
|
||||||
->setHref($this->getApplicationURI('disable/'.$user->getID().'/')));
|
->setHref($this->getApplicationURI('disable/'.$user->getID().'/')));
|
||||||
|
|
||||||
|
@ -158,8 +165,6 @@ final class PhabricatorPeopleProfileManageController
|
||||||
->setWorkflow(true)
|
->setWorkflow(true)
|
||||||
->setHref($this->getApplicationURI('delete/'.$user->getID().'/')));
|
->setHref($this->getApplicationURI('delete/'.$user->getID().'/')));
|
||||||
|
|
||||||
$can_welcome = ($is_admin && $user->canEstablishWebSessions());
|
|
||||||
|
|
||||||
$curtain->addAction(
|
$curtain->addAction(
|
||||||
id(new PhabricatorActionView())
|
id(new PhabricatorActionView())
|
||||||
->setIcon('fa-envelope')
|
->setIcon('fa-envelope')
|
||||||
|
|
|
@ -293,45 +293,6 @@ final class PhabricatorUserEditor extends PhabricatorEditor {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @task role
|
|
||||||
*/
|
|
||||||
public function disableUser(PhabricatorUser $user, $disable) {
|
|
||||||
$actor = $this->requireActor();
|
|
||||||
|
|
||||||
if (!$user->getID()) {
|
|
||||||
throw new Exception(pht('User has not been created yet!'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$user->openTransaction();
|
|
||||||
$user->beginWriteLocking();
|
|
||||||
|
|
||||||
$user->reload();
|
|
||||||
if ($user->getIsDisabled() == $disable) {
|
|
||||||
$user->endWriteLocking();
|
|
||||||
$user->killTransaction();
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
$log = PhabricatorUserLog::initializeNewLog(
|
|
||||||
$actor,
|
|
||||||
$user->getPHID(),
|
|
||||||
PhabricatorUserLog::ACTION_DISABLE);
|
|
||||||
$log->setOldValue($user->getIsDisabled());
|
|
||||||
$log->setNewValue($disable);
|
|
||||||
|
|
||||||
$user->setIsDisabled((int)$disable);
|
|
||||||
$user->save();
|
|
||||||
|
|
||||||
$log->save();
|
|
||||||
|
|
||||||
$user->endWriteLocking();
|
|
||||||
$user->saveTransaction();
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @task role
|
* @task role
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -60,6 +60,10 @@ final class PhabricatorUserDisableTransaction
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// You must have the "Can Disable Users" permission to disable a user.
|
||||||
|
$this->requireApplicationCapability(
|
||||||
|
PeopleDisableUsersCapability::CAPABILITY);
|
||||||
|
|
||||||
if ($this->getActingAsPHID() === $object->getPHID()) {
|
if ($this->getActingAsPHID() === $object->getPHID()) {
|
||||||
$errors[] = $this->newInvalidError(
|
$errors[] = $this->newInvalidError(
|
||||||
pht('You can not enable or disable your own account.'));
|
pht('You can not enable or disable your own account.'));
|
||||||
|
@ -69,4 +73,14 @@ final class PhabricatorUserDisableTransaction
|
||||||
return $errors;
|
return $errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getRequiredCapabilities(
|
||||||
|
$object,
|
||||||
|
PhabricatorApplicationTransaction $xaction) {
|
||||||
|
|
||||||
|
// You do not need to be able to edit users to disable them. Instead, this
|
||||||
|
// requirement is replaced with a requirement that you have the "Can
|
||||||
|
// Disable Users" permission.
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,7 @@ final class PhameHomeController extends PhamePostController {
|
||||||
pht('Recent Posts'),
|
pht('Recent Posts'),
|
||||||
$this->getApplicationURI('post/'));
|
$this->getApplicationURI('post/'));
|
||||||
|
|
||||||
$page = id(new PHUIDocumentViewPro())
|
$page = id(new PHUIDocumentView())
|
||||||
->setHeader($header)
|
->setHeader($header)
|
||||||
->appendChild($post_list);
|
->appendChild($post_list);
|
||||||
|
|
||||||
|
|
|
@ -85,7 +85,7 @@ final class PhameBlogViewController extends PhameLiveController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$page = id(new PHUIDocumentViewPro())
|
$page = id(new PHUIDocumentView())
|
||||||
->setHeader($header)
|
->setHeader($header)
|
||||||
->appendChild($post_list);
|
->appendChild($post_list);
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ final class PhamePostViewController
|
||||||
$header->setActionList($actions);
|
$header->setActionList($actions);
|
||||||
}
|
}
|
||||||
|
|
||||||
$document = id(new PHUIDocumentViewPro())
|
$document = id(new PHUIDocumentView())
|
||||||
->setHeader($header);
|
->setHeader($header);
|
||||||
|
|
||||||
if ($moved) {
|
if ($moved) {
|
||||||
|
|
|
@ -56,6 +56,8 @@ final class PhabricatorPhrictionApplication extends PhabricatorApplication {
|
||||||
|
|
||||||
'edit/(?:(?P<id>[1-9]\d*)/)?' => 'PhrictionEditController',
|
'edit/(?:(?P<id>[1-9]\d*)/)?' => 'PhrictionEditController',
|
||||||
'delete/(?P<id>[1-9]\d*)/' => 'PhrictionDeleteController',
|
'delete/(?P<id>[1-9]\d*)/' => 'PhrictionDeleteController',
|
||||||
|
'publish/(?P<documentID>[1-9]\d*)/(?P<contentID>[1-9]\d*)/'
|
||||||
|
=> 'PhrictionPublishController',
|
||||||
'new/' => 'PhrictionNewController',
|
'new/' => 'PhrictionNewController',
|
||||||
'move/(?P<id>[1-9]\d*)/' => 'PhrictionMoveController',
|
'move/(?P<id>[1-9]\d*)/' => 'PhrictionMoveController',
|
||||||
|
|
||||||
|
|
|
@ -65,8 +65,8 @@ final class PhrictionDiffController extends PhrictionController {
|
||||||
|
|
||||||
$slug = $document->getSlug();
|
$slug = $document->getSlug();
|
||||||
|
|
||||||
$revert_l = $this->renderRevertButton($content_l, $current);
|
$revert_l = $this->renderRevertButton($document, $content_l, $current);
|
||||||
$revert_r = $this->renderRevertButton($content_r, $current);
|
$revert_r = $this->renderRevertButton($document, $content_r, $current);
|
||||||
|
|
||||||
$crumbs = $this->buildApplicationCrumbs();
|
$crumbs = $this->buildApplicationCrumbs();
|
||||||
$crumb_views = $this->renderBreadcrumbs($slug);
|
$crumb_views = $this->renderBreadcrumbs($slug);
|
||||||
|
@ -179,10 +179,11 @@ final class PhrictionDiffController extends PhrictionController {
|
||||||
}
|
}
|
||||||
|
|
||||||
private function renderRevertButton(
|
private function renderRevertButton(
|
||||||
|
PhrictionDocument $document,
|
||||||
PhrictionContent $content,
|
PhrictionContent $content,
|
||||||
PhrictionContent $current) {
|
PhrictionContent $current) {
|
||||||
|
|
||||||
$document_id = $content->getDocumentID();
|
$document_id = $document->getID();
|
||||||
$version = $content->getVersion();
|
$version = $content->getVersion();
|
||||||
|
|
||||||
$hidden_statuses = array(
|
$hidden_statuses = array(
|
||||||
|
|
|
@ -20,8 +20,6 @@ final class PhrictionDocumentController
|
||||||
return id(new AphrontRedirectResponse())->setURI($uri);
|
return id(new AphrontRedirectResponse())->setURI($uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
require_celerity_resource('phriction-document-css');
|
|
||||||
|
|
||||||
$version_note = null;
|
$version_note = null;
|
||||||
$core_content = '';
|
$core_content = '';
|
||||||
$move_notice = '';
|
$move_notice = '';
|
||||||
|
@ -29,6 +27,8 @@ final class PhrictionDocumentController
|
||||||
$content = null;
|
$content = null;
|
||||||
$toc = null;
|
$toc = null;
|
||||||
|
|
||||||
|
$is_draft = false;
|
||||||
|
|
||||||
$document = id(new PhrictionDocumentQuery())
|
$document = id(new PhrictionDocumentQuery())
|
||||||
->setViewer($viewer)
|
->setViewer($viewer)
|
||||||
->withSlugs(array($slug))
|
->withSlugs(array($slug))
|
||||||
|
@ -66,8 +66,9 @@ final class PhrictionDocumentController
|
||||||
->addAction($create_button);
|
->addAction($create_button);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$version = $request->getInt('v');
|
$max_version = (int)$document->getMaxVersion();
|
||||||
|
|
||||||
|
$version = $request->getInt('v');
|
||||||
if ($version) {
|
if ($version) {
|
||||||
$content = id(new PhrictionContentQuery())
|
$content = id(new PhrictionContentQuery())
|
||||||
->setViewer($viewer)
|
->setViewer($viewer)
|
||||||
|
@ -78,15 +79,111 @@ final class PhrictionDocumentController
|
||||||
return new Aphront404Response();
|
return new Aphront404Response();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($content->getID() != $document->getContentID()) {
|
// When the "v" parameter exists, the user is in history mode so we
|
||||||
$version_note = id(new PHUIInfoView())
|
// show this header even if they're looking at the current version
|
||||||
->setSeverity(PHUIInfoView::SEVERITY_NOTICE)
|
// of the document. This keeps the next/previous links working.
|
||||||
->appendChild(
|
|
||||||
pht(
|
$view_version = (int)$content->getVersion();
|
||||||
'You are viewing an older version of this document, as it '.
|
$published_version = (int)$document->getContent()->getVersion();
|
||||||
'appeared on %s.',
|
|
||||||
phabricator_datetime($content->getDateCreated(), $viewer)));
|
if ($view_version < $published_version) {
|
||||||
|
$version_note = pht(
|
||||||
|
'You are viewing an older version of this document, as it '.
|
||||||
|
'appeared on %s.',
|
||||||
|
phabricator_datetime($content->getDateCreated(), $viewer));
|
||||||
|
} else if ($view_version > $published_version) {
|
||||||
|
$is_draft = true;
|
||||||
|
$version_note = pht(
|
||||||
|
'You are viewing an unpublished draft of this document.');
|
||||||
|
} else {
|
||||||
|
$version_note = pht(
|
||||||
|
'You are viewing the current published version of this document.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$version_note = array(
|
||||||
|
phutil_tag(
|
||||||
|
'strong',
|
||||||
|
array(),
|
||||||
|
pht('Version %d of %d: ', $view_version, $max_version)),
|
||||||
|
' ',
|
||||||
|
$version_note,
|
||||||
|
);
|
||||||
|
|
||||||
|
$version_note = id(new PHUIInfoView())
|
||||||
|
->setSeverity(PHUIInfoView::SEVERITY_NOTICE)
|
||||||
|
->appendChild($version_note);
|
||||||
|
|
||||||
|
$document_uri = new PhutilURI($document->getURI());
|
||||||
|
|
||||||
|
if ($view_version > 1) {
|
||||||
|
$previous_uri = $document_uri->alter('v', ($view_version - 1));
|
||||||
|
} else {
|
||||||
|
$previous_uri = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($view_version !== $published_version) {
|
||||||
|
$current_uri = $document_uri->alter('v', $published_version);
|
||||||
|
} else {
|
||||||
|
$current_uri = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($view_version < $max_version) {
|
||||||
|
$next_uri = $document_uri->alter('v', ($view_version + 1));
|
||||||
|
} else {
|
||||||
|
$next_uri = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($view_version !== $max_version) {
|
||||||
|
$draft_uri = $document_uri->alter('v', $max_version);
|
||||||
|
} else {
|
||||||
|
$draft_uri = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$button_bar = id(new PHUIButtonBarView())
|
||||||
|
->addButton(
|
||||||
|
id(new PHUIButtonView())
|
||||||
|
->setTag('a')
|
||||||
|
->setColor('grey')
|
||||||
|
->setIcon('fa-backward')
|
||||||
|
->setDisabled(!$previous_uri)
|
||||||
|
->setHref($previous_uri)
|
||||||
|
->setText(pht('Previous')))
|
||||||
|
->addButton(
|
||||||
|
id(new PHUIButtonView())
|
||||||
|
->setTag('a')
|
||||||
|
->setColor('grey')
|
||||||
|
->setIcon('fa-file-o')
|
||||||
|
->setDisabled(!$current_uri)
|
||||||
|
->setHref($current_uri)
|
||||||
|
->setText(pht('Published')))
|
||||||
|
->addButton(
|
||||||
|
id(new PHUIButtonView())
|
||||||
|
->setTag('a')
|
||||||
|
->setColor('grey')
|
||||||
|
->setIcon('fa-forward', false)
|
||||||
|
->setDisabled(!$next_uri)
|
||||||
|
->setHref($next_uri)
|
||||||
|
->setText(pht('Next')))
|
||||||
|
->addButton(
|
||||||
|
id(new PHUIButtonView())
|
||||||
|
->setTag('a')
|
||||||
|
->setColor('grey')
|
||||||
|
->setIcon('fa-fast-forward', false)
|
||||||
|
->setDisabled(!$draft_uri)
|
||||||
|
->setHref($draft_uri)
|
||||||
|
->setText(pht('Draft')));
|
||||||
|
|
||||||
|
require_celerity_resource('phui-document-view-css');
|
||||||
|
|
||||||
|
$version_note = array(
|
||||||
|
$version_note,
|
||||||
|
phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => 'phui-document-version-navigation',
|
||||||
|
),
|
||||||
|
$button_bar),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
$content = $document->getContent();
|
$content = $document->getContent();
|
||||||
}
|
}
|
||||||
|
@ -201,7 +298,10 @@ final class PhrictionDocumentController
|
||||||
|
|
||||||
$children = $this->renderDocumentChildren($slug);
|
$children = $this->renderDocumentChildren($slug);
|
||||||
|
|
||||||
$actions = $this->buildActionView($viewer, $document);
|
$curtain = null;
|
||||||
|
if ($document->getID()) {
|
||||||
|
$curtain = $this->buildCurtain($document, $content);
|
||||||
|
}
|
||||||
|
|
||||||
$crumbs = $this->buildApplicationCrumbs();
|
$crumbs = $this->buildApplicationCrumbs();
|
||||||
$crumbs->setBorder(true);
|
$crumbs->setBorder(true);
|
||||||
|
@ -213,10 +313,17 @@ final class PhrictionDocumentController
|
||||||
$header = id(new PHUIHeaderView())
|
$header = id(new PHUIHeaderView())
|
||||||
->setUser($viewer)
|
->setUser($viewer)
|
||||||
->setPolicyObject($document)
|
->setPolicyObject($document)
|
||||||
->setHeader($page_title)
|
->setHeader($page_title);
|
||||||
->setActionList($actions);
|
|
||||||
|
|
||||||
if ($content) {
|
if ($is_draft) {
|
||||||
|
$draft_tag = id(new PHUITagView())
|
||||||
|
->setName(pht('Draft'))
|
||||||
|
->setIcon('fa-spinner')
|
||||||
|
->setColor('pink')
|
||||||
|
->setType(PHUITagView::TYPE_SHADE);
|
||||||
|
|
||||||
|
$header->addTag($draft_tag);
|
||||||
|
} else if ($content) {
|
||||||
$header->setEpoch($content->getDateCreated());
|
$header->setEpoch($content->getDateCreated());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,25 +334,30 @@ final class PhrictionDocumentController
|
||||||
}
|
}
|
||||||
$prop_list = phutil_tag_div('phui-document-view-pro-box', $prop_list);
|
$prop_list = phutil_tag_div('phui-document-view-pro-box', $prop_list);
|
||||||
|
|
||||||
$page_content = id(new PHUIDocumentViewPro())
|
$page_content = id(new PHUIDocumentView())
|
||||||
|
->setBanner($version_note)
|
||||||
->setHeader($header)
|
->setHeader($header)
|
||||||
->setToc($toc)
|
->setToc($toc)
|
||||||
->appendChild(
|
->appendChild(
|
||||||
array(
|
array(
|
||||||
$version_note,
|
|
||||||
$move_notice,
|
$move_notice,
|
||||||
$core_content,
|
$core_content,
|
||||||
));
|
));
|
||||||
|
|
||||||
|
if ($curtain) {
|
||||||
|
$page_content->setCurtain($curtain);
|
||||||
|
}
|
||||||
|
|
||||||
return $this->newPage()
|
return $this->newPage()
|
||||||
->setTitle($page_title)
|
->setTitle($page_title)
|
||||||
->setCrumbs($crumbs)
|
->setCrumbs($crumbs)
|
||||||
->setPageObjectPHIDs(array($document->getPHID()))
|
->setPageObjectPHIDs(array($document->getPHID()))
|
||||||
->appendChild(array(
|
->appendChild(
|
||||||
$page_content,
|
array(
|
||||||
$prop_list,
|
$page_content,
|
||||||
$children,
|
$prop_list,
|
||||||
));
|
$children,
|
||||||
|
));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,8 +369,7 @@ final class PhrictionDocumentController
|
||||||
$viewer = $this->getViewer();
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
$view = id(new PHUIPropertyListView())
|
$view = id(new PHUIPropertyListView())
|
||||||
->setUser($viewer)
|
->setUser($viewer);
|
||||||
->setObject($document);
|
|
||||||
|
|
||||||
$view->addProperty(
|
$view->addProperty(
|
||||||
pht('Last Author'),
|
pht('Last Author'),
|
||||||
|
@ -271,37 +382,70 @@ final class PhrictionDocumentController
|
||||||
return $view;
|
return $view;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function buildActionView(
|
private function buildCurtain(
|
||||||
PhabricatorUser $viewer,
|
PhrictionDocument $document,
|
||||||
PhrictionDocument $document) {
|
PhrictionContent $content) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||||
$viewer,
|
$viewer,
|
||||||
$document,
|
$document,
|
||||||
PhabricatorPolicyCapability::CAN_EDIT);
|
PhabricatorPolicyCapability::CAN_EDIT);
|
||||||
|
|
||||||
$slug = PhabricatorSlug::normalize($this->slug);
|
$slug = PhabricatorSlug::normalize($this->slug);
|
||||||
|
$id = $document->getID();
|
||||||
|
|
||||||
$action_view = id(new PhabricatorActionListView())
|
$curtain = $this->newCurtainView($document);
|
||||||
->setUser($viewer)
|
|
||||||
->setObject($document);
|
|
||||||
|
|
||||||
if (!$document->getID()) {
|
$curtain->addAction(
|
||||||
return $action_view->addAction(
|
|
||||||
id(new PhabricatorActionView())
|
|
||||||
->setName(pht('Create This Document'))
|
|
||||||
->setIcon('fa-plus-square')
|
|
||||||
->setHref('/phriction/edit/?slug='.$slug));
|
|
||||||
}
|
|
||||||
|
|
||||||
$action_view->addAction(
|
|
||||||
id(new PhabricatorActionView())
|
id(new PhabricatorActionView())
|
||||||
->setName(pht('Edit Document'))
|
->setName(pht('Edit Document'))
|
||||||
->setDisabled(!$can_edit)
|
->setDisabled(!$can_edit)
|
||||||
->setIcon('fa-pencil')
|
->setIcon('fa-pencil')
|
||||||
->setHref('/phriction/edit/'.$document->getID().'/'));
|
->setHref('/phriction/edit/'.$document->getID().'/'));
|
||||||
|
|
||||||
|
$curtain->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setName(pht('View History'))
|
||||||
|
->setIcon('fa-history')
|
||||||
|
->setHref(PhrictionDocument::getSlugURI($slug, 'history')));
|
||||||
|
|
||||||
|
$is_current = false;
|
||||||
|
$content_id = null;
|
||||||
|
$is_draft = false;
|
||||||
|
if ($content) {
|
||||||
|
if ($content->getPHID() == $document->getContentPHID()) {
|
||||||
|
$is_current = true;
|
||||||
|
}
|
||||||
|
$content_id = $content->getID();
|
||||||
|
|
||||||
|
$current_version = $document->getContent()->getVersion();
|
||||||
|
$is_draft = ($content->getVersion() >= $current_version);
|
||||||
|
}
|
||||||
|
$can_publish = ($can_edit && $content && !$is_current);
|
||||||
|
|
||||||
|
if ($is_draft) {
|
||||||
|
$publish_name = pht('Publish Draft');
|
||||||
|
} else {
|
||||||
|
$publish_name = pht('Publish Revert');
|
||||||
|
}
|
||||||
|
|
||||||
|
$publish_uri = "/phriction/publish/{$id}/{$content_id}/";
|
||||||
|
|
||||||
|
if (PhabricatorEnv::getEnvConfig('phabricator.show-prototypes')) {
|
||||||
|
$publish_name = pht('Publish (Prototype!)');
|
||||||
|
|
||||||
|
$curtain->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setName($publish_name)
|
||||||
|
->setIcon('fa-upload')
|
||||||
|
->setDisabled(!$can_publish)
|
||||||
|
->setWorkflow(true)
|
||||||
|
->setHref($publish_uri));
|
||||||
|
}
|
||||||
|
|
||||||
if ($document->getStatus() == PhrictionDocumentStatus::STATUS_EXISTS) {
|
if ($document->getStatus() == PhrictionDocumentStatus::STATUS_EXISTS) {
|
||||||
$action_view->addAction(
|
$curtain->addAction(
|
||||||
id(new PhabricatorActionView())
|
id(new PhabricatorActionView())
|
||||||
->setName(pht('Move Document'))
|
->setName(pht('Move Document'))
|
||||||
->setDisabled(!$can_edit)
|
->setDisabled(!$can_edit)
|
||||||
|
@ -309,7 +453,7 @@ final class PhrictionDocumentController
|
||||||
->setHref('/phriction/move/'.$document->getID().'/')
|
->setHref('/phriction/move/'.$document->getID().'/')
|
||||||
->setWorkflow(true));
|
->setWorkflow(true));
|
||||||
|
|
||||||
$action_view->addAction(
|
$curtain->addAction(
|
||||||
id(new PhabricatorActionView())
|
id(new PhabricatorActionView())
|
||||||
->setName(pht('Delete Document'))
|
->setName(pht('Delete Document'))
|
||||||
->setDisabled(!$can_edit)
|
->setDisabled(!$can_edit)
|
||||||
|
@ -318,23 +462,16 @@ final class PhrictionDocumentController
|
||||||
->setWorkflow(true));
|
->setWorkflow(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
$action_view->addAction(
|
|
||||||
id(new PhabricatorActionView())
|
|
||||||
->setName(pht('View History'))
|
|
||||||
->setIcon('fa-list')
|
|
||||||
->setHref(PhrictionDocument::getSlugURI($slug, 'history')));
|
|
||||||
|
|
||||||
$print_uri = PhrictionDocument::getSlugURI($slug).'?__print__=1';
|
$print_uri = PhrictionDocument::getSlugURI($slug).'?__print__=1';
|
||||||
|
|
||||||
$action_view->addAction(
|
$curtain->addAction(
|
||||||
id(new PhabricatorActionView())
|
id(new PhabricatorActionView())
|
||||||
->setName(pht('Printable Page'))
|
->setName(pht('Printable Page'))
|
||||||
->setIcon('fa-print')
|
->setIcon('fa-print')
|
||||||
->setOpenInNewWindow(true)
|
->setOpenInNewWindow(true)
|
||||||
->setHref($print_uri));
|
->setHref($print_uri));
|
||||||
|
|
||||||
return $action_view;
|
return $curtain;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function renderDocumentChildren($slug) {
|
private function renderDocumentChildren($slug) {
|
||||||
|
|
|
@ -7,7 +7,7 @@ final class PhrictionEditController
|
||||||
$viewer = $request->getViewer();
|
$viewer = $request->getViewer();
|
||||||
$id = $request->getURIData('id');
|
$id = $request->getURIData('id');
|
||||||
|
|
||||||
$current_version = null;
|
$max_version = null;
|
||||||
if ($id) {
|
if ($id) {
|
||||||
$is_new = false;
|
$is_new = false;
|
||||||
$document = id(new PhrictionDocumentQuery())
|
$document = id(new PhrictionDocumentQuery())
|
||||||
|
@ -24,7 +24,7 @@ final class PhrictionEditController
|
||||||
return new Aphront404Response();
|
return new Aphront404Response();
|
||||||
}
|
}
|
||||||
|
|
||||||
$current_version = $document->getContent()->getVersion();
|
$max_version = $document->getMaxVersion();
|
||||||
|
|
||||||
$revert = $request->getInt('revert');
|
$revert = $request->getInt('revert');
|
||||||
if ($revert) {
|
if ($revert) {
|
||||||
|
@ -37,9 +37,12 @@ final class PhrictionEditController
|
||||||
return new Aphront404Response();
|
return new Aphront404Response();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$content = $document->getContent();
|
$content = id(new PhrictionContentQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withDocumentPHIDs(array($document->getPHID()))
|
||||||
|
->setLimit(1)
|
||||||
|
->executeOne();
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$slug = $request->getStr('slug');
|
$slug = $request->getStr('slug');
|
||||||
$slug = PhabricatorSlug::normalize($slug);
|
$slug = PhabricatorSlug::normalize($slug);
|
||||||
|
@ -54,8 +57,13 @@ final class PhrictionEditController
|
||||||
->executeOne();
|
->executeOne();
|
||||||
|
|
||||||
if ($document) {
|
if ($document) {
|
||||||
$content = $document->getContent();
|
$content = id(new PhrictionContentQuery())
|
||||||
$current_version = $content->getVersion();
|
->setViewer($viewer)
|
||||||
|
->withDocumentPHIDs(array($document->getPHID()))
|
||||||
|
->setLimit(1)
|
||||||
|
->executeOne();
|
||||||
|
|
||||||
|
$max_version = $document->getMaxVersion();
|
||||||
$is_new = false;
|
$is_new = false;
|
||||||
} else {
|
} else {
|
||||||
$document = PhrictionDocument::initializeNewDocument($viewer, $slug);
|
$document = PhrictionDocument::initializeNewDocument($viewer, $slug);
|
||||||
|
@ -128,7 +136,7 @@ final class PhrictionEditController
|
||||||
$title = $request->getStr('title');
|
$title = $request->getStr('title');
|
||||||
$content_text = $request->getStr('content');
|
$content_text = $request->getStr('content');
|
||||||
$notes = $request->getStr('description');
|
$notes = $request->getStr('description');
|
||||||
$current_version = $request->getInt('contentVersion');
|
$max_version = $request->getInt('contentVersion');
|
||||||
$v_view = $request->getStr('viewPolicy');
|
$v_view = $request->getStr('viewPolicy');
|
||||||
$v_edit = $request->getStr('editPolicy');
|
$v_edit = $request->getStr('editPolicy');
|
||||||
$v_cc = $request->getArr('cc');
|
$v_cc = $request->getArr('cc');
|
||||||
|
@ -168,7 +176,7 @@ final class PhrictionEditController
|
||||||
->setContinueOnNoEffect(true)
|
->setContinueOnNoEffect(true)
|
||||||
->setDescription($notes)
|
->setDescription($notes)
|
||||||
->setProcessContentVersionError(!$request->getBool('overwrite'))
|
->setProcessContentVersionError(!$request->getBool('overwrite'))
|
||||||
->setContentVersion($current_version);
|
->setContentVersion($max_version);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$editor->applyTransactions($document, $xactions);
|
$editor->applyTransactions($document, $xactions);
|
||||||
|
@ -226,19 +234,13 @@ final class PhrictionEditController
|
||||||
->execute();
|
->execute();
|
||||||
$view_capability = PhabricatorPolicyCapability::CAN_VIEW;
|
$view_capability = PhabricatorPolicyCapability::CAN_VIEW;
|
||||||
$edit_capability = PhabricatorPolicyCapability::CAN_EDIT;
|
$edit_capability = PhabricatorPolicyCapability::CAN_EDIT;
|
||||||
$codex = id(PhabricatorPolicyCodex::newFromObject($document, $viewer))
|
|
||||||
->setCapability($view_capability);
|
|
||||||
|
|
||||||
$view_capability_description = $codex->getPolicySpecialRuleForCapability(
|
|
||||||
PhabricatorPolicyCapability::CAN_VIEW)->getDescription();
|
|
||||||
$edit_capability_description = $codex->getPolicySpecialRuleForCapability(
|
|
||||||
PhabricatorPolicyCapability::CAN_EDIT)->getDescription();
|
|
||||||
|
|
||||||
$form = id(new AphrontFormView())
|
$form = id(new AphrontFormView())
|
||||||
->setUser($viewer)
|
->setUser($viewer)
|
||||||
->addHiddenInput('slug', $document->getSlug())
|
->addHiddenInput('slug', $document->getSlug())
|
||||||
->addHiddenInput('nodraft', $request->getBool('nodraft'))
|
->addHiddenInput('nodraft', $request->getBool('nodraft'))
|
||||||
->addHiddenInput('contentVersion', $current_version)
|
->addHiddenInput('contentVersion', $max_version)
|
||||||
->addHiddenInput('overwrite', $overwrite)
|
->addHiddenInput('overwrite', $overwrite)
|
||||||
->appendChild(
|
->appendChild(
|
||||||
id(new AphrontFormTextControl())
|
id(new AphrontFormTextControl())
|
||||||
|
@ -279,15 +281,13 @@ final class PhrictionEditController
|
||||||
->setSpacePHID($v_space)
|
->setSpacePHID($v_space)
|
||||||
->setPolicyObject($document)
|
->setPolicyObject($document)
|
||||||
->setCapability($view_capability)
|
->setCapability($view_capability)
|
||||||
->setPolicies($policies)
|
->setPolicies($policies))
|
||||||
->setCaption($view_capability_description))
|
|
||||||
->appendChild(
|
->appendChild(
|
||||||
id(new AphrontFormPolicyControl())
|
id(new AphrontFormPolicyControl())
|
||||||
->setName('editPolicy')
|
->setName('editPolicy')
|
||||||
->setPolicyObject($document)
|
->setPolicyObject($document)
|
||||||
->setCapability($edit_capability)
|
->setCapability($edit_capability)
|
||||||
->setPolicies($policies)
|
->setPolicies($policies))
|
||||||
->setCaption($edit_capability_description))
|
|
||||||
->appendChild(
|
->appendChild(
|
||||||
id(new AphrontFormTextControl())
|
id(new AphrontFormTextControl())
|
||||||
->setLabel(pht('Edit Notes'))
|
->setLabel(pht('Edit Notes'))
|
||||||
|
@ -323,17 +323,17 @@ final class PhrictionEditController
|
||||||
$crumbs->setBorder(true);
|
$crumbs->setBorder(true);
|
||||||
|
|
||||||
$view = id(new PHUITwoColumnView())
|
$view = id(new PHUITwoColumnView())
|
||||||
->setFooter(array(
|
->setFooter(
|
||||||
$draft_note,
|
array(
|
||||||
$form_box,
|
$draft_note,
|
||||||
$preview,
|
$form_box,
|
||||||
));
|
$preview,
|
||||||
|
));
|
||||||
|
|
||||||
return $this->newPage()
|
return $this->newPage()
|
||||||
->setTitle($page_title)
|
->setTitle($page_title)
|
||||||
->setCrumbs($crumbs)
|
->setCrumbs($crumbs)
|
||||||
->appendChild($view);
|
->appendChild($view);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,32 +31,18 @@ final class PhrictionHistoryController
|
||||||
->executeWithCursorPager($pager);
|
->executeWithCursorPager($pager);
|
||||||
|
|
||||||
$author_phids = mpull($history, 'getAuthorPHID');
|
$author_phids = mpull($history, 'getAuthorPHID');
|
||||||
$handles = $this->loadViewerHandles($author_phids);
|
$handles = $viewer->loadHandles($author_phids);
|
||||||
|
|
||||||
|
$max_version = (int)$document->getMaxVersion();
|
||||||
|
$current_version = $document->getContent()->getVersion();
|
||||||
|
|
||||||
$list = new PHUIObjectItemListView();
|
$list = new PHUIObjectItemListView();
|
||||||
$list->setFlush(true);
|
$list->setFlush(true);
|
||||||
|
|
||||||
foreach ($history as $content) {
|
foreach ($history as $content) {
|
||||||
|
|
||||||
$author = $handles[$content->getAuthorPHID()]->renderLink();
|
|
||||||
$slug_uri = PhrictionDocument::getSlugURI($document->getSlug());
|
$slug_uri = PhrictionDocument::getSlugURI($document->getSlug());
|
||||||
$version = $content->getVersion();
|
$version = $content->getVersion();
|
||||||
|
|
||||||
$diff_uri = new PhutilURI('/phriction/diff/'.$document->getID().'/');
|
$base_uri = new PhutilURI('/phriction/diff/'.$document->getID().'/');
|
||||||
|
|
||||||
$vs_previous = null;
|
|
||||||
if ($content->getVersion() != 1) {
|
|
||||||
$vs_previous = $diff_uri
|
|
||||||
->alter('l', $content->getVersion() - 1)
|
|
||||||
->alter('r', $content->getVersion());
|
|
||||||
}
|
|
||||||
|
|
||||||
$vs_head = null;
|
|
||||||
if ($content->getID() != $document->getContentID()) {
|
|
||||||
$vs_head = $diff_uri
|
|
||||||
->alter('l', $content->getVersion())
|
|
||||||
->alter('r', $current->getVersion());
|
|
||||||
}
|
|
||||||
|
|
||||||
$change_type = PhrictionChangeType::getChangeTypeLabel(
|
$change_type = PhrictionChangeType::getChangeTypeLabel(
|
||||||
$content->getChangeType());
|
$content->getChangeType());
|
||||||
|
@ -68,63 +54,90 @@ final class PhrictionHistoryController
|
||||||
$color = 'lightbluetext';
|
$color = 'lightbluetext';
|
||||||
break;
|
break;
|
||||||
case PhrictionChangeType::CHANGE_MOVE_HERE:
|
case PhrictionChangeType::CHANGE_MOVE_HERE:
|
||||||
$color = 'yellow';
|
$color = 'yellow';
|
||||||
break;
|
break;
|
||||||
case PhrictionChangeType::CHANGE_MOVE_AWAY:
|
case PhrictionChangeType::CHANGE_MOVE_AWAY:
|
||||||
$color = 'orange';
|
$color = 'orange';
|
||||||
break;
|
break;
|
||||||
case PhrictionChangeType::CHANGE_STUB:
|
case PhrictionChangeType::CHANGE_STUB:
|
||||||
$color = 'green';
|
$color = 'green';
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Exception(pht('Unknown change type!'));
|
$color = 'indigo';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$version_uri = $slug_uri.'?v='.$version;
|
||||||
|
|
||||||
$item = id(new PHUIObjectItemView())
|
$item = id(new PHUIObjectItemView())
|
||||||
->setHeader(pht('%s by %s', $change_type, $author))
|
->setHref($version_uri);
|
||||||
->setStatusIcon('fa-file '.$color)
|
|
||||||
->addAttribute(
|
|
||||||
phutil_tag(
|
|
||||||
'a',
|
|
||||||
array(
|
|
||||||
'href' => $slug_uri.'?v='.$version,
|
|
||||||
),
|
|
||||||
pht('Version %s', $version)))
|
|
||||||
->addAttribute(pht('%s %s',
|
|
||||||
phabricator_date($content->getDateCreated(), $viewer),
|
|
||||||
phabricator_time($content->getDateCreated(), $viewer)));
|
|
||||||
|
|
||||||
if ($content->getDescription()) {
|
if ($version > $current_version) {
|
||||||
$item->addAttribute($content->getDescription());
|
$icon = 'fa-spinner';
|
||||||
}
|
$color = 'pink';
|
||||||
|
$header = pht('Draft %d', $version);
|
||||||
if ($vs_previous) {
|
|
||||||
$item->addIcon(
|
|
||||||
'fa-reply',
|
|
||||||
pht('Show Change'),
|
|
||||||
array(
|
|
||||||
'href' => $vs_previous,
|
|
||||||
));
|
|
||||||
} else {
|
} else {
|
||||||
$item->addIcon(
|
$icon = 'fa-file-o';
|
||||||
'fa-reply grey',
|
$header = pht('Version %d', $version);
|
||||||
phutil_tag('em', array(), pht('No previous change')));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($vs_head) {
|
if ($version == $current_version) {
|
||||||
$item->addIcon(
|
$item->setEffect('selected');
|
||||||
'fa-reply-all',
|
|
||||||
pht('Show Later Changes'),
|
|
||||||
array(
|
|
||||||
'href' => $vs_head,
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
$item->addIcon(
|
|
||||||
'fa-reply-all grey',
|
|
||||||
phutil_tag('em', array(), pht('No later changes')));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$item
|
||||||
|
->setHeader($header)
|
||||||
|
->setStatusIcon($icon.' '.$color);
|
||||||
|
|
||||||
|
$description = $content->getDescription();
|
||||||
|
if (strlen($description)) {
|
||||||
|
$item->addAttribute($description);
|
||||||
|
}
|
||||||
|
|
||||||
|
$item->addIcon(
|
||||||
|
null,
|
||||||
|
phabricator_datetime($content->getDateCreated(), $viewer));
|
||||||
|
|
||||||
|
$author_phid = $content->getAuthorPHID();
|
||||||
|
$item->addByline($viewer->renderHandle($author_phid));
|
||||||
|
|
||||||
|
$diff_uri = null;
|
||||||
|
if ($version > 1) {
|
||||||
|
$diff_uri = $base_uri
|
||||||
|
->alter('l', $version - 1)
|
||||||
|
->alter('r', $version);
|
||||||
|
} else {
|
||||||
|
$diff_uri = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($content->getVersion() != $max_version) {
|
||||||
|
$compare_uri = $base_uri
|
||||||
|
->alter('l', $version)
|
||||||
|
->alter('r', $max_version);
|
||||||
|
} else {
|
||||||
|
$compare_uri = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$button_bar = id(new PHUIButtonBarView())
|
||||||
|
->addButton(
|
||||||
|
id(new PHUIButtonView())
|
||||||
|
->setTag('a')
|
||||||
|
->setColor('grey')
|
||||||
|
->setIcon('fa-chevron-down')
|
||||||
|
->setDisabled(!$diff_uri)
|
||||||
|
->setHref($diff_uri)
|
||||||
|
->setText(pht('Diff')))
|
||||||
|
->addButton(
|
||||||
|
id(new PHUIButtonView())
|
||||||
|
->setTag('a')
|
||||||
|
->setColor('grey')
|
||||||
|
->setIcon('fa-chevron-circle-up')
|
||||||
|
->setDisabled(!$compare_uri)
|
||||||
|
->setHref($compare_uri)
|
||||||
|
->setText(pht('Compare')));
|
||||||
|
|
||||||
|
$item->setSideColumn($button_bar);
|
||||||
|
|
||||||
$list->addItem($item);
|
$list->addItem($item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhrictionPublishController
|
||||||
|
extends PhrictionController {
|
||||||
|
|
||||||
|
public function handleRequest(AphrontRequest $request) {
|
||||||
|
$viewer = $request->getViewer();
|
||||||
|
$id = $request->getURIData('documentID');
|
||||||
|
$content_id = $request->getURIData('contentID');
|
||||||
|
|
||||||
|
$document = id(new PhrictionDocumentQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withIDs(array($id))
|
||||||
|
->needContent(true)
|
||||||
|
->requireCapabilities(
|
||||||
|
array(
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
))
|
||||||
|
->executeOne();
|
||||||
|
if (!$document) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
$document_uri = $document->getURI();
|
||||||
|
|
||||||
|
$content = id(new PhrictionContentQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withIDs(array($content_id))
|
||||||
|
->executeOne();
|
||||||
|
if (!$content) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($content->getPHID() == $document->getContentPHID()) {
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('Already Published'))
|
||||||
|
->appendChild(
|
||||||
|
pht(
|
||||||
|
'This version of the document is already the published '.
|
||||||
|
'version.'))
|
||||||
|
->addCancelButton($document_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
$content_uri = $document_uri.'?v='.$content->getVersion();
|
||||||
|
|
||||||
|
if ($request->isFormPost()) {
|
||||||
|
$xactions = array();
|
||||||
|
|
||||||
|
$xactions[] = id(new PhrictionTransaction())
|
||||||
|
->setTransactionType(
|
||||||
|
PhrictionDocumentPublishTransaction::TRANSACTIONTYPE)
|
||||||
|
->setNewValue($content->getPHID());
|
||||||
|
|
||||||
|
id(new PhrictionTransactionEditor())
|
||||||
|
->setActor($viewer)
|
||||||
|
->setContentSourceFromRequest($request)
|
||||||
|
->setContinueOnNoEffect(true)
|
||||||
|
->setContinueOnMissingFields(true)
|
||||||
|
->applyTransactions($document, $xactions);
|
||||||
|
|
||||||
|
return id(new AphrontRedirectResponse())->setURI($document_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($content->getVersion() < $document->getContent()->getVersion()) {
|
||||||
|
$title = pht('Revert Document?');
|
||||||
|
$body = pht(
|
||||||
|
'Revert the published version of this document to an older '.
|
||||||
|
'version?');
|
||||||
|
$button = pht('Revert');
|
||||||
|
} else {
|
||||||
|
$title = pht('Publish Draft?');
|
||||||
|
$body = pht(
|
||||||
|
'Update the published version of this document to this newer '.
|
||||||
|
'version?');
|
||||||
|
$button = pht('Publish');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle($title)
|
||||||
|
->appendChild($body)
|
||||||
|
->addSubmitButton($button)
|
||||||
|
->addCancelButton($content_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -93,29 +93,13 @@ final class PhrictionTransactionEditor
|
||||||
return $types;
|
return $types;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function shouldApplyInitialEffects(
|
protected function expandTransactions(
|
||||||
PhabricatorLiskDAO $object,
|
|
||||||
array $xactions) {
|
|
||||||
|
|
||||||
foreach ($xactions as $xaction) {
|
|
||||||
switch ($xaction->getTransactionType()) {
|
|
||||||
case PhrictionDocumentTitleTransaction::TRANSACTIONTYPE:
|
|
||||||
case PhrictionDocumentContentTransaction::TRANSACTIONTYPE:
|
|
||||||
case PhrictionDocumentDeleteTransaction::TRANSACTIONTYPE:
|
|
||||||
case PhrictionDocumentMoveToTransaction::TRANSACTIONTYPE:
|
|
||||||
case PhrictionDocumentMoveAwayTransaction::TRANSACTIONTYPE:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return parent::shouldApplyInitialEffects($object, $xactions);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function applyInitialEffects(
|
|
||||||
PhabricatorLiskDAO $object,
|
PhabricatorLiskDAO $object,
|
||||||
array $xactions) {
|
array $xactions) {
|
||||||
|
|
||||||
$this->setOldContent($object->getContent());
|
$this->setOldContent($object->getContent());
|
||||||
$this->setNewContent($this->buildNewContentTemplate($object));
|
|
||||||
|
return parent::expandTransactions($object, $xactions);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function expandTransaction(
|
protected function expandTransaction(
|
||||||
|
@ -148,7 +132,6 @@ final class PhrictionTransactionEditor
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $xactions;
|
return $xactions;
|
||||||
|
@ -158,29 +141,12 @@ final class PhrictionTransactionEditor
|
||||||
PhabricatorLiskDAO $object,
|
PhabricatorLiskDAO $object,
|
||||||
array $xactions) {
|
array $xactions) {
|
||||||
|
|
||||||
$save_content = false;
|
if ($this->hasNewDocumentContent()) {
|
||||||
foreach ($xactions as $xaction) {
|
$content = $this->getNewDocumentContent($object);
|
||||||
switch ($xaction->getTransactionType()) {
|
|
||||||
case PhrictionDocumentTitleTransaction::TRANSACTIONTYPE:
|
|
||||||
case PhrictionDocumentMoveToTransaction::TRANSACTIONTYPE:
|
|
||||||
case PhrictionDocumentMoveAwayTransaction::TRANSACTIONTYPE:
|
|
||||||
case PhrictionDocumentDeleteTransaction::TRANSACTIONTYPE:
|
|
||||||
case PhrictionDocumentContentTransaction::TRANSACTIONTYPE:
|
|
||||||
$save_content = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($save_content) {
|
$content
|
||||||
$content = $this->getNewContent();
|
->setDocumentPHID($object->getPHID())
|
||||||
$content->setDocumentID($object->getID());
|
->save();
|
||||||
$content->save();
|
|
||||||
|
|
||||||
$object->setContentID($content->getID());
|
|
||||||
$object->save();
|
|
||||||
$object->attachContent($content);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->getIsNewObject() && !$this->getSkipAncestorCheck()) {
|
if ($this->getIsNewObject() && !$this->getSkipAncestorCheck()) {
|
||||||
|
@ -502,7 +468,7 @@ final class PhrictionTransactionEditor
|
||||||
|
|
||||||
$error = null;
|
$error = null;
|
||||||
if ($this->getContentVersion() &&
|
if ($this->getContentVersion() &&
|
||||||
($object->getContent()->getVersion() != $this->getContentVersion())) {
|
($object->getMaxVersion() != $this->getContentVersion())) {
|
||||||
$error = new PhabricatorApplicationTransactionValidationError(
|
$error = new PhabricatorApplicationTransactionValidationError(
|
||||||
$type,
|
$type,
|
||||||
pht('Edit Conflict'),
|
pht('Edit Conflict'),
|
||||||
|
@ -535,24 +501,48 @@ final class PhrictionTransactionEditor
|
||||||
->setDocument($object);
|
->setDocument($object);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function buildNewContentTemplate(
|
private function hasNewDocumentContent() {
|
||||||
PhrictionDocument $document) {
|
return (bool)$this->newContent;
|
||||||
|
}
|
||||||
|
|
||||||
$new_content = id(new PhrictionContent())
|
public function getNewDocumentContent(PhrictionDocument $document) {
|
||||||
|
if (!$this->hasNewDocumentContent()) {
|
||||||
|
$content = $this->newDocumentContent($document);
|
||||||
|
|
||||||
|
// Generate a PHID now so we can populate "contentPHID" before saving
|
||||||
|
// the document to the database: the column is not nullable so we need
|
||||||
|
// a value.
|
||||||
|
$content_phid = $content->generatePHID();
|
||||||
|
|
||||||
|
$content->setPHID($content_phid);
|
||||||
|
|
||||||
|
$document->setContentPHID($content_phid);
|
||||||
|
$document->attachContent($content);
|
||||||
|
$document->setEditedEpoch(PhabricatorTime::getNow());
|
||||||
|
$document->setMaxVersion($content->getVersion());
|
||||||
|
|
||||||
|
$this->newContent = $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->newContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function newDocumentContent(PhrictionDocument $document) {
|
||||||
|
$content = id(new PhrictionContent())
|
||||||
->setSlug($document->getSlug())
|
->setSlug($document->getSlug())
|
||||||
->setAuthorPHID($this->getActor()->getPHID())
|
->setAuthorPHID($this->getActingAsPHID())
|
||||||
->setChangeType(PhrictionChangeType::CHANGE_EDIT)
|
->setChangeType(PhrictionChangeType::CHANGE_EDIT)
|
||||||
->setTitle($this->getOldContent()->getTitle())
|
->setTitle($this->getOldContent()->getTitle())
|
||||||
->setContent($this->getOldContent()->getContent())
|
->setContent($this->getOldContent()->getContent())
|
||||||
->setDescription('');
|
->setDescription('');
|
||||||
|
|
||||||
if (strlen($this->getDescription())) {
|
if (strlen($this->getDescription())) {
|
||||||
$new_content->setDescription($this->getDescription());
|
$content->setDescription($this->getDescription());
|
||||||
}
|
}
|
||||||
|
|
||||||
$new_content->setVersion($this->getOldContent()->getVersion() + 1);
|
$content->setVersion($document->getMaxVersion() + 1);
|
||||||
|
|
||||||
return $new_content;
|
return $content;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getCustomWorkerState() {
|
protected function getCustomWorkerState() {
|
||||||
|
|
|
@ -76,7 +76,7 @@ final class PhrictionContentQuery
|
||||||
if ($this->shouldJoinDocumentTable()) {
|
if ($this->shouldJoinDocumentTable()) {
|
||||||
$joins[] = qsprintf(
|
$joins[] = qsprintf(
|
||||||
$conn,
|
$conn,
|
||||||
'JOIN %T d ON d.id = c.documentID',
|
'JOIN %T d ON d.phid = c.documentPHID',
|
||||||
id(new PhrictionDocument())->getTableName());
|
id(new PhrictionDocument())->getTableName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,19 +84,19 @@ final class PhrictionContentQuery
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function willFilterPage(array $contents) {
|
protected function willFilterPage(array $contents) {
|
||||||
$document_ids = mpull($contents, 'getDocumentID');
|
$document_phids = mpull($contents, 'getDocumentPHID');
|
||||||
|
|
||||||
$documents = id(new PhrictionDocumentQuery())
|
$documents = id(new PhrictionDocumentQuery())
|
||||||
->setViewer($this->getViewer())
|
->setViewer($this->getViewer())
|
||||||
->setParentQuery($this)
|
->setParentQuery($this)
|
||||||
->withIDs($document_ids)
|
->withPHIDs($document_phids)
|
||||||
->execute();
|
->execute();
|
||||||
$documents = mpull($documents, null, 'getID');
|
$documents = mpull($documents, null, 'getPHID');
|
||||||
|
|
||||||
foreach ($contents as $key => $content) {
|
foreach ($contents as $key => $content) {
|
||||||
$document_id = $content->getDocumentID();
|
$document_phid = $content->getDocumentPHID();
|
||||||
|
|
||||||
$document = idx($documents, $document_id);
|
$document = idx($documents, $document_phid);
|
||||||
if (!$document) {
|
if (!$document) {
|
||||||
unset($contents[$key]);
|
unset($contents[$key]);
|
||||||
$this->didRejectResult($content);
|
$this->didRejectResult($content);
|
||||||
|
|
|
@ -151,17 +151,17 @@ final class PhrictionDocumentQuery
|
||||||
$contents = id(new PhrictionContentQuery())
|
$contents = id(new PhrictionContentQuery())
|
||||||
->setViewer($this->getViewer())
|
->setViewer($this->getViewer())
|
||||||
->setParentQuery($this)
|
->setParentQuery($this)
|
||||||
->withIDs(mpull($documents, 'getContentID'))
|
->withPHIDs(mpull($documents, 'getContentPHID'))
|
||||||
->execute();
|
->execute();
|
||||||
$contents = mpull($contents, null, 'getID');
|
$contents = mpull($contents, null, 'getPHID');
|
||||||
|
|
||||||
foreach ($documents as $key => $document) {
|
foreach ($documents as $key => $document) {
|
||||||
$content_id = $document->getContentID();
|
$content_phid = $document->getContentPHID();
|
||||||
if (empty($contents[$content_id])) {
|
if (empty($contents[$content_phid])) {
|
||||||
unset($documents[$key]);
|
unset($documents[$key]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$document->attachContent($contents[$content_id]);
|
$document->attachContent($contents[$content_phid]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,7 +175,7 @@ final class PhrictionDocumentQuery
|
||||||
$content_dao = new PhrictionContent();
|
$content_dao = new PhrictionContent();
|
||||||
$joins[] = qsprintf(
|
$joins[] = qsprintf(
|
||||||
$conn,
|
$conn,
|
||||||
'JOIN %T c ON d.contentID = c.id',
|
'JOIN %T c ON d.contentPHID = c.phid',
|
||||||
$content_dao->getTableName());
|
$content_dao->getTableName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,7 +321,7 @@ final class PhrictionDocumentQuery
|
||||||
public function getBuiltinOrders() {
|
public function getBuiltinOrders() {
|
||||||
return parent::getBuiltinOrders() + array(
|
return parent::getBuiltinOrders() + array(
|
||||||
self::ORDER_HIERARCHY => array(
|
self::ORDER_HIERARCHY => array(
|
||||||
'vector' => array('depth', 'title', 'updated'),
|
'vector' => array('depth', 'title', 'updated', 'id'),
|
||||||
'name' => pht('Hierarchy'),
|
'name' => pht('Hierarchy'),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -343,9 +343,9 @@ final class PhrictionDocumentQuery
|
||||||
),
|
),
|
||||||
'updated' => array(
|
'updated' => array(
|
||||||
'table' => 'd',
|
'table' => 'd',
|
||||||
'column' => 'contentID',
|
'column' => 'editedEpoch',
|
||||||
'type' => 'int',
|
'type' => 'int',
|
||||||
'unique' => true,
|
'unique' => false,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -356,7 +356,7 @@ final class PhrictionDocumentQuery
|
||||||
$map = array(
|
$map = array(
|
||||||
'id' => $document->getID(),
|
'id' => $document->getID(),
|
||||||
'depth' => $document->getDepth(),
|
'depth' => $document->getDepth(),
|
||||||
'updated' => $document->getContentID(),
|
'updated' => $document->getEditedEpoch(),
|
||||||
);
|
);
|
||||||
|
|
||||||
foreach ($keys as $key) {
|
foreach ($keys as $key) {
|
||||||
|
|
|
@ -7,7 +7,7 @@ final class PhrictionContent
|
||||||
PhabricatorDestructibleInterface,
|
PhabricatorDestructibleInterface,
|
||||||
PhabricatorConduitResultInterface {
|
PhabricatorConduitResultInterface {
|
||||||
|
|
||||||
protected $documentID;
|
protected $documentPHID;
|
||||||
protected $version;
|
protected $version;
|
||||||
protected $authorPHID;
|
protected $authorPHID;
|
||||||
|
|
||||||
|
@ -34,8 +34,8 @@ final class PhrictionContent
|
||||||
'description' => 'text',
|
'description' => 'text',
|
||||||
),
|
),
|
||||||
self::CONFIG_KEY_SCHEMA => array(
|
self::CONFIG_KEY_SCHEMA => array(
|
||||||
'documentID' => array(
|
'key_version' => array(
|
||||||
'columns' => array('documentID', 'version'),
|
'columns' => array('documentPHID', 'version'),
|
||||||
'unique' => true,
|
'unique' => true,
|
||||||
),
|
),
|
||||||
'authorPHID' => array(
|
'authorPHID' => array(
|
||||||
|
|
|
@ -17,12 +17,13 @@ final class PhrictionDocument extends PhrictionDAO
|
||||||
|
|
||||||
protected $slug;
|
protected $slug;
|
||||||
protected $depth;
|
protected $depth;
|
||||||
protected $contentID;
|
protected $contentPHID;
|
||||||
protected $status;
|
protected $status;
|
||||||
protected $mailKey;
|
|
||||||
protected $viewPolicy;
|
protected $viewPolicy;
|
||||||
protected $editPolicy;
|
protected $editPolicy;
|
||||||
protected $spacePHID;
|
protected $spacePHID;
|
||||||
|
protected $editedEpoch;
|
||||||
|
protected $maxVersion;
|
||||||
|
|
||||||
private $contentObject = self::ATTACHABLE;
|
private $contentObject = self::ATTACHABLE;
|
||||||
private $ancestors = array();
|
private $ancestors = array();
|
||||||
|
@ -34,16 +35,11 @@ final class PhrictionDocument extends PhrictionDAO
|
||||||
self::CONFIG_COLUMN_SCHEMA => array(
|
self::CONFIG_COLUMN_SCHEMA => array(
|
||||||
'slug' => 'sort128',
|
'slug' => 'sort128',
|
||||||
'depth' => 'uint32',
|
'depth' => 'uint32',
|
||||||
'contentID' => 'id?',
|
|
||||||
'status' => 'text32',
|
'status' => 'text32',
|
||||||
'mailKey' => 'bytes20',
|
'editedEpoch' => 'epoch',
|
||||||
|
'maxVersion' => 'uint32',
|
||||||
),
|
),
|
||||||
self::CONFIG_KEY_SCHEMA => array(
|
self::CONFIG_KEY_SCHEMA => array(
|
||||||
'key_phid' => null,
|
|
||||||
'phid' => array(
|
|
||||||
'columns' => array('phid'),
|
|
||||||
'unique' => true,
|
|
||||||
),
|
|
||||||
'slug' => array(
|
'slug' => array(
|
||||||
'columns' => array('slug'),
|
'columns' => array('slug'),
|
||||||
'unique' => true,
|
'unique' => true,
|
||||||
|
@ -56,17 +52,16 @@ final class PhrictionDocument extends PhrictionDAO
|
||||||
) + parent::getConfiguration();
|
) + parent::getConfiguration();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function generatePHID() {
|
public function getPHIDType() {
|
||||||
return PhabricatorPHID::generateNewPHID(
|
return PhrictionDocumentPHIDType::TYPECONST;
|
||||||
PhrictionDocumentPHIDType::TYPECONST);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function initializeNewDocument(PhabricatorUser $actor, $slug) {
|
public static function initializeNewDocument(PhabricatorUser $actor, $slug) {
|
||||||
$document = new PhrictionDocument();
|
$document = id(new self())
|
||||||
$document->setSlug($slug);
|
->setSlug($slug);
|
||||||
|
|
||||||
$content = new PhrictionContent();
|
$content = id(new PhrictionContent())
|
||||||
$content->setSlug($slug);
|
->setSlug($slug);
|
||||||
|
|
||||||
$default_title = PhabricatorSlug::getDefaultTitle($slug);
|
$default_title = PhabricatorSlug::getDefaultTitle($slug);
|
||||||
$content->setTitle($default_title);
|
$content->setTitle($default_title);
|
||||||
|
@ -95,14 +90,10 @@ final class PhrictionDocument extends PhrictionDAO
|
||||||
->setSpacePHID($actor->getDefaultSpacePHID());
|
->setSpacePHID($actor->getDefaultSpacePHID());
|
||||||
}
|
}
|
||||||
|
|
||||||
return $document;
|
$document->setEditedEpoch(PhabricatorTime::getNow());
|
||||||
}
|
$document->setMaxVersion(0);
|
||||||
|
|
||||||
public function save() {
|
return $document;
|
||||||
if (!$this->getMailKey()) {
|
|
||||||
$this->setMailKey(Filesystem::readRandomCharacters(20));
|
|
||||||
}
|
|
||||||
return parent::save();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getSlugURI($slug, $type = 'document') {
|
public static function getSlugURI($slug, $type = 'document') {
|
||||||
|
@ -332,9 +323,9 @@ final class PhrictionDocument extends PhrictionDAO
|
||||||
/* -( PhabricatorPolicyCodexInterface )------------------------------------ */
|
/* -( PhabricatorPolicyCodexInterface )------------------------------------ */
|
||||||
|
|
||||||
|
|
||||||
public function newPolicyCodex() {
|
public function newPolicyCodex() {
|
||||||
return new PhrictionDocumentPolicyCodex();
|
return new PhrictionDocumentPolicyCodex();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
final class PhrictionDocumentContentTransaction
|
final class PhrictionDocumentContentTransaction
|
||||||
extends PhrictionDocumentTransactionType {
|
extends PhrictionDocumentVersionTransaction {
|
||||||
|
|
||||||
const TRANSACTIONTYPE = 'content';
|
const TRANSACTIONTYPE = 'content';
|
||||||
|
|
||||||
|
@ -18,10 +18,9 @@ final class PhrictionDocumentContentTransaction
|
||||||
|
|
||||||
public function applyInternalEffects($object, $value) {
|
public function applyInternalEffects($object, $value) {
|
||||||
$object->setStatus(PhrictionDocumentStatus::STATUS_EXISTS);
|
$object->setStatus(PhrictionDocumentStatus::STATUS_EXISTS);
|
||||||
}
|
|
||||||
|
|
||||||
public function applyExternalEffects($object, $value) {
|
$content = $this->getNewDocumentContent($object);
|
||||||
$this->getEditor()->getNewContent()->setContent($value);
|
$content->setContent($value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function shouldHide() {
|
public function shouldHide() {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
final class PhrictionDocumentDeleteTransaction
|
final class PhrictionDocumentDeleteTransaction
|
||||||
extends PhrictionDocumentTransactionType {
|
extends PhrictionDocumentVersionTransaction {
|
||||||
|
|
||||||
const TRANSACTIONTYPE = 'delete';
|
const TRANSACTIONTYPE = 'delete';
|
||||||
|
|
||||||
|
@ -11,12 +11,11 @@ final class PhrictionDocumentDeleteTransaction
|
||||||
|
|
||||||
public function applyInternalEffects($object, $value) {
|
public function applyInternalEffects($object, $value) {
|
||||||
$object->setStatus(PhrictionDocumentStatus::STATUS_DELETED);
|
$object->setStatus(PhrictionDocumentStatus::STATUS_DELETED);
|
||||||
}
|
|
||||||
|
|
||||||
public function applyExternalEffects($object, $value) {
|
$content = $this->getNewDocumentContent($object);
|
||||||
$this->getEditor()->getNewContent()->setContent('');
|
|
||||||
$this->getEditor()->getNewContent()->setChangeType(
|
$content->setContent('');
|
||||||
PhrictionChangeType::CHANGE_DELETE);
|
$content->setChangeType(PhrictionChangeType::CHANGE_DELETE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getActionStrength() {
|
public function getActionStrength() {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
final class PhrictionDocumentMoveAwayTransaction
|
final class PhrictionDocumentMoveAwayTransaction
|
||||||
extends PhrictionDocumentTransactionType {
|
extends PhrictionDocumentVersionTransaction {
|
||||||
|
|
||||||
const TRANSACTIONTYPE = 'move-away';
|
const TRANSACTIONTYPE = 'move-away';
|
||||||
|
|
||||||
|
@ -22,14 +22,12 @@ final class PhrictionDocumentMoveAwayTransaction
|
||||||
|
|
||||||
public function applyInternalEffects($object, $value) {
|
public function applyInternalEffects($object, $value) {
|
||||||
$object->setStatus(PhrictionDocumentStatus::STATUS_MOVED);
|
$object->setStatus(PhrictionDocumentStatus::STATUS_MOVED);
|
||||||
}
|
|
||||||
|
|
||||||
public function applyExternalEffects($object, $value) {
|
$content = $this->getNewDocumentContent($object);
|
||||||
$dict = $value;
|
|
||||||
$this->getEditor()->getNewContent()->setContent('');
|
$content->setContent('');
|
||||||
$this->getEditor()->getNewContent()->setChangeType(
|
$content->setChangeType(PhrictionChangeType::CHANGE_MOVE_AWAY);
|
||||||
PhrictionChangeType::CHANGE_MOVE_AWAY);
|
$content->setChangeRef($value['id']);
|
||||||
$this->getEditor()->getNewContent()->setChangeRef($dict['id']);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getActionName() {
|
public function getActionName() {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
final class PhrictionDocumentMoveToTransaction
|
final class PhrictionDocumentMoveToTransaction
|
||||||
extends PhrictionDocumentTransactionType {
|
extends PhrictionDocumentVersionTransaction {
|
||||||
|
|
||||||
const TRANSACTIONTYPE = 'move-to';
|
const TRANSACTIONTYPE = 'move-to';
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ final class PhrictionDocumentMoveToTransaction
|
||||||
|
|
||||||
public function generateNewValue($object, $value) {
|
public function generateNewValue($object, $value) {
|
||||||
$document = $value;
|
$document = $value;
|
||||||
|
|
||||||
$dict = array(
|
$dict = array(
|
||||||
'id' => $document->getID(),
|
'id' => $document->getID(),
|
||||||
'phid' => $document->getPHID(),
|
'phid' => $document->getPHID(),
|
||||||
|
@ -26,15 +27,13 @@ final class PhrictionDocumentMoveToTransaction
|
||||||
|
|
||||||
public function applyInternalEffects($object, $value) {
|
public function applyInternalEffects($object, $value) {
|
||||||
$object->setStatus(PhrictionDocumentStatus::STATUS_EXISTS);
|
$object->setStatus(PhrictionDocumentStatus::STATUS_EXISTS);
|
||||||
}
|
|
||||||
|
|
||||||
public function applyExternalEffects($object, $value) {
|
$content = $this->getNewDocumentContent($object);
|
||||||
$dict = $value;
|
|
||||||
$this->getEditor()->getNewContent()->setContent($dict['content']);
|
$content->setContent($value['content']);
|
||||||
$this->getEditor()->getNewContent()->setTitle($dict['title']);
|
$content->setTitle($value['title']);
|
||||||
$this->getEditor()->getNewContent()->setChangeType(
|
$content->setChangeType(PhrictionChangeType::CHANGE_MOVE_HERE);
|
||||||
PhrictionChangeType::CHANGE_MOVE_HERE);
|
$content->setChangeRef($value['id']);
|
||||||
$this->getEditor()->getNewContent()->setChangeRef($dict['id']);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getActionStrength() {
|
public function getActionStrength() {
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhrictionDocumentPublishTransaction
|
||||||
|
extends PhrictionDocumentTransactionType {
|
||||||
|
|
||||||
|
const TRANSACTIONTYPE = 'publish';
|
||||||
|
|
||||||
|
public function generateOldValue($object) {
|
||||||
|
return $object->getContentPHID();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyInternalEffects($object, $value) {
|
||||||
|
$object->setContentPHID($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getActionName() {
|
||||||
|
return pht('Published');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle() {
|
||||||
|
return pht(
|
||||||
|
'%s published a new version of this document.',
|
||||||
|
$this->renderAuthor());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitleForFeed() {
|
||||||
|
return pht(
|
||||||
|
'%s published a new version of %s.',
|
||||||
|
$this->renderAuthor(),
|
||||||
|
$this->renderObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validateTransactions($object, array $xactions) {
|
||||||
|
$actor = $this->getActor();
|
||||||
|
$errors = array();
|
||||||
|
|
||||||
|
foreach ($xactions as $xaction) {
|
||||||
|
$content_phid = $xaction->getNewValue();
|
||||||
|
|
||||||
|
// If this isn't changing anything, skip it.
|
||||||
|
if ($content_phid === $object->getContentPHID()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$content = id(new PhrictionContentQuery())
|
||||||
|
->setViewer($actor)
|
||||||
|
->withPHIDs(array($content_phid))
|
||||||
|
->executeOne();
|
||||||
|
if (!$content) {
|
||||||
|
$errors[] = $this->newInvalidError(
|
||||||
|
pht(
|
||||||
|
'Unable to load Content object with PHID "%s".',
|
||||||
|
$content_phid),
|
||||||
|
$xaction);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($content->getDocumentPHID() !== $object->getPHID()) {
|
||||||
|
$errors[] = $this->newInvalidError(
|
||||||
|
pht(
|
||||||
|
'Content object "%s" can not be published because it belongs '.
|
||||||
|
'to a different document.',
|
||||||
|
$content_phid));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
final class PhrictionDocumentTitleTransaction
|
final class PhrictionDocumentTitleTransaction
|
||||||
extends PhrictionDocumentTransactionType {
|
extends PhrictionDocumentVersionTransaction {
|
||||||
|
|
||||||
const TRANSACTIONTYPE = 'title';
|
const TRANSACTIONTYPE = 'title';
|
||||||
|
|
||||||
|
@ -14,10 +14,10 @@ final class PhrictionDocumentTitleTransaction
|
||||||
|
|
||||||
public function applyInternalEffects($object, $value) {
|
public function applyInternalEffects($object, $value) {
|
||||||
$object->setStatus(PhrictionDocumentStatus::STATUS_EXISTS);
|
$object->setStatus(PhrictionDocumentStatus::STATUS_EXISTS);
|
||||||
}
|
|
||||||
|
|
||||||
public function applyExternalEffects($object, $value) {
|
$content = $this->getNewDocumentContent($object);
|
||||||
$this->getEditor()->getNewContent()->setTitle($value);
|
|
||||||
|
$content->setTitle($value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getActionStrength() {
|
public function getActionStrength() {
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class PhrictionDocumentVersionTransaction
|
||||||
|
extends PhrictionDocumentTransactionType {
|
||||||
|
|
||||||
|
protected function getNewDocumentContent($object) {
|
||||||
|
return $this->getEditor()->getNewDocumentContent($object);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -115,58 +115,6 @@ final class PhabricatorProjectTransactionEditor
|
||||||
return $errors;
|
return $errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function requireCapabilities(
|
|
||||||
PhabricatorLiskDAO $object,
|
|
||||||
PhabricatorApplicationTransaction $xaction) {
|
|
||||||
|
|
||||||
switch ($xaction->getTransactionType()) {
|
|
||||||
case PhabricatorTransactions::TYPE_EDGE:
|
|
||||||
switch ($xaction->getMetadataValue('edge:type')) {
|
|
||||||
case PhabricatorProjectProjectHasMemberEdgeType::EDGECONST:
|
|
||||||
$old = $xaction->getOldValue();
|
|
||||||
$new = $xaction->getNewValue();
|
|
||||||
|
|
||||||
$add = array_keys(array_diff_key($new, $old));
|
|
||||||
$rem = array_keys(array_diff_key($old, $new));
|
|
||||||
|
|
||||||
$actor_phid = $this->requireActor()->getPHID();
|
|
||||||
|
|
||||||
$is_join = (($add === array($actor_phid)) && !$rem);
|
|
||||||
$is_leave = (($rem === array($actor_phid)) && !$add);
|
|
||||||
|
|
||||||
if ($is_join) {
|
|
||||||
// You need CAN_JOIN to join a project.
|
|
||||||
PhabricatorPolicyFilter::requireCapability(
|
|
||||||
$this->requireActor(),
|
|
||||||
$object,
|
|
||||||
PhabricatorPolicyCapability::CAN_JOIN);
|
|
||||||
} else if ($is_leave) {
|
|
||||||
// You usually don't need any capabilities to leave a project.
|
|
||||||
if ($object->getIsMembershipLocked()) {
|
|
||||||
// you must be able to edit though to leave locked projects
|
|
||||||
PhabricatorPolicyFilter::requireCapability(
|
|
||||||
$this->requireActor(),
|
|
||||||
$object,
|
|
||||||
PhabricatorPolicyCapability::CAN_EDIT);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!$this->getIsNewObject()) {
|
|
||||||
// You need CAN_EDIT to change members other than yourself.
|
|
||||||
// (PHI193) Just skip this check if we're creating a project.
|
|
||||||
PhabricatorPolicyFilter::requireCapability(
|
|
||||||
$this->requireActor(),
|
|
||||||
$object,
|
|
||||||
PhabricatorPolicyCapability::CAN_EDIT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return parent::requireCapabilities($object, $xaction);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function willPublish(PhabricatorLiskDAO $object, array $xactions) {
|
protected function willPublish(PhabricatorLiskDAO $object, array $xactions) {
|
||||||
// NOTE: We're using the omnipotent user here because the original actor
|
// NOTE: We're using the omnipotent user here because the original actor
|
||||||
// may no longer have permission to view the object.
|
// may no longer have permission to view the object.
|
||||||
|
|
|
@ -200,6 +200,8 @@ final class PhabricatorRepositoryCommit
|
||||||
|
|
||||||
$this->authorIdentity = $author;
|
$this->authorIdentity = $author;
|
||||||
$this->committerIdentity = $committer;
|
$this->committerIdentity = $committer;
|
||||||
|
|
||||||
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAuthorIdentity() {
|
public function getAuthorIdentity() {
|
||||||
|
@ -485,6 +487,23 @@ final class PhabricatorRepositoryCommit
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function loadIdentities(PhabricatorUser $viewer) {
|
||||||
|
if ($this->authorIdentity !== self::ATTACHABLE) {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
$commit = id(new DiffusionCommitQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withIDs(array($this->getID()))
|
||||||
|
->needIdentities(true)
|
||||||
|
->executeOne();
|
||||||
|
|
||||||
|
$author_identity = $commit->getAuthorIdentity();
|
||||||
|
$committer_identity = $commit->getCommitterIdentity();
|
||||||
|
|
||||||
|
return $this->attachIdentities($author_identity, $committer_identity);
|
||||||
|
}
|
||||||
|
|
||||||
public function hasCommitterIdentity() {
|
public function hasCommitterIdentity() {
|
||||||
return ($this->getCommitterIdentity() !== null);
|
return ($this->getCommitterIdentity() !== null);
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,6 +65,16 @@ final class PhabricatorRepositoryIdentity
|
||||||
$this->getIdentityNameEncoding());
|
$this->getIdentityNameEncoding());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getIdentityEmailAddress() {
|
||||||
|
$address = new PhutilEmailAddress($this->getIdentityName());
|
||||||
|
return $address->getAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIdentityDisplayName() {
|
||||||
|
$address = new PhutilEmailAddress($this->getIdentityName());
|
||||||
|
return $address->getDisplayName();
|
||||||
|
}
|
||||||
|
|
||||||
public function getIdentityShortName() {
|
public function getIdentityShortName() {
|
||||||
// TODO
|
// TODO
|
||||||
return $this->getIdentityName();
|
return $this->getIdentityName();
|
||||||
|
|
|
@ -44,8 +44,6 @@ final class PhabricatorSubscriptionsMuteController
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$muted_type = PhabricatorMutedByEdgeType::EDGECONST;
|
|
||||||
|
|
||||||
$xaction = id($object->getApplicationTransactionTemplate())
|
$xaction = id($object->getApplicationTransactionTemplate())
|
||||||
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
|
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
|
||||||
->setMetadataValue('edge:type', $muted_type)
|
->setMetadataValue('edge:type', $muted_type)
|
||||||
|
|
|
@ -1679,7 +1679,7 @@ abstract class PhabricatorEditEngine
|
||||||
->setUser($viewer)
|
->setUser($viewer)
|
||||||
->setFields($fields);
|
->setFields($fields);
|
||||||
|
|
||||||
$document = id(new PHUIDocumentViewPro())
|
$document = id(new PHUIDocumentView())
|
||||||
->setUser($viewer)
|
->setUser($viewer)
|
||||||
->setHeader($header)
|
->setHeader($header)
|
||||||
->appendChild($help_view);
|
->appendChild($help_view);
|
||||||
|
@ -2003,7 +2003,19 @@ abstract class PhabricatorEditEngine
|
||||||
$identifier = $request->getValue('objectIdentifier');
|
$identifier = $request->getValue('objectIdentifier');
|
||||||
if ($identifier) {
|
if ($identifier) {
|
||||||
$this->setIsCreate(false);
|
$this->setIsCreate(false);
|
||||||
$object = $this->newObjectFromIdentifier($identifier);
|
|
||||||
|
// After T13186, each transaction can individually weaken or replace the
|
||||||
|
// capabilities required to apply it, so we no longer need CAN_EDIT to
|
||||||
|
// attempt to apply transactions to objects. In practice, almost all
|
||||||
|
// transactions require CAN_EDIT so we won't get very far if we don't
|
||||||
|
// have it.
|
||||||
|
$capabilities = array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
);
|
||||||
|
|
||||||
|
$object = $this->newObjectFromIdentifier(
|
||||||
|
$identifier,
|
||||||
|
$capabilities);
|
||||||
} else {
|
} else {
|
||||||
$this->requireCreateCapability();
|
$this->requireCreateCapability();
|
||||||
|
|
||||||
|
|
|
@ -976,6 +976,27 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
$this->adjustTransactionValues($object, $xaction);
|
$this->adjustTransactionValues($object, $xaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now that we've merged and combined transactions, check for required
|
||||||
|
// capabilities. Note that we're doing this before filtering
|
||||||
|
// transactions: if you try to apply an edit which you do not have
|
||||||
|
// permission to apply, we want to give you a permissions error even
|
||||||
|
// if the edit would have no effect.
|
||||||
|
$this->applyCapabilityChecks($object, $xactions);
|
||||||
|
|
||||||
|
// See T13186. Fatal hard if this object has an older
|
||||||
|
// "requireCapabilities()" method. The code may rely on this method being
|
||||||
|
// called to apply policy checks, so err on the side of safety and fatal.
|
||||||
|
// TODO: Remove this check after some time has passed.
|
||||||
|
if (method_exists($this, 'requireCapabilities')) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Editor (of class "%s") implements obsolete policy method '.
|
||||||
|
'requireCapabilities(). The implementation for this Editor '.
|
||||||
|
'MUST be updated. See <%s> for discussion.',
|
||||||
|
get_class($this),
|
||||||
|
'https://secure.phabricator.com/T13186'));
|
||||||
|
}
|
||||||
|
|
||||||
$xactions = $this->filterTransactions($object, $xactions);
|
$xactions = $this->filterTransactions($object, $xactions);
|
||||||
|
|
||||||
// TODO: Once everything is on EditEngine, just use getIsNewObject() to
|
// TODO: Once everything is on EditEngine, just use getIsNewObject() to
|
||||||
|
@ -994,12 +1015,6 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that we've merged, filtered, and combined transactions, check for
|
|
||||||
// required capabilities.
|
|
||||||
foreach ($xactions as $xaction) {
|
|
||||||
$this->requireCapabilities($object, $xaction);
|
|
||||||
}
|
|
||||||
|
|
||||||
$xactions = $this->sortTransactions($xactions);
|
$xactions = $this->sortTransactions($xactions);
|
||||||
$file_phids = $this->extractFilePHIDs($object, $xactions);
|
$file_phids = $this->extractFilePHIDs($object, $xactions);
|
||||||
|
|
||||||
|
@ -1459,34 +1474,151 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function requireCapabilities(
|
private function applyCapabilityChecks(
|
||||||
PhabricatorLiskDAO $object,
|
PhabricatorLiskDAO $object,
|
||||||
PhabricatorApplicationTransaction $xaction) {
|
array $xactions) {
|
||||||
|
assert_instances_of($xactions, 'PhabricatorApplicationTransaction');
|
||||||
|
|
||||||
|
$can_edit = PhabricatorPolicyCapability::CAN_EDIT;
|
||||||
|
|
||||||
if ($this->getIsNewObject()) {
|
if ($this->getIsNewObject()) {
|
||||||
return;
|
// If we're creating a new object, we don't need any special capabilities
|
||||||
|
// on the object. The actor has already made it through creation checks,
|
||||||
|
// and objects which haven't been created yet often can not be
|
||||||
|
// meaningfully tested for capabilities anyway.
|
||||||
|
$required_capabilities = array();
|
||||||
|
} else {
|
||||||
|
if (!$xactions && !$this->xactions) {
|
||||||
|
// If we aren't doing anything, require CAN_EDIT to improve consistency.
|
||||||
|
$required_capabilities = array($can_edit);
|
||||||
|
} else {
|
||||||
|
$required_capabilities = array();
|
||||||
|
|
||||||
|
foreach ($xactions as $xaction) {
|
||||||
|
$type = $xaction->getTransactionType();
|
||||||
|
|
||||||
|
$xtype = $this->getModularTransactionType($type);
|
||||||
|
if (!$xtype) {
|
||||||
|
$capabilities = $this->getLegacyRequiredCapabilities($xaction);
|
||||||
|
} else {
|
||||||
|
$capabilities = $xtype->getRequiredCapabilities($object, $xaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For convenience, we allow flexibility in the return types because
|
||||||
|
// it's very unusual that a transaction actually requires multiple
|
||||||
|
// capability checks.
|
||||||
|
if ($capabilities === null) {
|
||||||
|
$capabilities = array();
|
||||||
|
} else {
|
||||||
|
$capabilities = (array)$capabilities;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($capabilities as $capability) {
|
||||||
|
$required_capabilities[$capability] = $capability;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$actor = $this->requireActor();
|
$required_capabilities = array_fuse($required_capabilities);
|
||||||
switch ($xaction->getTransactionType()) {
|
$actor = $this->getActor();
|
||||||
case PhabricatorTransactions::TYPE_COMMENT:
|
|
||||||
PhabricatorPolicyFilter::requireCapability(
|
if ($required_capabilities) {
|
||||||
$actor,
|
id(new PhabricatorPolicyFilter())
|
||||||
$object,
|
->setViewer($actor)
|
||||||
PhabricatorPolicyCapability::CAN_VIEW);
|
->requireCapabilities($required_capabilities)
|
||||||
break;
|
->raisePolicyExceptions(true)
|
||||||
case PhabricatorTransactions::TYPE_VIEW_POLICY:
|
->apply(array($object));
|
||||||
case PhabricatorTransactions::TYPE_EDIT_POLICY:
|
|
||||||
case PhabricatorTransactions::TYPE_JOIN_POLICY:
|
|
||||||
case PhabricatorTransactions::TYPE_SPACE:
|
|
||||||
PhabricatorPolicyFilter::requireCapability(
|
|
||||||
$actor,
|
|
||||||
$object,
|
|
||||||
PhabricatorPolicyCapability::CAN_EDIT);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getLegacyRequiredCapabilities(
|
||||||
|
PhabricatorApplicationTransaction $xaction) {
|
||||||
|
|
||||||
|
$type = $xaction->getTransactionType();
|
||||||
|
switch ($type) {
|
||||||
|
case PhabricatorTransactions::TYPE_COMMENT:
|
||||||
|
// TODO: Comments technically require CAN_INTERACT, but this is
|
||||||
|
// currently somewhat special and handled through EditEngine. For now,
|
||||||
|
// don't enforce it here.
|
||||||
|
return null;
|
||||||
|
case PhabricatorTransactions::TYPE_SUBSCRIBERS:
|
||||||
|
// TODO: Removing subscribers other than yourself should probably
|
||||||
|
// require CAN_EDIT permission. You can do this via the API but
|
||||||
|
// generally can not via the web interface.
|
||||||
|
return null;
|
||||||
|
case PhabricatorTransactions::TYPE_TOKEN:
|
||||||
|
// TODO: This technically requires CAN_INTERACT, like comments.
|
||||||
|
return null;
|
||||||
|
case PhabricatorTransactions::TYPE_HISTORY:
|
||||||
|
// This is a special magic transaction which sends you history via
|
||||||
|
// email and is only partially supported in the upstream. You don't
|
||||||
|
// need any capabilities to apply it.
|
||||||
|
return null;
|
||||||
|
case PhabricatorTransactions::TYPE_EDGE:
|
||||||
|
return $this->getLegacyRequiredEdgeCapabilities($xaction);
|
||||||
|
default:
|
||||||
|
// For other older (non-modular) transactions, always require exactly
|
||||||
|
// CAN_EDIT. Transactions which do not need CAN_EDIT or need additional
|
||||||
|
// capabilities must move to ModularTransactions.
|
||||||
|
return PhabricatorPolicyCapability::CAN_EDIT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getLegacyRequiredEdgeCapabilities(
|
||||||
|
PhabricatorApplicationTransaction $xaction) {
|
||||||
|
|
||||||
|
// You don't need to have edit permission on an object to mention it or
|
||||||
|
// otherwise add a relationship pointing toward it.
|
||||||
|
if ($this->getIsInverseEdgeEditor()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$edge_type = $xaction->getMetadataValue('edge:type');
|
||||||
|
switch ($edge_type) {
|
||||||
|
case PhabricatorMutedByEdgeType::EDGECONST:
|
||||||
|
// At time of writing, you can only write this edge for yourself, so
|
||||||
|
// you don't need permissions. If you can eventually mute an object
|
||||||
|
// for other users, this would need to be revisited.
|
||||||
|
return null;
|
||||||
|
case PhabricatorObjectMentionsObjectEdgeType::EDGECONST:
|
||||||
|
return null;
|
||||||
|
case PhabricatorProjectProjectHasMemberEdgeType::EDGECONST:
|
||||||
|
$old = $xaction->getOldValue();
|
||||||
|
$new = $xaction->getNewValue();
|
||||||
|
|
||||||
|
$add = array_keys(array_diff_key($new, $old));
|
||||||
|
$rem = array_keys(array_diff_key($old, $new));
|
||||||
|
|
||||||
|
$actor_phid = $this->requireActor()->getPHID();
|
||||||
|
|
||||||
|
$is_join = (($add === array($actor_phid)) && !$rem);
|
||||||
|
$is_leave = (($rem === array($actor_phid)) && !$add);
|
||||||
|
|
||||||
|
if ($is_join) {
|
||||||
|
// You need CAN_JOIN to join a project.
|
||||||
|
return PhabricatorPolicyCapability::CAN_JOIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($is_leave) {
|
||||||
|
$object = $this->object;
|
||||||
|
// You usually don't need any capabilities to leave a project...
|
||||||
|
if ($object->getIsMembershipLocked()) {
|
||||||
|
// ...you must be able to edit to leave locked projects, though.
|
||||||
|
return PhabricatorPolicyCapability::CAN_EDIT;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// You need CAN_EDIT to change members other than yourself.
|
||||||
|
return PhabricatorPolicyCapability::CAN_EDIT;
|
||||||
|
default:
|
||||||
|
return PhabricatorPolicyCapability::CAN_EDIT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private function buildSubscribeTransaction(
|
private function buildSubscribeTransaction(
|
||||||
PhabricatorLiskDAO $object,
|
PhabricatorLiskDAO $object,
|
||||||
array $xactions,
|
array $xactions,
|
||||||
|
|
|
@ -366,4 +366,30 @@ abstract class PhabricatorModularTransactionType
|
||||||
$capability);
|
$capability);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of capabilities the actor must have on the object to apply
|
||||||
|
* a transaction to it.
|
||||||
|
*
|
||||||
|
* Usually, you should use this to reduce capability requirements when a
|
||||||
|
* transaction (like leaving a Conpherence thread) can be applied without
|
||||||
|
* having edit permission on the object. You can override this method to
|
||||||
|
* remove the CAN_EDIT requirement, or to replace it with a different
|
||||||
|
* requirement.
|
||||||
|
*
|
||||||
|
* If you are increasing capability requirements and need to add an
|
||||||
|
* additional capability or policy requirement above and beyond CAN_EDIT, it
|
||||||
|
* is usually better implemented as a validation check.
|
||||||
|
*
|
||||||
|
* @param object Object being edited.
|
||||||
|
* @param PhabricatorApplicationTransaction Transaction being applied.
|
||||||
|
* @return null|const|list<const> A capability constant (or list of
|
||||||
|
* capability constants) which the actor must have on the object. You can
|
||||||
|
* return `null` as a shorthand for "no capabilities are required".
|
||||||
|
*/
|
||||||
|
public function getRequiredCapabilities(
|
||||||
|
$object,
|
||||||
|
PhabricatorApplicationTransaction $xaction) {
|
||||||
|
return PhabricatorPolicyCapability::CAN_EDIT;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,7 +142,7 @@ final class PhabricatorTypeaheadFunctionHelpController
|
||||||
$header = id(new PHUIHeaderView())
|
$header = id(new PHUIHeaderView())
|
||||||
->setHeader($title);
|
->setHeader($title);
|
||||||
|
|
||||||
$document = id(new PHUIDocumentViewPro())
|
$document = id(new PHUIDocumentView())
|
||||||
->setHeader($header)
|
->setHeader($header)
|
||||||
->appendChild($content_box);
|
->appendChild($content_box);
|
||||||
|
|
||||||
|
|
|
@ -279,7 +279,6 @@ final class AphrontFormPolicyControl extends AphrontFormControl {
|
||||||
->setIcon($icon);
|
->setIcon($icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if ($this->templatePHIDType) {
|
if ($this->templatePHIDType) {
|
||||||
$context_path = 'template/'.$this->templatePHIDType.'/';
|
$context_path = 'template/'.$this->templatePHIDType.'/';
|
||||||
} else {
|
} else {
|
||||||
|
@ -346,15 +345,6 @@ final class AphrontFormPolicyControl extends AphrontFormControl {
|
||||||
)),
|
)),
|
||||||
$input,
|
$input,
|
||||||
));
|
));
|
||||||
|
|
||||||
return AphrontFormSelectControl::renderSelectTag(
|
|
||||||
$this->getValue(),
|
|
||||||
$this->getOptions(),
|
|
||||||
array(
|
|
||||||
'name' => $this->getName(),
|
|
||||||
'disabled' => $this->getDisabled() ? 'disabled' : null,
|
|
||||||
'id' => $this->getID(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getSelectCustomKey() {
|
public static function getSelectCustomKey() {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
final class PHUIDocumentViewPro extends AphrontTagView {
|
final class PHUIDocumentView extends AphrontTagView {
|
||||||
|
|
||||||
private $header;
|
private $header;
|
||||||
private $bookname;
|
private $bookname;
|
||||||
|
@ -8,6 +8,8 @@ final class PHUIDocumentViewPro extends AphrontTagView {
|
||||||
private $fluid;
|
private $fluid;
|
||||||
private $toc;
|
private $toc;
|
||||||
private $foot;
|
private $foot;
|
||||||
|
private $curtain;
|
||||||
|
private $banner;
|
||||||
|
|
||||||
public function setHeader(PHUIHeaderView $header) {
|
public function setHeader(PHUIHeaderView $header) {
|
||||||
$header->setTall(true);
|
$header->setTall(true);
|
||||||
|
@ -36,6 +38,24 @@ final class PHUIDocumentViewPro extends AphrontTagView {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setCurtain(PHUICurtainView $curtain) {
|
||||||
|
$this->curtain = $curtain;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCurtain() {
|
||||||
|
return $this->curtain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setBanner($banner) {
|
||||||
|
$this->banner = $banner;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBanner() {
|
||||||
|
return $this->banner;
|
||||||
|
}
|
||||||
|
|
||||||
protected function getTagAttributes() {
|
protected function getTagAttributes() {
|
||||||
$classes = array();
|
$classes = array();
|
||||||
|
|
||||||
|
@ -61,6 +81,17 @@ final class PHUIDocumentViewPro extends AphrontTagView {
|
||||||
$classes[] = 'phui-document-view';
|
$classes[] = 'phui-document-view';
|
||||||
$classes[] = 'phui-document-view-pro';
|
$classes[] = 'phui-document-view-pro';
|
||||||
|
|
||||||
|
if ($this->curtain) {
|
||||||
|
$classes[] = 'has-curtain';
|
||||||
|
} else {
|
||||||
|
$classes[] = 'has-no-curtain';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->curtain) {
|
||||||
|
$action_list = $this->curtain->getActionList();
|
||||||
|
$this->header->setActionListID($action_list->getID());
|
||||||
|
}
|
||||||
|
|
||||||
$book = null;
|
$book = null;
|
||||||
if ($this->bookname) {
|
if ($this->bookname) {
|
||||||
$book = pht('%s (%s)', $this->bookname, $this->bookdescription);
|
$book = pht('%s (%s)', $this->bookname, $this->bookdescription);
|
||||||
|
@ -114,32 +145,52 @@ final class PHUIDocumentViewPro extends AphrontTagView {
|
||||||
$this->foot);
|
$this->foot);
|
||||||
}
|
}
|
||||||
|
|
||||||
$content_inner = phutil_tag(
|
$curtain = null;
|
||||||
|
if ($this->curtain) {
|
||||||
|
$curtain = phutil_tag(
|
||||||
'div',
|
'div',
|
||||||
array(
|
array(
|
||||||
'class' => 'phui-document-inner',
|
'class' => 'phui-document-curtain',
|
||||||
),
|
),
|
||||||
|
$this->curtain);
|
||||||
|
}
|
||||||
|
|
||||||
|
$main_content = phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => 'phui-document-content-view',
|
||||||
|
),
|
||||||
|
$main_content);
|
||||||
|
|
||||||
|
$content_inner = phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => 'phui-document-inner',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
$table_of_contents,
|
||||||
|
$this->header,
|
||||||
|
$this->banner,
|
||||||
array(
|
array(
|
||||||
$table_of_contents,
|
$curtain,
|
||||||
$this->header,
|
|
||||||
$main_content,
|
$main_content,
|
||||||
$foot_content,
|
),
|
||||||
));
|
$foot_content,
|
||||||
|
));
|
||||||
|
|
||||||
$content = phutil_tag(
|
$content = phutil_tag(
|
||||||
'div',
|
'div',
|
||||||
array(
|
array(
|
||||||
'class' => 'phui-document-content',
|
'class' => 'phui-document-content',
|
||||||
),
|
),
|
||||||
$content_inner);
|
$content_inner);
|
||||||
|
|
||||||
return phutil_tag(
|
|
||||||
'div',
|
|
||||||
array(
|
|
||||||
'class' => implode(' ', $classes),
|
|
||||||
),
|
|
||||||
$content);
|
|
||||||
|
|
||||||
|
return phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => implode(' ', $classes),
|
||||||
|
),
|
||||||
|
$content);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -709,8 +709,9 @@ final class PHUIObjectItemView extends AphrontTagView {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fixed width, right column container. */
|
/* Fixed width, right column container. */
|
||||||
|
$column3 = null;
|
||||||
if ($this->sideColumn) {
|
if ($this->sideColumn) {
|
||||||
$column2 = phutil_tag(
|
$column3 = phutil_tag(
|
||||||
'div',
|
'div',
|
||||||
array(
|
array(
|
||||||
'class' => 'phui-oi-col2 phui-oi-side-column',
|
'class' => 'phui-oi-col2 phui-oi-side-column',
|
||||||
|
@ -731,6 +732,7 @@ final class PHUIObjectItemView extends AphrontTagView {
|
||||||
$column0,
|
$column0,
|
||||||
$column1,
|
$column1,
|
||||||
$column2,
|
$column2,
|
||||||
|
$column3,
|
||||||
)));
|
)));
|
||||||
|
|
||||||
$box = phutil_tag(
|
$box = phutil_tag(
|
||||||
|
|
|
@ -105,7 +105,7 @@ final class PHUIRemarkupPreviewPanel extends AphrontTagView {
|
||||||
$header = id(new PHUIHeaderView())
|
$header = id(new PHUIHeaderView())
|
||||||
->setHeader(pht('%s (Preview)', $this->header));
|
->setHeader(pht('%s (Preview)', $this->header));
|
||||||
|
|
||||||
$content = id(new PHUIDocumentViewPro())
|
$content = id(new PHUIDocumentView())
|
||||||
->setHeader($header)
|
->setHeader($header)
|
||||||
->appendChild($preview);
|
->appendChild($preview);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,11 +26,14 @@
|
||||||
.harbormaster-unit-details {
|
.harbormaster-unit-details {
|
||||||
margin: 8px 0 4px;
|
margin: 8px 0 4px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
white-space: pre;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
color: {$lightgreytext};
|
color: {$lightgreytext};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.harbormaster-unit-details-text {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
.harbormaster-log-view-loading {
|
.harbormaster-log-view-loading {
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
|
@ -8,6 +8,35 @@
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.phui-document-view.phui-document-view-pro.has-curtain {
|
||||||
|
max-width: 1132px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.printable .phui-document-view.phui-document-view-pro.has-curtain {
|
||||||
|
max-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.device-desktop .phui-document-inner {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.device-desktop .has-curtain .phui-document-content-view {
|
||||||
|
padding-right: 332px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.printable .phui-document-content-view {
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.device-desktop .phui-document-curtain {
|
||||||
|
float: right;
|
||||||
|
width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.printable .phui-document-curtain {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.phui-document-container {
|
.phui-document-container {
|
||||||
background-color: {$page.content};
|
background-color: {$page.content};
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
|
@ -63,7 +63,8 @@
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.phui-document-view .phui-header-action-links .phui-mobile-menu {
|
.phui-document-view.has-no-curtain
|
||||||
|
.phui-header-action-links .phui-mobile-menu {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,10 +72,6 @@
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.device-desktop .phui-document-content .phabricator-action-list-view {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.phui-document-content .phabricator-remarkup .remarkup-code-block {
|
.phui-document-content .phabricator-remarkup .remarkup-code-block {
|
||||||
clear: both;
|
clear: both;
|
||||||
margin: 16px 0;
|
margin: 16px 0;
|
||||||
|
@ -103,3 +100,9 @@
|
||||||
.remarkup-code {
|
.remarkup-code {
|
||||||
font: 13px/18px "Menlo", "Consolas", "Monaco", monospace;
|
font: 13px/18px "Menlo", "Consolas", "Monaco", monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.phui-document-version-navigation {
|
||||||
|
text-align: center;
|
||||||
|
padding: 8px;
|
||||||
|
background-color: {$lightgreybackground};
|
||||||
|
}
|
||||||
|
|
|
@ -259,7 +259,6 @@ body .phui-header-shell.phui-bleed-header
|
||||||
color: {$lightgreytext};
|
color: {$lightgreytext};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.phui-header-action-links .phui-mobile-menu {
|
.phui-header-action-links .phui-mobile-menu {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,10 +20,13 @@ JX.behavior('phabricator-nav', function(config) {
|
||||||
|
|
||||||
// - Flexible Navigation Column ------------------------------------------------
|
// - Flexible Navigation Column ------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
var dragging;
|
var dragging;
|
||||||
var track;
|
var track;
|
||||||
|
|
||||||
|
var collapsed = config.collapsed;
|
||||||
|
var narrowed;
|
||||||
|
var visible = null;
|
||||||
|
|
||||||
JX.enableDispatch(document.body, 'mousemove');
|
JX.enableDispatch(document.body, 'mousemove');
|
||||||
|
|
||||||
JX.DOM.listen(drag, 'mousedown', null, function(e) {
|
JX.DOM.listen(drag, 'mousedown', null, function(e) {
|
||||||
|
@ -95,6 +98,7 @@ JX.behavior('phabricator-nav', function(config) {
|
||||||
if (!dragging) {
|
if (!dragging) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
JX.DOM.alterClass(document.body, 'jx-drag-col', false);
|
JX.DOM.alterClass(document.body, 'jx-drag-col', false);
|
||||||
dragging = false;
|
dragging = false;
|
||||||
|
|
||||||
|
@ -117,6 +121,29 @@ JX.behavior('phabricator-nav', function(config) {
|
||||||
return (JX.$V(drag).x - JX.Vector.getScroll().x);
|
return (JX.$V(drag).x - JX.Vector.getScroll().x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function repaint() {
|
||||||
|
narrowed = !JX.Device.isDesktop();
|
||||||
|
|
||||||
|
var was_visible = visible;
|
||||||
|
visible = (!collapsed && !narrowed);
|
||||||
|
|
||||||
|
if (was_visible === visible) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!visible) {
|
||||||
|
savedrag();
|
||||||
|
}
|
||||||
|
|
||||||
|
JX.DOM.alterClass(main, 'has-local-nav', visible);
|
||||||
|
JX.DOM.alterClass(main, 'has-drag-nav', visible);
|
||||||
|
JX.DOM.alterClass(main, 'has-closed-nav', !visible);
|
||||||
|
|
||||||
|
if (visible) {
|
||||||
|
restoredrag();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var saved_width = config.width;
|
var saved_width = config.width;
|
||||||
function savedrag() {
|
function savedrag() {
|
||||||
saved_width = get_width();
|
saved_width = get_width();
|
||||||
|
@ -136,21 +163,10 @@ JX.behavior('phabricator-nav', function(config) {
|
||||||
content.style.marginLeft = (saved_width + JX.Vector.getDim(drag).x) + 'px';
|
content.style.marginLeft = (saved_width + JX.Vector.getDim(drag).x) + 'px';
|
||||||
}
|
}
|
||||||
|
|
||||||
var collapsed = config.collapsed;
|
|
||||||
JX.Stratcom.listen('differential-filetree-toggle', null, function() {
|
JX.Stratcom.listen('differential-filetree-toggle', null, function() {
|
||||||
collapsed = !collapsed;
|
collapsed = !collapsed;
|
||||||
|
|
||||||
if (collapsed) {
|
repaint();
|
||||||
savedrag();
|
|
||||||
}
|
|
||||||
|
|
||||||
JX.DOM.alterClass(main, 'has-local-nav', !collapsed);
|
|
||||||
JX.DOM.alterClass(main, 'has-drag-nav', !collapsed);
|
|
||||||
JX.DOM.alterClass(main, 'has-closed-nav', collapsed);
|
|
||||||
|
|
||||||
if (!collapsed) {
|
|
||||||
restoredrag();
|
|
||||||
}
|
|
||||||
|
|
||||||
new JX.Request('/settings/adjust/', JX.bag)
|
new JX.Request('/settings/adjust/', JX.bag)
|
||||||
.setData({ key : 'nav-collapsed', value : (collapsed ? 1 : 0) })
|
.setData({ key : 'nav-collapsed', value : (collapsed ? 1 : 0) })
|
||||||
|
@ -168,7 +184,9 @@ JX.behavior('phabricator-nav', function(config) {
|
||||||
// of the navigation bar.
|
// of the navigation bar.
|
||||||
|
|
||||||
function onresize() {
|
function onresize() {
|
||||||
if (JX.Device.getDevice() != 'desktop') {
|
repaint();
|
||||||
|
|
||||||
|
if (!visible) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,14 +211,13 @@ JX.behavior('phabricator-nav', function(config) {
|
||||||
local.style.left = 0;
|
local.style.left = 0;
|
||||||
|
|
||||||
JX.Stratcom.listen(['scroll', 'resize'], null, onresize);
|
JX.Stratcom.listen(['scroll', 'resize'], null, onresize);
|
||||||
onresize();
|
|
||||||
|
|
||||||
|
repaint();
|
||||||
|
|
||||||
// - Navigation Reset ----------------------------------------------------------
|
// - Navigation Reset ----------------------------------------------------------
|
||||||
|
|
||||||
JX.Stratcom.listen('phabricator-device-change', null, function() {
|
JX.Stratcom.listen('phabricator-device-change', null, function() {
|
||||||
resetdrag();
|
repaint();
|
||||||
onresize();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue