mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-15 18:10:53 +01:00
(stable) Promote 2017 Week 12
This commit is contained in:
commit
6f1e2d8055
107 changed files with 1469 additions and 10964 deletions
|
@ -7,9 +7,9 @@
|
|||
*/
|
||||
return array(
|
||||
'names' => array(
|
||||
'conpherence.pkg.css' => '32f2c040',
|
||||
'conpherence.pkg.css' => '82aca405',
|
||||
'conpherence.pkg.js' => '6249a1cf',
|
||||
'core.pkg.css' => '491d7018',
|
||||
'core.pkg.css' => 'dc689e29',
|
||||
'core.pkg.js' => '1fa7c0c5',
|
||||
'darkconsole.pkg.js' => 'e7393ebb',
|
||||
'differential.pkg.css' => '90b30783',
|
||||
|
@ -46,7 +46,7 @@ return array(
|
|||
'rsrc/css/application/config/setup-issue.css' => 'f794cfc3',
|
||||
'rsrc/css/application/config/unhandled-exception.css' => '4c96257a',
|
||||
'rsrc/css/application/conpherence/durable-column.css' => '292c71f0',
|
||||
'rsrc/css/application/conpherence/header-pane.css' => 'db93ebc6',
|
||||
'rsrc/css/application/conpherence/header-pane.css' => '4082233d',
|
||||
'rsrc/css/application/conpherence/menu.css' => '3d8e5c9c',
|
||||
'rsrc/css/application/conpherence/message-pane.css' => 'd1fc13e1',
|
||||
'rsrc/css/application/conpherence/notification.css' => '965db05b',
|
||||
|
@ -83,7 +83,7 @@ return array(
|
|||
'rsrc/css/application/paste/paste.css' => '1898e534',
|
||||
'rsrc/css/application/people/people-picture-menu-item.css' => 'a06f7f34',
|
||||
'rsrc/css/application/people/people-profile.css' => '4df76faf',
|
||||
'rsrc/css/application/phame/phame.css' => '53fa6236',
|
||||
'rsrc/css/application/phame/phame.css' => 'b3a0b3a3',
|
||||
'rsrc/css/application/pholio/pholio-edit.css' => '07676f51',
|
||||
'rsrc/css/application/pholio/pholio-inline-comments.css' => '8e545e49',
|
||||
'rsrc/css/application/pholio/pholio.css' => 'ca89d380',
|
||||
|
@ -96,7 +96,7 @@ return array(
|
|||
'rsrc/css/application/policy/policy-transaction-detail.css' => '82100a43',
|
||||
'rsrc/css/application/policy/policy.css' => '957ea14c',
|
||||
'rsrc/css/application/ponder/ponder-view.css' => 'fbd45f96',
|
||||
'rsrc/css/application/project/project-card-view.css' => '1be8c87b',
|
||||
'rsrc/css/application/project/project-card-view.css' => '3d3c1f91',
|
||||
'rsrc/css/application/project/project-view.css' => '792c9057',
|
||||
'rsrc/css/application/releeph/releeph-core.css' => '9b3c5733',
|
||||
'rsrc/css/application/releeph/releeph-preview-branch.css' => 'b7a6f4a5',
|
||||
|
@ -112,7 +112,6 @@ return array(
|
|||
'rsrc/css/core/syntax.css' => '769d3498',
|
||||
'rsrc/css/core/z-index.css' => '5e72c4e0',
|
||||
'rsrc/css/diviner/diviner-shared.css' => '896f1d43',
|
||||
'rsrc/css/font/font-aleo.css' => '8bdb2835',
|
||||
'rsrc/css/font/font-awesome.css' => 'e838e088',
|
||||
'rsrc/css/font/font-lato.css' => 'c7ccd872',
|
||||
'rsrc/css/font/phui-font-icon-base.css' => '870a7360',
|
||||
|
@ -145,11 +144,11 @@ return array(
|
|||
'rsrc/css/phui/phui-document-summary.css' => '9ca48bdf',
|
||||
'rsrc/css/phui/phui-document.css' => 'c32e8dec',
|
||||
'rsrc/css/phui/phui-feed-story.css' => '44a9c8e9',
|
||||
'rsrc/css/phui/phui-fontkit.css' => 'b78a0059',
|
||||
'rsrc/css/phui/phui-form-view.css' => 'cf198e10',
|
||||
'rsrc/css/phui/phui-fontkit.css' => '1320ed01',
|
||||
'rsrc/css/phui/phui-form-view.css' => '6175808d',
|
||||
'rsrc/css/phui/phui-form.css' => 'b62c01d8',
|
||||
'rsrc/css/phui/phui-head-thing.css' => 'fd311e5f',
|
||||
'rsrc/css/phui/phui-header-view.css' => 'fef6a54e',
|
||||
'rsrc/css/phui/phui-header-view.css' => '9cf828ce',
|
||||
'rsrc/css/phui/phui-hovercard.css' => 'ae091fc5',
|
||||
'rsrc/css/phui/phui-icon-set-selector.css' => '87db8fee',
|
||||
'rsrc/css/phui/phui-icon.css' => '12b387a1',
|
||||
|
@ -169,7 +168,7 @@ return array(
|
|||
'rsrc/css/phui/phui-status.css' => 'd5263e49',
|
||||
'rsrc/css/phui/phui-tag-view.css' => '84d65f26',
|
||||
'rsrc/css/phui/phui-timeline-view.css' => 'bf45789e',
|
||||
'rsrc/css/phui/phui-two-column-view.css' => '8a1074c7',
|
||||
'rsrc/css/phui/phui-two-column-view.css' => 'ce9fa0b7',
|
||||
'rsrc/css/phui/workboards/phui-workboard-color.css' => '783cdff5',
|
||||
'rsrc/css/phui/workboards/phui-workboard.css' => '3bc85455',
|
||||
'rsrc/css/phui/workboards/phui-workcard.css' => 'cca5fa92',
|
||||
|
@ -178,16 +177,6 @@ return array(
|
|||
'rsrc/css/sprite-tokens.css' => '9cdfd599',
|
||||
'rsrc/css/syntax/syntax-default.css' => '9923583c',
|
||||
'rsrc/externals/d3/d3.min.js' => 'a11a5ff2',
|
||||
'rsrc/externals/font/aleo/aleo-bold.eot' => 'd3d3bed7',
|
||||
'rsrc/externals/font/aleo/aleo-bold.svg' => '45899c8e',
|
||||
'rsrc/externals/font/aleo/aleo-bold.ttf' => '4b08bef0',
|
||||
'rsrc/externals/font/aleo/aleo-bold.woff' => '93b513a1',
|
||||
'rsrc/externals/font/aleo/aleo-bold.woff2' => '75fbf322',
|
||||
'rsrc/externals/font/aleo/aleo-regular.eot' => 'a4e29e2f',
|
||||
'rsrc/externals/font/aleo/aleo-regular.svg' => '42a86f7a',
|
||||
'rsrc/externals/font/aleo/aleo-regular.ttf' => '751e7479',
|
||||
'rsrc/externals/font/aleo/aleo-regular.woff' => 'c3744be9',
|
||||
'rsrc/externals/font/aleo/aleo-regular.woff2' => '851aa0ee',
|
||||
'rsrc/externals/font/fontawesome/fontawesome-webfont.eot' => '24a7064f',
|
||||
'rsrc/externals/font/fontawesome/fontawesome-webfont.ttf' => '0039fe26',
|
||||
'rsrc/externals/font/fontawesome/fontawesome-webfont.woff' => 'de978a43',
|
||||
|
@ -541,7 +530,7 @@ return array(
|
|||
'rsrc/js/phuix/PHUIXActionView.js' => 'b3465b9b',
|
||||
'rsrc/js/phuix/PHUIXAutocomplete.js' => '7c492cd2',
|
||||
'rsrc/js/phuix/PHUIXDropdownMenu.js' => '8018ee50',
|
||||
'rsrc/js/phuix/PHUIXFormControl.js' => 'bbece68d',
|
||||
'rsrc/js/phuix/PHUIXFormControl.js' => '83e03671',
|
||||
'rsrc/js/phuix/PHUIXIconView.js' => 'bff6884b',
|
||||
),
|
||||
'symbols' => array(
|
||||
|
@ -564,7 +553,7 @@ return array(
|
|||
'config-options-css' => '0ede4c9b',
|
||||
'config-page-css' => 'c1d5121b',
|
||||
'conpherence-durable-column-view' => '292c71f0',
|
||||
'conpherence-header-pane-css' => 'db93ebc6',
|
||||
'conpherence-header-pane-css' => '4082233d',
|
||||
'conpherence-menu-css' => '3d8e5c9c',
|
||||
'conpherence-message-pane-css' => 'd1fc13e1',
|
||||
'conpherence-notification-css' => '965db05b',
|
||||
|
@ -584,7 +573,6 @@ return array(
|
|||
'diffusion-readme-css' => '297373eb',
|
||||
'diffusion-source-css' => '750add59',
|
||||
'diviner-shared-css' => '896f1d43',
|
||||
'font-aleo' => '8bdb2835',
|
||||
'font-fontawesome' => 'e838e088',
|
||||
'font-lato' => 'c7ccd872',
|
||||
'global-drag-and-drop-css' => '5c1b47c2',
|
||||
|
@ -826,7 +814,7 @@ return array(
|
|||
'phabricator-uiexample-reactor-sendclass' => '1def2711',
|
||||
'phabricator-uiexample-reactor-sendproperties' => 'b1f0ccee',
|
||||
'phabricator-zindex-css' => '5e72c4e0',
|
||||
'phame-css' => '53fa6236',
|
||||
'phame-css' => 'b3a0b3a3',
|
||||
'pholio-css' => 'ca89d380',
|
||||
'pholio-edit-css' => '07676f51',
|
||||
'pholio-inline-comments-css' => '8e545e49',
|
||||
|
@ -857,11 +845,11 @@ return array(
|
|||
'phui-document-view-pro-css' => 'f56738ed',
|
||||
'phui-feed-story-css' => '44a9c8e9',
|
||||
'phui-font-icon-base-css' => '870a7360',
|
||||
'phui-fontkit-css' => 'b78a0059',
|
||||
'phui-fontkit-css' => '1320ed01',
|
||||
'phui-form-css' => 'b62c01d8',
|
||||
'phui-form-view-css' => 'cf198e10',
|
||||
'phui-form-view-css' => '6175808d',
|
||||
'phui-head-thing-view-css' => 'fd311e5f',
|
||||
'phui-header-view-css' => 'fef6a54e',
|
||||
'phui-header-view-css' => '9cf828ce',
|
||||
'phui-hovercard' => '1bd28176',
|
||||
'phui-hovercard-view-css' => 'ae091fc5',
|
||||
'phui-icon-set-selector-css' => '87db8fee',
|
||||
|
@ -890,7 +878,7 @@ return array(
|
|||
'phui-tag-view-css' => '84d65f26',
|
||||
'phui-theme-css' => '9f261c6b',
|
||||
'phui-timeline-view-css' => 'bf45789e',
|
||||
'phui-two-column-view-css' => '8a1074c7',
|
||||
'phui-two-column-view-css' => 'ce9fa0b7',
|
||||
'phui-workboard-color-css' => '783cdff5',
|
||||
'phui-workboard-view-css' => '3bc85455',
|
||||
'phui-workcard-view-css' => 'cca5fa92',
|
||||
|
@ -899,13 +887,13 @@ return array(
|
|||
'phuix-action-view' => 'b3465b9b',
|
||||
'phuix-autocomplete' => '7c492cd2',
|
||||
'phuix-dropdown-menu' => '8018ee50',
|
||||
'phuix-form-control-view' => 'bbece68d',
|
||||
'phuix-form-control-view' => '83e03671',
|
||||
'phuix-icon-view' => 'bff6884b',
|
||||
'policy-css' => '957ea14c',
|
||||
'policy-edit-css' => '815c66f7',
|
||||
'policy-transaction-detail-css' => '82100a43',
|
||||
'ponder-view-css' => 'fbd45f96',
|
||||
'project-card-view-css' => '1be8c87b',
|
||||
'project-card-view-css' => '3d3c1f91',
|
||||
'project-view-css' => '792c9057',
|
||||
'releeph-core' => '9b3c5733',
|
||||
'releeph-preview-branch' => 'b7a6f4a5',
|
||||
|
@ -1530,6 +1518,10 @@ return array(
|
|||
'javelin-behavior',
|
||||
'javelin-scrollbar',
|
||||
),
|
||||
'83e03671' => array(
|
||||
'javelin-install',
|
||||
'javelin-dom',
|
||||
),
|
||||
'8499b6ab' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
|
@ -1585,9 +1577,6 @@ return array(
|
|||
'javelin-install',
|
||||
'javelin-dom',
|
||||
),
|
||||
'8bdb2835' => array(
|
||||
'phui-fontkit-css',
|
||||
),
|
||||
'8ce821c5' => array(
|
||||
'phabricator-notification',
|
||||
'javelin-stratcom',
|
||||
|
@ -1917,10 +1906,6 @@ return array(
|
|||
'javelin-vector',
|
||||
'javelin-install',
|
||||
),
|
||||
'bbece68d' => array(
|
||||
'javelin-install',
|
||||
'javelin-dom',
|
||||
),
|
||||
'bcaccd64' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-behavior-device',
|
||||
|
@ -2322,7 +2307,6 @@ return array(
|
|||
'phui-list-view-css',
|
||||
'font-fontawesome',
|
||||
'font-lato',
|
||||
'font-aleo',
|
||||
'phui-font-icon-base-css',
|
||||
'phui-fontkit-css',
|
||||
'phui-box-css',
|
||||
|
|
|
@ -138,7 +138,6 @@ return array(
|
|||
|
||||
'font-fontawesome',
|
||||
'font-lato',
|
||||
'font-aleo',
|
||||
'phui-font-icon-base-css',
|
||||
'phui-fontkit-css',
|
||||
'phui-box-css',
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_differential.differential_reviewer
|
||||
ADD lastActionDiffPHID VARBINARY(64);
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_differential.differential_reviewer
|
||||
ADD lastCommentDiffPHID VARBINARY(64);
|
125
resources/sql/autopatches/20170320.reviewers.03.migrate.php
Normal file
125
resources/sql/autopatches/20170320.reviewers.03.migrate.php
Normal file
|
@ -0,0 +1,125 @@
|
|||
<?php
|
||||
|
||||
$table = new DifferentialRevision();
|
||||
$diff_table = new DifferentialDiff();
|
||||
$reviewer_table = new DifferentialReviewer();
|
||||
|
||||
$table_name = PhabricatorEdgeConfig::TABLE_NAME_EDGE;
|
||||
$data_name = PhabricatorEdgeConfig::TABLE_NAME_EDGEDATA;
|
||||
|
||||
$conn = $table->establishConnection('w');
|
||||
|
||||
// Previously "DifferentialRevisionHasReviewerEdgeType::EDGECONST".
|
||||
$edge_type = 35;
|
||||
|
||||
// NOTE: We can't use normal migration iterators for edges because they don't
|
||||
// have an "id" column. For now, try just loading the whole result set: the
|
||||
// actual size of the rows is small. If we run into issues, we could write an
|
||||
// EdgeIterator.
|
||||
$every_edge = queryfx_all(
|
||||
$conn,
|
||||
'SELECT * FROM %T edge LEFT JOIN %T data ON edge.dataID = data.id
|
||||
WHERE edge.type = %d',
|
||||
$table_name,
|
||||
$data_name,
|
||||
$edge_type);
|
||||
|
||||
foreach ($every_edge as $edge) {
|
||||
if ($edge['type'] != $edge_type) {
|
||||
// Ignore edges which aren't "reviewers", like subscribers.
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$data = phutil_json_decode($edge['data']);
|
||||
$data = idx($data, 'data');
|
||||
} catch (Exception $ex) {
|
||||
// Just ignore any kind of issue with the edge data, we'll use a default
|
||||
// below.
|
||||
$data = null;
|
||||
}
|
||||
|
||||
if (!$data) {
|
||||
$data = array(
|
||||
'status' => 'added',
|
||||
);
|
||||
}
|
||||
|
||||
$status = idx($data, 'status');
|
||||
|
||||
$diff_phid = null;
|
||||
|
||||
// NOTE: At one point, the code to populate "diffID" worked correctly, but
|
||||
// it seems to have later been broken. Salvage it if we can, and look up
|
||||
// the corresponding diff PHID.
|
||||
$diff_id = idx($data, 'diffID');
|
||||
if ($diff_id) {
|
||||
$row = queryfx_one(
|
||||
$conn,
|
||||
'SELECT phid FROM %T WHERE id = %d',
|
||||
$diff_table->getTableName(),
|
||||
$diff_id);
|
||||
if ($row) {
|
||||
$diff_phid = $row['phid'];
|
||||
}
|
||||
}
|
||||
|
||||
if (!$diff_phid) {
|
||||
// If the status is "accepted" or "rejected", look up the current diff
|
||||
// PHID so we can distinguish between "accepted" and "accepted older".
|
||||
switch ($status) {
|
||||
case 'accepted':
|
||||
case 'rejected':
|
||||
case 'commented':
|
||||
$row = queryfx_one(
|
||||
$conn,
|
||||
'SELECT diff.phid FROM %T diff JOIN %T revision
|
||||
ON diff.revisionID = revision.id
|
||||
WHERE revision.phid = %s
|
||||
ORDER BY diff.id DESC LIMIT 1',
|
||||
$diff_table->getTableName(),
|
||||
$table->getTableName(),
|
||||
$edge['src']);
|
||||
if ($row) {
|
||||
$diff_phid = $row['phid'];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We now represent some states (like "Commented" and "Accepted Older") as
|
||||
// a primary state plus an extra flag, instead of making "Commented" a
|
||||
// primary state. Map old states to new states and flags.
|
||||
|
||||
if ($status == 'commented') {
|
||||
$status = 'added';
|
||||
$comment_phid = $diff_phid;
|
||||
$action_phid = null;
|
||||
} else {
|
||||
$comment_phid = null;
|
||||
$action_phid = $diff_phid;
|
||||
}
|
||||
|
||||
if ($status == 'accepted-older') {
|
||||
$status = 'accepted';
|
||||
}
|
||||
|
||||
if ($status == 'rejected-older') {
|
||||
$status = 'rejected';
|
||||
}
|
||||
|
||||
queryfx(
|
||||
$conn,
|
||||
'INSERT INTO %T (revisionPHID, reviewerPHID, reviewerStatus,
|
||||
lastActionDiffPHID, lastCommentDiffPHID, dateCreated, dateModified)
|
||||
VALUES (%s, %s, %s, %ns, %ns, %d, %d)
|
||||
ON DUPLICATE KEY UPDATE dateCreated = VALUES(dateCreated)',
|
||||
$reviewer_table->getTableName(),
|
||||
$edge['src'],
|
||||
$edge['dst'],
|
||||
$status,
|
||||
$action_phid,
|
||||
$comment_phid,
|
||||
$edge['dateCreated'],
|
||||
$edge['dateCreated']);
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_differential.differential_reviewer
|
||||
ADD lastActorPHID VARBINARY(64);
|
|
@ -494,7 +494,6 @@ phutil_register_library_map(array(
|
|||
'DifferentialReviewer' => 'applications/differential/storage/DifferentialReviewer.php',
|
||||
'DifferentialReviewerDatasource' => 'applications/differential/typeahead/DifferentialReviewerDatasource.php',
|
||||
'DifferentialReviewerForRevisionEdgeType' => 'applications/differential/edge/DifferentialReviewerForRevisionEdgeType.php',
|
||||
'DifferentialReviewerProxy' => 'applications/differential/storage/DifferentialReviewerProxy.php',
|
||||
'DifferentialReviewerStatus' => 'applications/differential/constants/DifferentialReviewerStatus.php',
|
||||
'DifferentialReviewersAddBlockingReviewersHeraldAction' => 'applications/differential/herald/DifferentialReviewersAddBlockingReviewersHeraldAction.php',
|
||||
'DifferentialReviewersAddBlockingSelfHeraldAction' => 'applications/differential/herald/DifferentialReviewersAddBlockingSelfHeraldAction.php',
|
||||
|
@ -2013,7 +2012,6 @@ phutil_register_library_map(array(
|
|||
'PhabricatorAuthValidateController' => 'applications/auth/controller/PhabricatorAuthValidateController.php',
|
||||
'PhabricatorAuthenticationConfigOptions' => 'applications/config/option/PhabricatorAuthenticationConfigOptions.php',
|
||||
'PhabricatorAutoEventListener' => 'infrastructure/events/PhabricatorAutoEventListener.php',
|
||||
'PhabricatorBadgeHasRecipientEdgeType' => 'applications/badges/edge/PhabricatorBadgeHasRecipientEdgeType.php',
|
||||
'PhabricatorBadgesApplication' => 'applications/badges/application/PhabricatorBadgesApplication.php',
|
||||
'PhabricatorBadgesArchiveController' => 'applications/badges/controller/PhabricatorBadgesArchiveController.php',
|
||||
'PhabricatorBadgesAward' => 'applications/badges/storage/PhabricatorBadgesAward.php',
|
||||
|
@ -2530,6 +2528,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorDashboardProfileController' => 'applications/dashboard/controller/PhabricatorDashboardProfileController.php',
|
||||
'PhabricatorDashboardProfileMenuItem' => 'applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php',
|
||||
'PhabricatorDashboardQuery' => 'applications/dashboard/query/PhabricatorDashboardQuery.php',
|
||||
'PhabricatorDashboardQueryPanelInstallController' => 'applications/dashboard/controller/PhabricatorDashboardQueryPanelInstallController.php',
|
||||
'PhabricatorDashboardQueryPanelType' => 'applications/dashboard/paneltype/PhabricatorDashboardQueryPanelType.php',
|
||||
'PhabricatorDashboardRemarkupRule' => 'applications/dashboard/remarkup/PhabricatorDashboardRemarkupRule.php',
|
||||
'PhabricatorDashboardRemovePanelController' => 'applications/dashboard/controller/PhabricatorDashboardRemovePanelController.php',
|
||||
|
@ -2602,6 +2601,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorEdgesDestructionEngineExtension' => 'infrastructure/edges/engineextension/PhabricatorEdgesDestructionEngineExtension.php',
|
||||
'PhabricatorEditEngine' => 'applications/transactions/editengine/PhabricatorEditEngine.php',
|
||||
'PhabricatorEditEngineAPIMethod' => 'applications/transactions/editengine/PhabricatorEditEngineAPIMethod.php',
|
||||
'PhabricatorEditEngineCheckboxesCommentAction' => 'applications/transactions/commentaction/PhabricatorEditEngineCheckboxesCommentAction.php',
|
||||
'PhabricatorEditEngineColumnsCommentAction' => 'applications/transactions/commentaction/PhabricatorEditEngineColumnsCommentAction.php',
|
||||
'PhabricatorEditEngineCommentAction' => 'applications/transactions/commentaction/PhabricatorEditEngineCommentAction.php',
|
||||
'PhabricatorEditEngineCommentActionGroup' => 'applications/transactions/commentaction/PhabricatorEditEngineCommentActionGroup.php',
|
||||
|
@ -3622,7 +3622,6 @@ phutil_register_library_map(array(
|
|||
'PhabricatorQueryOrderVector' => 'infrastructure/query/order/PhabricatorQueryOrderVector.php',
|
||||
'PhabricatorRateLimitRequestExceptionHandler' => 'aphront/handler/PhabricatorRateLimitRequestExceptionHandler.php',
|
||||
'PhabricatorRecaptchaConfigOptions' => 'applications/config/option/PhabricatorRecaptchaConfigOptions.php',
|
||||
'PhabricatorRecipientHasBadgeEdgeType' => 'applications/badges/edge/PhabricatorRecipientHasBadgeEdgeType.php',
|
||||
'PhabricatorRedirectController' => 'applications/base/controller/PhabricatorRedirectController.php',
|
||||
'PhabricatorRefreshCSRFController' => 'applications/auth/controller/PhabricatorRefreshCSRFController.php',
|
||||
'PhabricatorRegistrationProfile' => 'applications/people/storage/PhabricatorRegistrationProfile.php',
|
||||
|
@ -3691,6 +3690,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorRepositoryPullEventPHIDType' => 'applications/repository/phid/PhabricatorRepositoryPullEventPHIDType.php',
|
||||
'PhabricatorRepositoryPullEventQuery' => 'applications/repository/query/PhabricatorRepositoryPullEventQuery.php',
|
||||
'PhabricatorRepositoryPullLocalDaemon' => 'applications/repository/daemon/PhabricatorRepositoryPullLocalDaemon.php',
|
||||
'PhabricatorRepositoryPullLocalDaemonModule' => 'applications/repository/daemon/PhabricatorRepositoryPullLocalDaemonModule.php',
|
||||
'PhabricatorRepositoryPushEvent' => 'applications/repository/storage/PhabricatorRepositoryPushEvent.php',
|
||||
'PhabricatorRepositoryPushEventPHIDType' => 'applications/repository/phid/PhabricatorRepositoryPushEventPHIDType.php',
|
||||
'PhabricatorRepositoryPushEventQuery' => 'applications/repository/query/PhabricatorRepositoryPushEventQuery.php',
|
||||
|
@ -3987,6 +3987,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorTOTPAuthFactor' => 'applications/auth/factor/PhabricatorTOTPAuthFactor.php',
|
||||
'PhabricatorTOTPAuthFactorTestCase' => 'applications/auth/factor/__tests__/PhabricatorTOTPAuthFactorTestCase.php',
|
||||
'PhabricatorTaskmasterDaemon' => 'infrastructure/daemon/workers/PhabricatorTaskmasterDaemon.php',
|
||||
'PhabricatorTaskmasterDaemonModule' => 'infrastructure/daemon/workers/PhabricatorTaskmasterDaemonModule.php',
|
||||
'PhabricatorTestApplication' => 'applications/base/controller/__tests__/PhabricatorTestApplication.php',
|
||||
'PhabricatorTestCase' => 'infrastructure/testing/PhabricatorTestCase.php',
|
||||
'PhabricatorTestController' => 'applications/base/controller/__tests__/PhabricatorTestController.php',
|
||||
|
@ -5254,7 +5255,6 @@ phutil_register_library_map(array(
|
|||
'DifferentialReviewer' => 'DifferentialDAO',
|
||||
'DifferentialReviewerDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
||||
'DifferentialReviewerForRevisionEdgeType' => 'PhabricatorEdgeType',
|
||||
'DifferentialReviewerProxy' => 'Phobject',
|
||||
'DifferentialReviewerStatus' => 'Phobject',
|
||||
'DifferentialReviewersAddBlockingReviewersHeraldAction' => 'DifferentialReviewersHeraldAction',
|
||||
'DifferentialReviewersAddBlockingSelfHeraldAction' => 'DifferentialReviewersHeraldAction',
|
||||
|
@ -6996,7 +6996,6 @@ phutil_register_library_map(array(
|
|||
'PhabricatorAuthValidateController' => 'PhabricatorAuthController',
|
||||
'PhabricatorAuthenticationConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||
'PhabricatorAutoEventListener' => 'PhabricatorEventListener',
|
||||
'PhabricatorBadgeHasRecipientEdgeType' => 'PhabricatorEdgeType',
|
||||
'PhabricatorBadgesApplication' => 'PhabricatorApplication',
|
||||
'PhabricatorBadgesArchiveController' => 'PhabricatorBadgesController',
|
||||
'PhabricatorBadgesAward' => array(
|
||||
|
@ -7610,6 +7609,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorDashboardProfileController' => 'PhabricatorController',
|
||||
'PhabricatorDashboardProfileMenuItem' => 'PhabricatorProfileMenuItem',
|
||||
'PhabricatorDashboardQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'PhabricatorDashboardQueryPanelInstallController' => 'PhabricatorDashboardController',
|
||||
'PhabricatorDashboardQueryPanelType' => 'PhabricatorDashboardPanelType',
|
||||
'PhabricatorDashboardRemarkupRule' => 'PhabricatorObjectRemarkupRule',
|
||||
'PhabricatorDashboardRemovePanelController' => 'PhabricatorDashboardController',
|
||||
|
@ -7686,6 +7686,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorPolicyInterface',
|
||||
),
|
||||
'PhabricatorEditEngineAPIMethod' => 'ConduitAPIMethod',
|
||||
'PhabricatorEditEngineCheckboxesCommentAction' => 'PhabricatorEditEngineCommentAction',
|
||||
'PhabricatorEditEngineColumnsCommentAction' => 'PhabricatorEditEngineCommentAction',
|
||||
'PhabricatorEditEngineCommentAction' => 'Phobject',
|
||||
'PhabricatorEditEngineCommentActionGroup' => 'Phobject',
|
||||
|
@ -8874,7 +8875,6 @@ phutil_register_library_map(array(
|
|||
),
|
||||
'PhabricatorRateLimitRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler',
|
||||
'PhabricatorRecaptchaConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||
'PhabricatorRecipientHasBadgeEdgeType' => 'PhabricatorEdgeType',
|
||||
'PhabricatorRedirectController' => 'PhabricatorController',
|
||||
'PhabricatorRefreshCSRFController' => 'PhabricatorAuthController',
|
||||
'PhabricatorRegistrationProfile' => 'Phobject',
|
||||
|
@ -8985,6 +8985,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorRepositoryPullEventPHIDType' => 'PhabricatorPHIDType',
|
||||
'PhabricatorRepositoryPullEventQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'PhabricatorRepositoryPullLocalDaemon' => 'PhabricatorDaemon',
|
||||
'PhabricatorRepositoryPullLocalDaemonModule' => 'PhutilDaemonOverseerModule',
|
||||
'PhabricatorRepositoryPushEvent' => array(
|
||||
'PhabricatorRepositoryDAO',
|
||||
'PhabricatorPolicyInterface',
|
||||
|
@ -9314,6 +9315,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorTOTPAuthFactor' => 'PhabricatorAuthFactor',
|
||||
'PhabricatorTOTPAuthFactorTestCase' => 'PhabricatorTestCase',
|
||||
'PhabricatorTaskmasterDaemon' => 'PhabricatorDaemon',
|
||||
'PhabricatorTaskmasterDaemonModule' => 'PhutilDaemonOverseerModule',
|
||||
'PhabricatorTestApplication' => 'PhabricatorApplication',
|
||||
'PhabricatorTestCase' => 'PhutilTestCase',
|
||||
'PhabricatorTestController' => 'PhabricatorController',
|
||||
|
|
|
@ -178,10 +178,13 @@ final class PhabricatorCommitSearchEngine
|
|||
$groups = $bucket->newResultGroups($query, $commits);
|
||||
|
||||
foreach ($groups as $group) {
|
||||
$views[] = id(clone $template)
|
||||
->setHeader($group->getName())
|
||||
->setNoDataString($group->getNoDataString())
|
||||
->setCommits($group->getObjects());
|
||||
// Don't show groups in Dashboard Panels
|
||||
if ($group->getObjects() || !$this->isPanelContext()) {
|
||||
$views[] = id(clone $template)
|
||||
->setHeader($group->getName())
|
||||
->setNoDataString($group->getNoDataString())
|
||||
->setCommits($group->getObjects());
|
||||
}
|
||||
}
|
||||
} catch (Exception $ex) {
|
||||
$this->addError($ex->getMessage());
|
||||
|
@ -189,7 +192,13 @@ final class PhabricatorCommitSearchEngine
|
|||
} else {
|
||||
$views[] = id(clone $template)
|
||||
->setCommits($commits)
|
||||
->setNoDataString(pht('No matching commits.'));
|
||||
->setNoDataString(pht('No commits found.'));
|
||||
}
|
||||
|
||||
if (!$views) {
|
||||
$views[] = id(new PhabricatorAuditListView())
|
||||
->setViewer($viewer)
|
||||
->setNoDataString(pht('No commits found.'));
|
||||
}
|
||||
|
||||
if (count($views) == 1) {
|
||||
|
|
|
@ -26,10 +26,6 @@ final class PhabricatorBadgesApplication extends PhabricatorApplication {
|
|||
return self::GROUP_UTILITIES;
|
||||
}
|
||||
|
||||
public function isPrototype() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getRoutes() {
|
||||
return array(
|
||||
'/badges/' => array(
|
||||
|
|
|
@ -1,103 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorBadgeHasRecipientEdgeType
|
||||
extends PhabricatorEdgeType {
|
||||
|
||||
const EDGECONST = 59;
|
||||
|
||||
public function getInverseEdgeConstant() {
|
||||
return PhabricatorRecipientHasBadgeEdgeType::EDGECONST;
|
||||
}
|
||||
|
||||
public function shouldWriteInverseTransactions() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getTransactionAddString(
|
||||
$actor,
|
||||
$add_count,
|
||||
$add_edges) {
|
||||
|
||||
return pht(
|
||||
'%s awarded %s recipients(s): %s.',
|
||||
$actor,
|
||||
$add_count,
|
||||
$add_edges);
|
||||
}
|
||||
|
||||
public function getTransactionRemoveString(
|
||||
$actor,
|
||||
$rem_count,
|
||||
$rem_edges) {
|
||||
|
||||
return pht(
|
||||
'%s revoked %s recipients(s): %s.',
|
||||
$actor,
|
||||
$rem_count,
|
||||
$rem_edges);
|
||||
}
|
||||
|
||||
public function getTransactionEditString(
|
||||
$actor,
|
||||
$total_count,
|
||||
$add_count,
|
||||
$add_edges,
|
||||
$rem_count,
|
||||
$rem_edges) {
|
||||
|
||||
return pht(
|
||||
'%s edited recipient(s), awarded %s: %s; revoked %s: %s.',
|
||||
$actor,
|
||||
$add_count,
|
||||
$add_edges,
|
||||
$rem_count,
|
||||
$rem_edges);
|
||||
}
|
||||
|
||||
public function getFeedAddString(
|
||||
$actor,
|
||||
$object,
|
||||
$add_count,
|
||||
$add_edges) {
|
||||
|
||||
return pht(
|
||||
'%s awarded %s recipient(s) for %s: %s.',
|
||||
$actor,
|
||||
$add_count,
|
||||
$object,
|
||||
$add_edges);
|
||||
}
|
||||
|
||||
public function getFeedRemoveString(
|
||||
$actor,
|
||||
$object,
|
||||
$rem_count,
|
||||
$rem_edges) {
|
||||
|
||||
return pht(
|
||||
'%s revoked %s recipient(s) for %s: %s.',
|
||||
$actor,
|
||||
$rem_count,
|
||||
$object,
|
||||
$rem_edges);
|
||||
}
|
||||
|
||||
public function getFeedEditString(
|
||||
$actor,
|
||||
$object,
|
||||
$total_count,
|
||||
$add_count,
|
||||
$add_edges,
|
||||
$rem_count,
|
||||
$rem_edges) {
|
||||
|
||||
return pht(
|
||||
'%s edited recipient(s) for %s, awarded %s: %s; revoked %s: %s.',
|
||||
$actor,
|
||||
$object,
|
||||
$add_count,
|
||||
$add_edges,
|
||||
$rem_count,
|
||||
$rem_edges);
|
||||
}
|
||||
}
|
|
@ -1,103 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorRecipientHasBadgeEdgeType
|
||||
extends PhabricatorEdgeType {
|
||||
|
||||
const EDGECONST = 58;
|
||||
|
||||
public function getInverseEdgeConstant() {
|
||||
return PhabricatorBadgeHasRecipientEdgeType::EDGECONST;
|
||||
}
|
||||
|
||||
public function shouldWriteInverseTransactions() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getTransactionAddString(
|
||||
$actor,
|
||||
$add_count,
|
||||
$add_edges) {
|
||||
|
||||
return pht(
|
||||
'%s added %s badge(s): %s.',
|
||||
$actor,
|
||||
$add_count,
|
||||
$add_edges);
|
||||
}
|
||||
|
||||
public function getTransactionRemoveString(
|
||||
$actor,
|
||||
$rem_count,
|
||||
$rem_edges) {
|
||||
|
||||
return pht(
|
||||
'%s revoked %s badge(s): %s.',
|
||||
$actor,
|
||||
$rem_count,
|
||||
$rem_edges);
|
||||
}
|
||||
|
||||
public function getTransactionEditString(
|
||||
$actor,
|
||||
$total_count,
|
||||
$add_count,
|
||||
$add_edges,
|
||||
$rem_count,
|
||||
$rem_edges) {
|
||||
|
||||
return pht(
|
||||
'%s edited badge(s), added %s: %s; revoked %s: %s.',
|
||||
$actor,
|
||||
$add_count,
|
||||
$add_edges,
|
||||
$rem_count,
|
||||
$rem_edges);
|
||||
}
|
||||
|
||||
public function getFeedAddString(
|
||||
$actor,
|
||||
$object,
|
||||
$add_count,
|
||||
$add_edges) {
|
||||
|
||||
return pht(
|
||||
'%s added %s badge(s) for %s: %s.',
|
||||
$actor,
|
||||
$add_count,
|
||||
$object,
|
||||
$add_edges);
|
||||
}
|
||||
|
||||
public function getFeedRemoveString(
|
||||
$actor,
|
||||
$object,
|
||||
$rem_count,
|
||||
$rem_edges) {
|
||||
|
||||
return pht(
|
||||
'%s revoked %s badge(s) for %s: %s.',
|
||||
$actor,
|
||||
$rem_count,
|
||||
$object,
|
||||
$rem_edges);
|
||||
}
|
||||
|
||||
public function getFeedEditString(
|
||||
$actor,
|
||||
$object,
|
||||
$total_count,
|
||||
$add_count,
|
||||
$add_edges,
|
||||
$rem_count,
|
||||
$rem_edges) {
|
||||
|
||||
return pht(
|
||||
'%s edited badge(s) for %s, added %s: %s; revoked %s: %s.',
|
||||
$actor,
|
||||
$object,
|
||||
$add_count,
|
||||
$add_edges,
|
||||
$rem_count,
|
||||
$rem_edges);
|
||||
}
|
||||
}
|
|
@ -1343,7 +1343,21 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
|
|||
PhabricatorDestructionEngine $engine) {
|
||||
|
||||
$this->openTransaction();
|
||||
$this->delete();
|
||||
$invitees = id(new PhabricatorCalendarEventInvitee())->loadAllWhere(
|
||||
'eventPHID = %s',
|
||||
$this->getPHID());
|
||||
foreach ($invitees as $invitee) {
|
||||
$invitee->delete();
|
||||
}
|
||||
|
||||
$notifications = id(new PhabricatorCalendarNotification())->loadAllWhere(
|
||||
'eventPHID = %s',
|
||||
$this->getPHID());
|
||||
foreach ($notifications as $notification) {
|
||||
$notification->delete();
|
||||
}
|
||||
|
||||
$this->delete();
|
||||
$this->saveTransaction();
|
||||
}
|
||||
|
||||
|
|
|
@ -56,6 +56,12 @@ abstract class PhabricatorConduitController extends PhabricatorController {
|
|||
$panel_link),
|
||||
);
|
||||
|
||||
if ($params === null) {
|
||||
$messages[] = pht(
|
||||
'If you submit parameters, these examples will update to show '.
|
||||
'exactly how to encode the parameters you submit.');
|
||||
}
|
||||
|
||||
$info_view = id(new PHUIInfoView())
|
||||
->setErrors($messages)
|
||||
->setSeverity(PHUIInfoView::SEVERITY_NOTICE);
|
||||
|
|
|
@ -7,6 +7,10 @@ abstract class PhabricatorDaemonController
|
|||
return true;
|
||||
}
|
||||
|
||||
public function buildApplicationMenu() {
|
||||
return $this->buildSideNavView(true)->getMenu();
|
||||
}
|
||||
|
||||
protected function buildSideNavView() {
|
||||
$nav = new AphrontSideNavFilterView();
|
||||
$nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
|
||||
|
|
|
@ -125,12 +125,10 @@ final class PhabricatorDaemonLogViewController
|
|||
case PhabricatorDaemonLog::STATUS_WAIT:
|
||||
$details = pht(
|
||||
'This daemon is running normally and reported a status update '.
|
||||
'recently (within %s). However, it encountered an error while '.
|
||||
'doing work and is waiting a little while (%s) to resume '.
|
||||
'processing. After encountering an error, daemons wait before '.
|
||||
'resuming work to avoid overloading services.',
|
||||
phutil_format_relative_time($unknown_time),
|
||||
phutil_format_relative_time($wait_time));
|
||||
'recently (within %s). The process is currently waiting to '.
|
||||
'restart, either because it is hibernating or because it '.
|
||||
'encountered an error.',
|
||||
phutil_format_relative_time($unknown_time));
|
||||
break;
|
||||
case PhabricatorDaemonLog::STATUS_EXITING:
|
||||
$details = pht('This daemon is shutting down gracefully.');
|
||||
|
|
|
@ -18,6 +18,14 @@ final class PhabricatorDashboardApplication extends PhabricatorApplication {
|
|||
return 'fa-dashboard';
|
||||
}
|
||||
|
||||
public function isPinnedByDefault(PhabricatorUser $viewer) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getApplicationOrder() {
|
||||
return 0.160;
|
||||
}
|
||||
|
||||
public function getRoutes() {
|
||||
return array(
|
||||
'/W(?P<id>\d+)' => 'PhabricatorDashboardPanelViewController',
|
||||
|
@ -36,6 +44,8 @@ final class PhabricatorDashboardApplication extends PhabricatorApplication {
|
|||
'removepanel/(?P<id>\d+)/'
|
||||
=> 'PhabricatorDashboardRemovePanelController',
|
||||
'panel/' => array(
|
||||
'install/(?P<engineKey>[^/]+)/(?:(?P<queryKey>[^/]+)/)?' =>
|
||||
'PhabricatorDashboardQueryPanelInstallController',
|
||||
'(?:query/(?P<queryKey>[^/]+)/)?'
|
||||
=> 'PhabricatorDashboardPanelListController',
|
||||
'create/' => 'PhabricatorDashboardPanelEditController',
|
||||
|
|
|
@ -0,0 +1,194 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorDashboardQueryPanelInstallController
|
||||
extends PhabricatorDashboardController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $request->getViewer();
|
||||
|
||||
$v_dashboard = null;
|
||||
$v_name = null;
|
||||
$v_column = 0;
|
||||
$v_engine = $request->getURIData('engineKey');
|
||||
$v_query = $request->getURIData('queryKey');
|
||||
|
||||
$e_name = true;
|
||||
|
||||
// Validate Engines
|
||||
$engines = PhabricatorApplicationSearchEngine::getAllEngines();
|
||||
foreach ($engines as $name => $engine) {
|
||||
if (!$engine->canUseInPanelContext()) {
|
||||
unset($engines[$name]);
|
||||
}
|
||||
}
|
||||
if (!in_array($v_engine, array_keys($engines))) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
// Validate Queries
|
||||
$engine = $engines[$v_engine];
|
||||
$engine->setViewer($viewer);
|
||||
$good_query = false;
|
||||
if ($engine->isBuiltinQuery($v_query)) {
|
||||
$good_query = true;
|
||||
} else {
|
||||
$saved_query = id(new PhabricatorSavedQueryQuery())
|
||||
->setViewer($viewer)
|
||||
->withEngineClassNames(array($v_engine))
|
||||
->withQueryKeys(array($v_query))
|
||||
->executeOne();
|
||||
if ($saved_query) {
|
||||
$good_query = true;
|
||||
}
|
||||
}
|
||||
if (!$good_query) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$named_query = idx($engine->loadEnabledNamedQueries(), $v_query);
|
||||
if ($named_query) {
|
||||
$v_name = $named_query->getQueryName();
|
||||
}
|
||||
|
||||
$errors = array();
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$v_dashboard = $request->getInt('dashboardID');
|
||||
$v_name = $request->getStr('name');
|
||||
if (!$v_name) {
|
||||
$errors[] = pht('You must provide a name for this panel.');
|
||||
$e_name = pht('Required');
|
||||
}
|
||||
|
||||
$dashboard = id(new PhabricatorDashboardQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($v_dashboard))
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->executeOne();
|
||||
|
||||
if (!$dashboard) {
|
||||
$errors[] = pht('Please select a valid dashboard.');
|
||||
}
|
||||
|
||||
if (!$errors) {
|
||||
$redirect_uri = "/dashboard/arrange/{$v_dashboard}/";
|
||||
|
||||
$panel_type = id(new PhabricatorDashboardQueryPanelType())
|
||||
->getPanelTypeKey();
|
||||
$panel = PhabricatorDashboardPanel::initializeNewPanel($viewer);
|
||||
$panel->setPanelType($panel_type);
|
||||
|
||||
$field_list = PhabricatorCustomField::getObjectFields(
|
||||
$panel,
|
||||
PhabricatorCustomField::ROLE_EDIT);
|
||||
|
||||
$field_list
|
||||
->setViewer($viewer)
|
||||
->readFieldsFromStorage($panel);
|
||||
|
||||
$panel->requireImplementation()->initializeFieldsFromRequest(
|
||||
$panel,
|
||||
$field_list,
|
||||
$request);
|
||||
|
||||
$xactions = array();
|
||||
|
||||
$xactions[] = id(new PhabricatorDashboardPanelTransaction())
|
||||
->setTransactionType(PhabricatorDashboardPanelTransaction::TYPE_NAME)
|
||||
->setNewValue($v_name);
|
||||
|
||||
$xactions[] = id(new PhabricatorDashboardPanelTransaction())
|
||||
->setTransactionType(PhabricatorTransactions::TYPE_CUSTOMFIELD)
|
||||
->setMetadataValue('customfield:key', 'std:dashboard:core:class')
|
||||
->setOldValue(null)
|
||||
->setNewValue($v_engine);
|
||||
|
||||
$xactions[] = id(new PhabricatorDashboardPanelTransaction())
|
||||
->setTransactionType(PhabricatorTransactions::TYPE_CUSTOMFIELD)
|
||||
->setMetadataValue('customfield:key', 'std:dashboard:core:key')
|
||||
->setOldValue(null)
|
||||
->setNewValue($v_query);
|
||||
|
||||
$editor = id(new PhabricatorDashboardPanelTransactionEditor())
|
||||
->setActor($viewer)
|
||||
->setContinueOnNoEffect(true)
|
||||
->setContentSourceFromRequest($request)
|
||||
->applyTransactions($panel, $xactions);
|
||||
|
||||
PhabricatorDashboardTransactionEditor::addPanelToDashboard(
|
||||
$viewer,
|
||||
PhabricatorContentSource::newFromRequest($request),
|
||||
$panel,
|
||||
$dashboard,
|
||||
$request->getInt('column', 0));
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI($redirect_uri);
|
||||
}
|
||||
}
|
||||
|
||||
// Make this a select for now, as we don't expect someone to have
|
||||
// edit access to a vast number of dashboards.
|
||||
// Can add optiongroup if needed down the road.
|
||||
$dashboards = id(new PhabricatorDashboardQuery())
|
||||
->setViewer($viewer)
|
||||
->withStatuses(array(
|
||||
PhabricatorDashboard::STATUS_ACTIVE,
|
||||
))
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->execute();
|
||||
$options = mpull($dashboards, 'getName', 'getID');
|
||||
asort($options);
|
||||
|
||||
$redirect_uri = $engine->getQueryResultsPageURI($v_query);
|
||||
|
||||
if (!$options) {
|
||||
$notice = id(new PHUIInfoView())
|
||||
->setSeverity(PHUIInfoView::SEVERITY_NOTICE)
|
||||
->appendChild(pht('You do not have access to any dashboards. To '.
|
||||
'continue, please create a dashboard first.'));
|
||||
|
||||
return $this->newDialog()
|
||||
->setTitle(pht('No Dashboards'))
|
||||
->setWidth(AphrontDialogView::WIDTH_FORM)
|
||||
->appendChild($notice)
|
||||
->addCancelButton($redirect_uri);
|
||||
}
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($viewer)
|
||||
->addHiddenInput('engine', $v_engine)
|
||||
->addHiddenInput('query', $v_query)
|
||||
->addHiddenInput('column', $v_column)
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setLabel(pht('Name'))
|
||||
->setName('name')
|
||||
->setValue($v_name)
|
||||
->setError($e_name))
|
||||
->appendChild(
|
||||
id(new AphrontFormSelectControl())
|
||||
->setUser($this->getViewer())
|
||||
->setValue($v_dashboard)
|
||||
->setName('dashboardID')
|
||||
->setOptions($options)
|
||||
->setLabel(pht('Dashboard')));
|
||||
|
||||
return $this->newDialog()
|
||||
->setTitle(pht('Add Panel to Dashboard'))
|
||||
->setErrors($errors)
|
||||
->setWidth(AphrontDialogView::WIDTH_FORM)
|
||||
->appendChild($form->buildLayoutView())
|
||||
->addCancelButton($redirect_uri)
|
||||
->addSubmitButton(pht('Add Panel'));
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -12,6 +12,7 @@ final class PhabricatorDashboardIconSet
|
|||
protected function newIcons() {
|
||||
$map = array(
|
||||
'fa-home' => pht('Home'),
|
||||
'fa-dashboard' => pht('Dashboard'),
|
||||
'fa-th-large' => pht('Blocks'),
|
||||
'fa-columns' => pht('Columns'),
|
||||
'fa-bookmark' => pht('Page Saver'),
|
||||
|
@ -20,16 +21,26 @@ final class PhabricatorDashboardIconSet
|
|||
'fa-bomb' => pht('Kaboom'),
|
||||
'fa-pie-chart' => pht('Apple Blueberry'),
|
||||
'fa-bar-chart' => pht('Serious Business'),
|
||||
'fa-briefcase' => pht('Project'),
|
||||
|
||||
'fa-bell' => pht('Ding Ding'),
|
||||
'fa-credit-card' => pht('Plastic Debt'),
|
||||
'fa-code' => pht('PHP is Life'),
|
||||
'fa-sticky-note' => pht('To Self'),
|
||||
|
||||
'fa-newspaper-o' => pht('Stay Woke'),
|
||||
|
||||
'fa-server' => pht('Metallica'),
|
||||
'fa-hashtag' => pht('Corned Beef'),
|
||||
'fa-group' => pht('Triplets'),
|
||||
'fa-anchor' => pht('Tasks'),
|
||||
'fa-calendar' => pht('Calendar'),
|
||||
'fa-compass' => pht('Wayfinding'),
|
||||
|
||||
'fa-futbol-o' => pht('Sports'),
|
||||
'fa-flag' => pht('Flag'),
|
||||
'fa-ship' => pht('Water Vessel'),
|
||||
'fa-feed' => pht('Wireless'),
|
||||
'fa-bullhorn' => pht('Announcement'),
|
||||
|
||||
);
|
||||
|
||||
$icons = array();
|
||||
|
|
|
@ -7,6 +7,7 @@ final class PhabricatorDashboardQuery
|
|||
private $phids;
|
||||
private $statuses;
|
||||
private $authorPHIDs;
|
||||
private $canEdit;
|
||||
|
||||
private $needPanels;
|
||||
private $needProjects;
|
||||
|
@ -41,6 +42,11 @@ final class PhabricatorDashboardQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function withCanEdit($can_edit) {
|
||||
$this->canEdit = $can_edit;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withNameNgrams($ngrams) {
|
||||
return $this->withNgramsConstraint(
|
||||
id(new PhabricatorDashboardNgrams()),
|
||||
|
@ -59,6 +65,15 @@ final class PhabricatorDashboardQuery
|
|||
|
||||
$phids = mpull($dashboards, 'getPHID');
|
||||
|
||||
if ($this->canEdit) {
|
||||
$dashboards = id(new PhabricatorPolicyFilter())
|
||||
->setViewer($this->getViewer())
|
||||
->requireCapabilities(array(
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->apply($dashboards);
|
||||
}
|
||||
|
||||
if ($this->needPanels) {
|
||||
$edge_query = id(new PhabricatorEdgeQuery())
|
||||
->withSourcePHIDs($phids)
|
||||
|
|
|
@ -34,6 +34,10 @@ final class PhabricatorDashboardSearchEngine
|
|||
->setKey('statuses')
|
||||
->setLabel(pht('Status'))
|
||||
->setOptions(PhabricatorDashboard::getStatusNameMap()),
|
||||
id(new PhabricatorSearchCheckboxesField())
|
||||
->setKey('editable')
|
||||
->setLabel(pht('Editable'))
|
||||
->setOptions(array('editable' => null)),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -94,6 +98,10 @@ final class PhabricatorDashboardSearchEngine
|
|||
$query->withNameNgrams($map['name']);
|
||||
}
|
||||
|
||||
if ($map['editable'] !== null) {
|
||||
$query->withCanEdit($map['editable']);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
|
@ -126,8 +134,10 @@ final class PhabricatorDashboardSearchEngine
|
|||
->setHref($this->getApplicationURI("view/{$id}/"))
|
||||
->setObject($dashboard);
|
||||
|
||||
$bg_color = 'bg-dark';
|
||||
if ($dashboard->isArchived()) {
|
||||
$item->setDisabled(true);
|
||||
$bg_color = 'bg-grey';
|
||||
}
|
||||
|
||||
$panels = $dashboard->getPanels();
|
||||
|
@ -142,7 +152,7 @@ final class PhabricatorDashboardSearchEngine
|
|||
|
||||
$icon = id(new PHUIIconView())
|
||||
->setIcon($dashboard->getIcon())
|
||||
->setBackground('bg-dark');
|
||||
->setBackground($bg_color);
|
||||
$item->setImageIcon($icon);
|
||||
$item->setEpoch($dashboard->getDateModified());
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ final class DifferentialCloseConduitAPIMethod
|
|||
$revision = id(new DifferentialRevisionQuery())
|
||||
->withIDs(array($id))
|
||||
->setViewer($viewer)
|
||||
->needReviewerStatus(true)
|
||||
->needReviewers(true)
|
||||
->executeOne();
|
||||
if (!$revision) {
|
||||
throw new ConduitException('ERR_NOT_FOUND');
|
||||
|
|
|
@ -47,7 +47,7 @@ final class DifferentialCreateCommentConduitAPIMethod
|
|||
$revision = id(new DifferentialRevisionQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($request->getValue('revision_id')))
|
||||
->needReviewerStatus(true)
|
||||
->needReviewers(true)
|
||||
->needReviewerAuthority(true)
|
||||
->executeOne();
|
||||
if (!$revision) {
|
||||
|
@ -56,11 +56,28 @@ final class DifferentialCreateCommentConduitAPIMethod
|
|||
|
||||
$xactions = array();
|
||||
|
||||
$modular_map = array(
|
||||
'accept' => DifferentialRevisionAcceptTransaction::TRANSACTIONTYPE,
|
||||
'reject' => DifferentialRevisionRejectTransaction::TRANSACTIONTYPE,
|
||||
'resign' => DifferentialRevisionResignTransaction::TRANSACTIONTYPE,
|
||||
);
|
||||
|
||||
$action = $request->getValue('action');
|
||||
if ($action && ($action != 'comment') && ($action != 'none')) {
|
||||
if (isset($modular_map[$action])) {
|
||||
$xactions[] = id(new DifferentialTransaction())
|
||||
->setTransactionType(DifferentialTransaction::TYPE_ACTION)
|
||||
->setNewValue($action);
|
||||
->setTransactionType($modular_map[$action])
|
||||
->setNewValue(true);
|
||||
} else if ($action) {
|
||||
switch ($action) {
|
||||
case 'comment':
|
||||
case 'none':
|
||||
break;
|
||||
default:
|
||||
$xactions[] = id(new DifferentialTransaction())
|
||||
->setTransactionType(DifferentialTransaction::TYPE_ACTION)
|
||||
->setNewValue($action);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$content = $request->getValue('message');
|
||||
|
|
|
@ -53,7 +53,7 @@ final class DifferentialCreateRevisionConduitAPIMethod
|
|||
}
|
||||
|
||||
$revision = DifferentialRevision::initializeNewRevision($viewer);
|
||||
$revision->attachReviewerStatus(array());
|
||||
$revision->attachReviewers(array());
|
||||
|
||||
$result = $this->applyFieldEdit(
|
||||
$request,
|
||||
|
|
|
@ -39,7 +39,7 @@ final class DifferentialGetCommitMessageConduitAPIMethod
|
|||
$revision = id(new DifferentialRevisionQuery())
|
||||
->withIDs(array($id))
|
||||
->setViewer($viewer)
|
||||
->needReviewerStatus(true)
|
||||
->needReviewers(true)
|
||||
->needActiveDiffs(true)
|
||||
->executeOne();
|
||||
if (!$revision) {
|
||||
|
|
|
@ -42,15 +42,14 @@ final class DifferentialGetRevisionConduitAPIMethod
|
|||
$revision = id(new DifferentialRevisionQuery())
|
||||
->withIDs(array($revision_id))
|
||||
->setViewer($request->getUser())
|
||||
->needRelationships(true)
|
||||
->needReviewerStatus(true)
|
||||
->needReviewers(true)
|
||||
->executeOne();
|
||||
|
||||
if (!$revision) {
|
||||
throw new ConduitException('ERR_BAD_REVISION');
|
||||
}
|
||||
|
||||
$reviewer_phids = array_values($revision->getReviewers());
|
||||
$reviewer_phids = $revision->getReviewerPHIDs();
|
||||
|
||||
$diffs = id(new DifferentialDiffQuery())
|
||||
->setViewer($request->getUser())
|
||||
|
|
|
@ -182,7 +182,7 @@ final class DifferentialQueryConduitAPIMethod
|
|||
$query->withBranches($branches);
|
||||
}
|
||||
|
||||
$query->needRelationships(true);
|
||||
$query->needReviewers(true);
|
||||
$query->needCommitPHIDs(true);
|
||||
$query->needDiffIDs(true);
|
||||
$query->needActiveDiffs(true);
|
||||
|
@ -194,6 +194,14 @@ final class DifferentialQueryConduitAPIMethod
|
|||
$request->getUser(),
|
||||
$revisions);
|
||||
|
||||
if ($revisions) {
|
||||
$ccs = id(new PhabricatorSubscribersQuery())
|
||||
->withObjectPHIDs(mpull($revisions, 'getPHID'))
|
||||
->execute();
|
||||
} else {
|
||||
$ccs = array();
|
||||
}
|
||||
|
||||
$results = array();
|
||||
foreach ($revisions as $revision) {
|
||||
$diff = $revision->getActiveDiff();
|
||||
|
@ -224,8 +232,8 @@ final class DifferentialQueryConduitAPIMethod
|
|||
'activeDiffPHID' => $diff->getPHID(),
|
||||
'diffs' => $revision->getDiffIDs(),
|
||||
'commits' => $revision->getCommitPHIDs(),
|
||||
'reviewers' => array_values($revision->getReviewers()),
|
||||
'ccs' => array_values($revision->getCCPHIDs()),
|
||||
'reviewers' => $revision->getReviewerPHIDs(),
|
||||
'ccs' => idx($ccs, $phid, array()),
|
||||
'hashes' => $revision->getHashes(),
|
||||
'auxiliary' => idx($field_data, $phid, array()),
|
||||
'repositoryPHID' => $diff->getRepositoryPHID(),
|
||||
|
|
|
@ -57,7 +57,7 @@ final class DifferentialUpdateRevisionConduitAPIMethod
|
|||
$revision = id(new DifferentialRevisionQuery())
|
||||
->setViewer($request->getUser())
|
||||
->withIDs(array($request->getValue('id')))
|
||||
->needReviewerStatus(true)
|
||||
->needReviewers(true)
|
||||
->needActiveDiffs(true)
|
||||
->requireCapabilities(
|
||||
array(
|
||||
|
|
|
@ -119,37 +119,4 @@ final class DifferentialAction extends Phobject {
|
|||
return $title;
|
||||
}
|
||||
|
||||
public static function getActionVerb($action) {
|
||||
$verbs = array(
|
||||
self::ACTION_COMMENT => pht('Comment'),
|
||||
self::ACTION_ACCEPT => pht("Accept Revision \xE2\x9C\x94"),
|
||||
self::ACTION_REJECT => pht("Request Changes \xE2\x9C\x98"),
|
||||
self::ACTION_RETHINK => pht("Plan Changes \xE2\x9C\x98"),
|
||||
self::ACTION_ABANDON => pht('Abandon Revision'),
|
||||
self::ACTION_REQUEST => pht('Request Review'),
|
||||
self::ACTION_RECLAIM => pht('Reclaim Revision'),
|
||||
self::ACTION_RESIGN => pht('Resign as Reviewer'),
|
||||
self::ACTION_ADDREVIEWERS => pht('Add Reviewers'),
|
||||
self::ACTION_ADDCCS => pht('Add Subscribers'),
|
||||
self::ACTION_CLOSE => pht('Close Revision'),
|
||||
self::ACTION_CLAIM => pht('Commandeer Revision'),
|
||||
self::ACTION_REOPEN => pht('Reopen'),
|
||||
);
|
||||
|
||||
if (!empty($verbs[$action])) {
|
||||
return $verbs[$action];
|
||||
} else {
|
||||
return pht('brazenly %s', $action);
|
||||
}
|
||||
}
|
||||
|
||||
public static function allowReviewers($action) {
|
||||
if ($action == self::ACTION_ADDREVIEWERS ||
|
||||
$action == self::ACTION_REQUEST ||
|
||||
$action == self::ACTION_RESIGN) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,8 +17,7 @@ final class DifferentialRevisionViewController extends DifferentialController {
|
|||
$revision = id(new DifferentialRevisionQuery())
|
||||
->withIDs(array($this->revisionID))
|
||||
->setViewer($viewer)
|
||||
->needRelationships(true)
|
||||
->needReviewerStatus(true)
|
||||
->needReviewers(true)
|
||||
->needReviewerAuthority(true)
|
||||
->executeOne();
|
||||
if (!$revision) {
|
||||
|
@ -103,9 +102,12 @@ final class DifferentialRevisionViewController extends DifferentialController {
|
|||
$this->loadDiffProperties($diffs);
|
||||
$props = $target_manual->getDiffProperties();
|
||||
|
||||
$subscriber_phids = PhabricatorSubscribersQuery::loadSubscribersForPHID(
|
||||
$revision->getPHID());
|
||||
|
||||
$object_phids = array_merge(
|
||||
$revision->getReviewers(),
|
||||
$revision->getCCPHIDs(),
|
||||
$revision->getReviewerPHIDs(),
|
||||
$subscriber_phids,
|
||||
$revision->loadCommitPHIDs(),
|
||||
array(
|
||||
$revision->getAuthorPHID(),
|
||||
|
@ -782,7 +784,7 @@ final class DifferentialRevisionViewController extends DifferentialController {
|
|||
->setLimit(10)
|
||||
->needFlags(true)
|
||||
->needDrafts(true)
|
||||
->needRelationships(true);
|
||||
->needReviewers(true);
|
||||
|
||||
foreach ($path_map as $path => $path_id) {
|
||||
$query->withPath($repository->getID(), $path_id);
|
||||
|
|
|
@ -70,6 +70,15 @@ abstract class DifferentialCustomField
|
|||
return array();
|
||||
}
|
||||
|
||||
protected function getActiveDiff() {
|
||||
$object = $this->getObject();
|
||||
try {
|
||||
return $object->getActiveDiff();
|
||||
} catch (Exception $ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public function getRequiredHandlePHIDsForRevisionHeaderWarnings() {
|
||||
return array();
|
||||
}
|
||||
|
|
|
@ -42,14 +42,17 @@ final class DifferentialProjectReviewersField
|
|||
->setReviewers($reviewers)
|
||||
->setHandles($handles);
|
||||
|
||||
// TODO: Active diff stuff.
|
||||
$diff = $this->getActiveDiff();
|
||||
if ($diff) {
|
||||
$view->setActiveDiff($diff);
|
||||
}
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
private function getProjectReviewers() {
|
||||
$reviewers = array();
|
||||
foreach ($this->getObject()->getReviewerStatus() as $reviewer) {
|
||||
foreach ($this->getObject()->getReviewers() as $reviewer) {
|
||||
if (!$reviewer->isUser()) {
|
||||
$reviewers[] = $reviewer;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ final class DifferentialReviewersField
|
|||
|
||||
protected function readValueFromRevision(
|
||||
DifferentialRevision $revision) {
|
||||
return $revision->getReviewerStatus();
|
||||
return $revision->getReviewers();
|
||||
}
|
||||
|
||||
public function shouldAppearInPropertyView() {
|
||||
|
@ -43,14 +43,17 @@ final class DifferentialReviewersField
|
|||
->setReviewers($reviewers)
|
||||
->setHandles($handles);
|
||||
|
||||
// TODO: Active diff stuff.
|
||||
$diff = $this->getActiveDiff();
|
||||
if ($diff) {
|
||||
$view->setActiveDiff($diff);
|
||||
}
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
private function getUserReviewers() {
|
||||
$reviewers = array();
|
||||
foreach ($this->getObject()->getReviewerStatus() as $reviewer) {
|
||||
foreach ($this->getObject()->getReviewers() as $reviewer) {
|
||||
if ($reviewer->isUser()) {
|
||||
$reviewers[] = $reviewer;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ final class DifferentialDoorkeeperRevisionFeedStoryPublisher
|
|||
return id(new DifferentialRevisionQuery())
|
||||
->setViewer($this->getViewer())
|
||||
->withIDs(array($object->getID()))
|
||||
->needRelationships(true)
|
||||
->needReviewers(true)
|
||||
->executeOne();
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@ final class DifferentialDoorkeeperRevisionFeedStoryPublisher
|
|||
public function getActiveUserPHIDs($object) {
|
||||
$status = $object->getStatus();
|
||||
if ($status == ArcanistDifferentialRevisionStatus::NEEDS_REVIEW) {
|
||||
return $object->getReviewers();
|
||||
return $object->getReviewerPHIDs();
|
||||
} else {
|
||||
return array();
|
||||
}
|
||||
|
@ -48,12 +48,13 @@ final class DifferentialDoorkeeperRevisionFeedStoryPublisher
|
|||
if ($status == ArcanistDifferentialRevisionStatus::NEEDS_REVIEW) {
|
||||
return array();
|
||||
} else {
|
||||
return $object->getReviewers();
|
||||
return $object->getReviewerPHIDs();
|
||||
}
|
||||
}
|
||||
|
||||
public function getCCUserPHIDs($object) {
|
||||
return $object->getCCPHIDs();
|
||||
return PhabricatorSubscribersQuery::loadSubscribersForPHID(
|
||||
$object->getPHID());
|
||||
}
|
||||
|
||||
public function getObjectTitle($object) {
|
||||
|
|
|
@ -41,7 +41,7 @@ final class DifferentialRevisionEditEngine
|
|||
protected function newObjectQuery() {
|
||||
return id(new DifferentialRevisionQuery())
|
||||
->needActiveDiffs(true)
|
||||
->needReviewerStatus(true)
|
||||
->needReviewers(true)
|
||||
->needReviewerAuthority(true);
|
||||
}
|
||||
|
||||
|
|
|
@ -130,33 +130,6 @@ final class DifferentialTransactionEditor
|
|||
|
||||
$action_type = $xaction->getNewValue();
|
||||
switch ($action_type) {
|
||||
case DifferentialAction::ACTION_ACCEPT:
|
||||
case DifferentialAction::ACTION_REJECT:
|
||||
if ($action_type == DifferentialAction::ACTION_ACCEPT) {
|
||||
$new_status = DifferentialReviewerStatus::STATUS_ACCEPTED;
|
||||
} else {
|
||||
$new_status = DifferentialReviewerStatus::STATUS_REJECTED;
|
||||
}
|
||||
|
||||
$actor = $this->getActor();
|
||||
|
||||
// These transactions can cause effects in two ways: by altering the
|
||||
// status of an existing reviewer; or by adding the actor as a new
|
||||
// reviewer.
|
||||
|
||||
$will_add_reviewer = true;
|
||||
foreach ($object->getReviewerStatus() as $reviewer) {
|
||||
if ($reviewer->hasAuthority($actor)) {
|
||||
if ($reviewer->getStatus() != $new_status) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if ($reviewer->getReviewerPHID() == $actor_phid) {
|
||||
$will_add_reviwer = false;
|
||||
}
|
||||
}
|
||||
|
||||
return $will_add_reviewer;
|
||||
case DifferentialAction::ACTION_CLOSE:
|
||||
return ($object->getStatus() != $status_closed);
|
||||
case DifferentialAction::ACTION_ABANDON:
|
||||
|
@ -169,13 +142,6 @@ final class DifferentialTransactionEditor
|
|||
return ($object->getStatus() != $status_plan);
|
||||
case DifferentialAction::ACTION_REQUEST:
|
||||
return ($object->getStatus() != $status_review);
|
||||
case DifferentialAction::ACTION_RESIGN:
|
||||
foreach ($object->getReviewerStatus() as $reviewer) {
|
||||
if ($reviewer->getReviewerPHID() == $actor_phid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
case DifferentialAction::ACTION_CLAIM:
|
||||
return ($actor_phid != $object->getAuthorPHID());
|
||||
}
|
||||
|
@ -222,12 +188,6 @@ final class DifferentialTransactionEditor
|
|||
return;
|
||||
case DifferentialTransaction::TYPE_ACTION:
|
||||
switch ($xaction->getNewValue()) {
|
||||
case DifferentialAction::ACTION_RESIGN:
|
||||
case DifferentialAction::ACTION_ACCEPT:
|
||||
case DifferentialAction::ACTION_REJECT:
|
||||
// These have no direct effects, and affect review status only
|
||||
// indirectly by altering reviewers with TYPE_EDGE transactions.
|
||||
return;
|
||||
case DifferentialAction::ACTION_ABANDON:
|
||||
$object->setStatus(ArcanistDifferentialRevisionStatus::ABANDONED);
|
||||
return;
|
||||
|
@ -366,9 +326,9 @@ final class DifferentialTransactionEditor
|
|||
// actually change the diff text.
|
||||
|
||||
$edits = array();
|
||||
foreach ($object->getReviewerStatus() as $reviewer) {
|
||||
foreach ($object->getReviewers() as $reviewer) {
|
||||
if ($downgrade_rejects) {
|
||||
if ($reviewer->getStatus() == $new_reject) {
|
||||
if ($reviewer->getReviewerStatus() == $new_reject) {
|
||||
$edits[$reviewer->getReviewerPHID()] = array(
|
||||
'data' => array(
|
||||
'status' => $old_reject,
|
||||
|
@ -378,7 +338,7 @@ final class DifferentialTransactionEditor
|
|||
}
|
||||
|
||||
if ($downgrade_accepts) {
|
||||
if ($reviewer->getStatus() == $new_accept) {
|
||||
if ($reviewer->getReviewerStatus() == $new_accept) {
|
||||
$edits[$reviewer->getReviewerPHID()] = array(
|
||||
'data' => array(
|
||||
'status' => $old_accept,
|
||||
|
@ -455,9 +415,9 @@ final class DifferentialTransactionEditor
|
|||
);
|
||||
|
||||
$edits = array();
|
||||
foreach ($object->getReviewerStatus() as $reviewer) {
|
||||
foreach ($object->getReviewers() as $reviewer) {
|
||||
if ($reviewer->getReviewerPHID() == $actor_phid) {
|
||||
if ($reviewer->getStatus() == $status_added) {
|
||||
if ($reviewer->getReviewerStatus() == $status_added) {
|
||||
$edits[$actor_phid] = array(
|
||||
'data' => $data,
|
||||
);
|
||||
|
@ -482,59 +442,9 @@ final class DifferentialTransactionEditor
|
|||
$action_type = $xaction->getNewValue();
|
||||
|
||||
switch ($action_type) {
|
||||
case DifferentialAction::ACTION_ACCEPT:
|
||||
case DifferentialAction::ACTION_REJECT:
|
||||
if ($action_type == DifferentialAction::ACTION_ACCEPT) {
|
||||
$data = array(
|
||||
'status' => DifferentialReviewerStatus::STATUS_ACCEPTED,
|
||||
);
|
||||
} else {
|
||||
$data = array(
|
||||
'status' => DifferentialReviewerStatus::STATUS_REJECTED,
|
||||
);
|
||||
}
|
||||
|
||||
$edits = array();
|
||||
|
||||
foreach ($object->getReviewerStatus() as $reviewer) {
|
||||
if ($reviewer->hasAuthority($actor)) {
|
||||
$edits[$reviewer->getReviewerPHID()] = array(
|
||||
'data' => $data,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Also either update or add the actor themselves as a reviewer.
|
||||
$edits[$actor_phid] = array(
|
||||
'data' => $data,
|
||||
);
|
||||
|
||||
$results[] = id(new DifferentialTransaction())
|
||||
->setTransactionType($type_edge)
|
||||
->setMetadataValue('edge:type', $edge_reviewer)
|
||||
->setIgnoreOnNoEffect(true)
|
||||
->setNewValue(array('+' => $edits));
|
||||
break;
|
||||
|
||||
case DifferentialAction::ACTION_CLAIM:
|
||||
$is_commandeer = true;
|
||||
break;
|
||||
case DifferentialAction::ACTION_RESIGN:
|
||||
// If the user is resigning, add a separate reviewer edit
|
||||
// transaction which removes them as a reviewer.
|
||||
|
||||
$results[] = id(new DifferentialTransaction())
|
||||
->setTransactionType($type_edge)
|
||||
->setMetadataValue('edge:type', $edge_reviewer)
|
||||
->setIgnoreOnNoEffect(true)
|
||||
->setNewValue(
|
||||
array(
|
||||
'-' => array(
|
||||
$actor_phid => $actor_phid,
|
||||
),
|
||||
));
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -704,7 +614,7 @@ final class DifferentialTransactionEditor
|
|||
|
||||
$new_revision = id(new DifferentialRevisionQuery())
|
||||
->setViewer($this->getActor())
|
||||
->needReviewerStatus(true)
|
||||
->needReviewers(true)
|
||||
->needActiveDiffs(true)
|
||||
->withIDs(array($object->getID()))
|
||||
->executeOne();
|
||||
|
@ -713,7 +623,7 @@ final class DifferentialTransactionEditor
|
|||
pht('Failed to load revision from transaction finalization.'));
|
||||
}
|
||||
|
||||
$object->attachReviewerStatus($new_revision->getReviewerStatus());
|
||||
$object->attachReviewers($new_revision->getReviewers());
|
||||
$object->attachActiveDiff($new_revision->getActiveDiff());
|
||||
$object->attachRepository($new_revision->getRepository());
|
||||
|
||||
|
@ -735,7 +645,11 @@ final class DifferentialTransactionEditor
|
|||
$status_revision = ArcanistDifferentialRevisionStatus::NEEDS_REVISION;
|
||||
$status_review = ArcanistDifferentialRevisionStatus::NEEDS_REVIEW;
|
||||
|
||||
$is_sticky_accept = PhabricatorEnv::getEnvConfig(
|
||||
'differential.sticky-accept');
|
||||
|
||||
$old_status = $object->getStatus();
|
||||
$active_diff = $object->getActiveDiff();
|
||||
switch ($old_status) {
|
||||
case $status_accepted:
|
||||
case $status_revision:
|
||||
|
@ -751,11 +665,17 @@ final class DifferentialTransactionEditor
|
|||
$has_rejecting_reviewer = false;
|
||||
$has_rejecting_older_reviewer = false;
|
||||
$has_blocking_reviewer = false;
|
||||
foreach ($object->getReviewerStatus() as $reviewer) {
|
||||
$reviewer_status = $reviewer->getStatus();
|
||||
foreach ($object->getReviewers() as $reviewer) {
|
||||
$reviewer_status = $reviewer->getReviewerStatus();
|
||||
switch ($reviewer_status) {
|
||||
case DifferentialReviewerStatus::STATUS_REJECTED:
|
||||
$has_rejecting_reviewer = true;
|
||||
$action_phid = $reviewer->getLastActionDiffPHID();
|
||||
$active_phid = $active_diff->getPHID();
|
||||
$is_current = ($action_phid == $active_phid);
|
||||
|
||||
if ($is_current) {
|
||||
$has_rejecting_reviewer = true;
|
||||
}
|
||||
break;
|
||||
case DifferentialReviewerStatus::STATUS_REJECTED_OLDER:
|
||||
$has_rejecting_older_reviewer = true;
|
||||
|
@ -765,7 +685,13 @@ final class DifferentialTransactionEditor
|
|||
break;
|
||||
case DifferentialReviewerStatus::STATUS_ACCEPTED:
|
||||
if ($reviewer->isUser()) {
|
||||
$has_accepting_user = true;
|
||||
$action_phid = $reviewer->getLastActionDiffPHID();
|
||||
$active_phid = $active_diff->getPHID();
|
||||
$is_current = ($action_phid == $active_phid);
|
||||
|
||||
if ($is_sticky_accept || $is_current) {
|
||||
$has_accepting_user = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -808,6 +734,9 @@ final class DifferentialTransactionEditor
|
|||
break;
|
||||
}
|
||||
|
||||
|
||||
$this->markReviewerComments($object, $xactions);
|
||||
|
||||
return $xactions;
|
||||
}
|
||||
|
||||
|
@ -925,60 +854,6 @@ final class DifferentialTransactionEditor
|
|||
$status_closed = ArcanistDifferentialRevisionStatus::CLOSED;
|
||||
|
||||
switch ($action) {
|
||||
case DifferentialAction::ACTION_ACCEPT:
|
||||
if ($actor_is_author && !$allow_self_accept) {
|
||||
return pht(
|
||||
'You can not accept this revision because you are the owner.');
|
||||
}
|
||||
|
||||
if ($revision_status == $status_abandoned) {
|
||||
return pht(
|
||||
'You can not accept this revision because it has been '.
|
||||
'abandoned.');
|
||||
}
|
||||
|
||||
if ($revision_status == $status_closed) {
|
||||
return pht(
|
||||
'You can not accept this revision because it has already been '.
|
||||
'closed.');
|
||||
}
|
||||
|
||||
// TODO: It would be nice to make this generic at some point.
|
||||
$signatures = DifferentialRequiredSignaturesField::loadForRevision(
|
||||
$revision);
|
||||
foreach ($signatures as $phid => $signed) {
|
||||
if (!$signed) {
|
||||
return pht(
|
||||
'You can not accept this revision because the author has '.
|
||||
'not signed all of the required legal documents.');
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case DifferentialAction::ACTION_REJECT:
|
||||
if ($actor_is_author) {
|
||||
return pht('You can not request changes to your own revision.');
|
||||
}
|
||||
|
||||
if ($revision_status == $status_abandoned) {
|
||||
return pht(
|
||||
'You can not request changes to this revision because it has been '.
|
||||
'abandoned.');
|
||||
}
|
||||
|
||||
if ($revision_status == $status_closed) {
|
||||
return pht(
|
||||
'You can not request changes to this revision because it has '.
|
||||
'already been closed.');
|
||||
}
|
||||
break;
|
||||
|
||||
case DifferentialAction::ACTION_RESIGN:
|
||||
// You can always resign from a revision if you're a reviewer. If you
|
||||
// aren't, this is a no-op rather than invalid.
|
||||
break;
|
||||
|
||||
case DifferentialAction::ACTION_CLAIM:
|
||||
// You can claim a revision if you're not the owner. If you are, this
|
||||
// is a no-op rather than invalid.
|
||||
|
@ -1173,7 +1048,7 @@ final class DifferentialTransactionEditor
|
|||
protected function getMailTo(PhabricatorLiskDAO $object) {
|
||||
$phids = array();
|
||||
$phids[] = $object->getAuthorPHID();
|
||||
foreach ($object->getReviewerStatus() as $reviewer) {
|
||||
foreach ($object->getReviewers() as $reviewer) {
|
||||
$phids[] = $reviewer->getReviewerPHID();
|
||||
}
|
||||
return $phids;
|
||||
|
@ -1648,7 +1523,7 @@ final class DifferentialTransactionEditor
|
|||
// and both are needlessly complex. This logic should live in the normal
|
||||
// transaction application pipeline. See T10967.
|
||||
|
||||
$reviewers = $object->getReviewerStatus();
|
||||
$reviewers = $object->getReviewers();
|
||||
$reviewers = mpull($reviewers, null, 'getReviewerPHID');
|
||||
|
||||
if ($is_blocking) {
|
||||
|
@ -1669,7 +1544,7 @@ final class DifferentialTransactionEditor
|
|||
// If we're applying a stronger status (usually, upgrading a reviewer
|
||||
// into a blocking reviewer), skip this check so we apply the change.
|
||||
$old_strength = DifferentialReviewerStatus::getStatusStrength(
|
||||
$reviewers[$phid]->getStatus());
|
||||
$reviewers[$phid]->getReviewerStatus());
|
||||
if ($old_strength <= $new_strength) {
|
||||
continue;
|
||||
}
|
||||
|
@ -1687,22 +1562,21 @@ final class DifferentialTransactionEditor
|
|||
|
||||
$value = array();
|
||||
foreach ($phids as $phid) {
|
||||
$value[$phid] = array(
|
||||
'data' => array(
|
||||
'status' => $new_status,
|
||||
),
|
||||
);
|
||||
if ($is_blocking) {
|
||||
$value[] = 'blocking('.$phid.')';
|
||||
} else {
|
||||
$value[] = $phid;
|
||||
}
|
||||
}
|
||||
|
||||
$edgetype_reviewer = DifferentialRevisionHasReviewerEdgeType::EDGECONST;
|
||||
|
||||
$owners_phid = id(new PhabricatorOwnersApplication())
|
||||
->getPHID();
|
||||
|
||||
$reviewers_type = DifferentialRevisionReviewersTransaction::TRANSACTIONTYPE;
|
||||
|
||||
return $object->getApplicationTransactionTemplate()
|
||||
->setAuthorPHID($owners_phid)
|
||||
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
|
||||
->setMetadataValue('edge:type', $edgetype_reviewer)
|
||||
->setTransactionType($reviewers_type)
|
||||
->setNewValue(
|
||||
array(
|
||||
'+' => $value,
|
||||
|
@ -1717,7 +1591,7 @@ final class DifferentialTransactionEditor
|
|||
->setViewer($this->getActor())
|
||||
->withPHIDs(array($object->getPHID()))
|
||||
->needActiveDiffs(true)
|
||||
->needReviewerStatus(true)
|
||||
->needReviewers(true)
|
||||
->executeOne();
|
||||
if (!$revision) {
|
||||
throw new Exception(
|
||||
|
@ -1933,7 +1807,7 @@ final class DifferentialTransactionEditor
|
|||
// Reload to pick up the active diff and reviewer status.
|
||||
return id(new DifferentialRevisionQuery())
|
||||
->setViewer($this->getActor())
|
||||
->needReviewerStatus(true)
|
||||
->needReviewers(true)
|
||||
->needActiveDiffs(true)
|
||||
->withIDs(array($object->getID()))
|
||||
->executeOne();
|
||||
|
@ -1981,4 +1855,59 @@ final class DifferentialTransactionEditor
|
|||
->setNewValue($edits);
|
||||
}
|
||||
|
||||
public function getActiveDiff($object) {
|
||||
if ($this->getIsNewObject()) {
|
||||
return null;
|
||||
} else {
|
||||
return $object->getActiveDiff();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When a reviewer makes a comment, mark the last revision they commented
|
||||
* on.
|
||||
*
|
||||
* This allows us to show a hint to help authors and other reviewers quickly
|
||||
* distinguish between reviewers who have participated in the discussion and
|
||||
* reviewers who haven't been part of it.
|
||||
*/
|
||||
private function markReviewerComments($object, array $xactions) {
|
||||
$acting_phid = $this->getActingAsPHID();
|
||||
if (!$acting_phid) {
|
||||
return;
|
||||
}
|
||||
|
||||
$diff = $this->getActiveDiff($object);
|
||||
if (!$diff) {
|
||||
return;
|
||||
}
|
||||
|
||||
$has_comment = false;
|
||||
foreach ($xactions as $xaction) {
|
||||
if ($xaction->hasComment()) {
|
||||
$has_comment = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$has_comment) {
|
||||
return;
|
||||
}
|
||||
|
||||
$reviewer_table = new DifferentialReviewer();
|
||||
$conn = $reviewer_table->establishConnection('w');
|
||||
|
||||
queryfx(
|
||||
$conn,
|
||||
'UPDATE %T SET lastCommentDiffPHID = %s
|
||||
WHERE revisionPHID = %s
|
||||
AND reviewerPHID = %s',
|
||||
$reviewer_table->getTableName(),
|
||||
$diff->getPHID(),
|
||||
$object->getPHID(),
|
||||
$acting_phid);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ final class DifferentialHovercardEngineExtension
|
|||
$revisions = id(new DifferentialRevisionQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs($phids)
|
||||
->needReviewerStatus(true)
|
||||
->needReviewers(true)
|
||||
->execute();
|
||||
$revisions = mpull($revisions, null, 'getPHID');
|
||||
|
||||
|
@ -54,8 +54,7 @@ final class DifferentialHovercardEngineExtension
|
|||
pht('Author'),
|
||||
$viewer->renderHandle($revision->getAuthorPHID()));
|
||||
|
||||
$reviewer_phids = $revision->getReviewerStatus();
|
||||
$reviewer_phids = mpull($reviewer_phids, 'getReviewerPHID');
|
||||
$reviewer_phids = $revision->getReviewerPHIDs();
|
||||
|
||||
$hovercard->addField(
|
||||
pht('Reviewers'),
|
||||
|
|
|
@ -37,10 +37,9 @@ final class DifferentialReviewedByCommitMessageField
|
|||
}
|
||||
|
||||
$phids = array();
|
||||
foreach ($revision->getReviewerStatus() as $reviewer) {
|
||||
switch ($reviewer->getStatus()) {
|
||||
foreach ($revision->getReviewers() as $reviewer) {
|
||||
switch ($reviewer->getReviewerStatus()) {
|
||||
case DifferentialReviewerStatus::STATUS_ACCEPTED:
|
||||
case DifferentialReviewerStatus::STATUS_ACCEPTED_OLDER:
|
||||
$phids[] = $reviewer->getReviewerPHID();
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -45,8 +45,8 @@ final class DifferentialReviewersCommitMessageField
|
|||
$status_blocking = DifferentialReviewerStatus::STATUS_BLOCKING;
|
||||
|
||||
$results = array();
|
||||
foreach ($revision->getReviewerStatus() as $reviewer) {
|
||||
if ($reviewer->getStatus() == $status_blocking) {
|
||||
foreach ($revision->getReviewers() as $reviewer) {
|
||||
if ($reviewer->getReviewerStatus() == $status_blocking) {
|
||||
$suffixes = array('!' => '!');
|
||||
} else {
|
||||
$suffixes = array();
|
||||
|
|
|
@ -37,8 +37,7 @@ abstract class DifferentialReviewersHeraldAction
|
|||
}
|
||||
}
|
||||
|
||||
$reviewers = $object->getReviewerStatus();
|
||||
$reviewers = mpull($reviewers, null, 'getReviewerPHID');
|
||||
$reviewers = $object->getReviewers();
|
||||
|
||||
if ($is_blocking) {
|
||||
$new_status = DifferentialReviewerStatus::STATUS_BLOCKING;
|
||||
|
@ -58,7 +57,7 @@ abstract class DifferentialReviewersHeraldAction
|
|||
// If we're applying a stronger status (usually, upgrading a reviewer
|
||||
// into a blocking reviewer), skip this check so we apply the change.
|
||||
$old_strength = DifferentialReviewerStatus::getStatusStrength(
|
||||
$reviewers[$phid]->getStatus());
|
||||
$reviewers[$phid]->getReviewerStatus());
|
||||
if ($old_strength <= $new_strength) {
|
||||
continue;
|
||||
}
|
||||
|
@ -81,18 +80,17 @@ abstract class DifferentialReviewersHeraldAction
|
|||
|
||||
$value = array();
|
||||
foreach ($phids as $phid) {
|
||||
$value[$phid] = array(
|
||||
'data' => array(
|
||||
'status' => $new_status,
|
||||
),
|
||||
);
|
||||
if ($is_blocking) {
|
||||
$value[] = 'blocking('.$phid.')';
|
||||
} else {
|
||||
$value[] = $phid;
|
||||
}
|
||||
}
|
||||
|
||||
$edgetype_reviewer = DifferentialRevisionHasReviewerEdgeType::EDGECONST;
|
||||
$reviewers_type = DifferentialRevisionReviewersTransaction::TRANSACTIONTYPE;
|
||||
|
||||
$xaction = $adapter->newTransaction()
|
||||
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
|
||||
->setMetadataValue('edge:type', $edgetype_reviewer)
|
||||
->setTransactionType($reviewers_type)
|
||||
->setNewValue(
|
||||
array(
|
||||
'+' => $value,
|
||||
|
|
|
@ -85,8 +85,7 @@ final class HeraldDifferentialRevisionAdapter
|
|||
$revision = id(new DifferentialRevisionQuery())
|
||||
->withIDs(array($revision->getID()))
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->needRelationships(true)
|
||||
->needReviewerStatus(true)
|
||||
->needReviewers(true)
|
||||
->executeOne();
|
||||
|
||||
$object->revision = $revision;
|
||||
|
@ -138,8 +137,7 @@ final class HeraldDifferentialRevisionAdapter
|
|||
}
|
||||
|
||||
public function loadReviewers() {
|
||||
$reviewers = $this->getObject()->getReviewerStatus();
|
||||
return mpull($reviewers, 'getReviewerPHID');
|
||||
return $this->getObject()->getReviewerPHIDs();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ final class PhabricatorDifferentialRevisionTestDataGenerator
|
|||
$author = $this->loadPhabricatorUser();
|
||||
|
||||
$revision = DifferentialRevision::initializeNewRevision($author);
|
||||
$revision->attachReviewerStatus(array());
|
||||
$revision->attachReviewers(array());
|
||||
$revision->attachActiveDiff(null);
|
||||
|
||||
// This could be a bit richer and more formal than it is.
|
||||
|
|
|
@ -18,7 +18,7 @@ final class DifferentialRevisionMailReceiver
|
|||
return id(new DifferentialRevisionQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($id))
|
||||
->needReviewerStatus(true)
|
||||
->needReviewers(true)
|
||||
->needReviewerAuthority(true)
|
||||
->needActiveDiffs(true)
|
||||
->executeOne();
|
||||
|
|
|
@ -43,12 +43,11 @@ final class DifferentialRevisionQuery
|
|||
const ORDER_MODIFIED = 'order-modified';
|
||||
const ORDER_CREATED = 'order-created';
|
||||
|
||||
private $needRelationships = false;
|
||||
private $needActiveDiffs = false;
|
||||
private $needDiffIDs = false;
|
||||
private $needCommitPHIDs = false;
|
||||
private $needHashes = false;
|
||||
private $needReviewerStatus = false;
|
||||
private $needReviewers = false;
|
||||
private $needReviewerAuthority;
|
||||
private $needDrafts;
|
||||
private $needFlags;
|
||||
|
@ -227,20 +226,6 @@ final class DifferentialRevisionQuery
|
|||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set whether or not the query will load and attach relationships.
|
||||
*
|
||||
* @param bool True to load and attach relationships.
|
||||
* @return this
|
||||
* @task config
|
||||
*/
|
||||
public function needRelationships($need_relationships) {
|
||||
$this->needRelationships = $need_relationships;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set whether or not the query should load the active diff for each
|
||||
* revision.
|
||||
|
@ -298,14 +283,14 @@ final class DifferentialRevisionQuery
|
|||
|
||||
|
||||
/**
|
||||
* Set whether or not the query should load associated reviewer status.
|
||||
* Set whether or not the query should load associated reviewers.
|
||||
*
|
||||
* @param bool True to load and attach reviewers.
|
||||
* @return this
|
||||
* @task config
|
||||
*/
|
||||
public function needReviewerStatus($need_reviewer_status) {
|
||||
$this->needReviewerStatus = $need_reviewer_status;
|
||||
public function needReviewers($need_reviewers) {
|
||||
$this->needReviewers = $need_reviewers;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -425,10 +410,6 @@ final class DifferentialRevisionQuery
|
|||
$table = new DifferentialRevision();
|
||||
$conn_r = $table->establishConnection('r');
|
||||
|
||||
if ($this->needRelationships) {
|
||||
$this->loadRelationships($conn_r, $revisions);
|
||||
}
|
||||
|
||||
if ($this->needCommitPHIDs) {
|
||||
$this->loadCommitPHIDs($conn_r, $revisions);
|
||||
}
|
||||
|
@ -448,7 +429,7 @@ final class DifferentialRevisionQuery
|
|||
$this->loadHashes($conn_r, $revisions);
|
||||
}
|
||||
|
||||
if ($this->needReviewerStatus || $this->needReviewerAuthority) {
|
||||
if ($this->needReviewers || $this->needReviewerAuthority) {
|
||||
$this->loadReviewers($conn_r, $revisions);
|
||||
}
|
||||
|
||||
|
@ -605,11 +586,11 @@ final class DifferentialRevisionQuery
|
|||
if ($this->reviewers) {
|
||||
$joins[] = qsprintf(
|
||||
$conn_r,
|
||||
'JOIN %T e_reviewers ON e_reviewers.src = r.phid '.
|
||||
'AND e_reviewers.type = %s '.
|
||||
'AND e_reviewers.dst in (%Ls)',
|
||||
PhabricatorEdgeConfig::TABLE_NAME_EDGE,
|
||||
DifferentialRevisionHasReviewerEdgeType::EDGECONST,
|
||||
'JOIN %T reviewer ON reviewer.revisionPHID = r.phid
|
||||
AND reviewer.reviewerStatus != %s
|
||||
AND reviewer.reviewerPHID in (%Ls)',
|
||||
id(new DifferentialReviewer())->getTableName(),
|
||||
DifferentialReviewerStatus::STATUS_RESIGNED,
|
||||
$this->reviewers);
|
||||
}
|
||||
|
||||
|
@ -854,40 +835,6 @@ final class DifferentialRevisionQuery
|
|||
);
|
||||
}
|
||||
|
||||
private function loadRelationships($conn_r, array $revisions) {
|
||||
assert_instances_of($revisions, 'DifferentialRevision');
|
||||
|
||||
$type_reviewer = DifferentialRevisionHasReviewerEdgeType::EDGECONST;
|
||||
$type_subscriber = PhabricatorObjectHasSubscriberEdgeType::EDGECONST;
|
||||
|
||||
$edges = id(new PhabricatorEdgeQuery())
|
||||
->withSourcePHIDs(mpull($revisions, 'getPHID'))
|
||||
->withEdgeTypes(array($type_reviewer, $type_subscriber))
|
||||
->setOrder(PhabricatorEdgeQuery::ORDER_OLDEST_FIRST)
|
||||
->execute();
|
||||
|
||||
$type_map = array(
|
||||
DifferentialRevision::RELATION_REVIEWER => $type_reviewer,
|
||||
DifferentialRevision::RELATION_SUBSCRIBED => $type_subscriber,
|
||||
);
|
||||
|
||||
foreach ($revisions as $revision) {
|
||||
$data = array();
|
||||
foreach ($type_map as $rel_type => $edge_type) {
|
||||
$revision_edges = $edges[$revision->getPHID()][$edge_type];
|
||||
foreach ($revision_edges as $dst_phid => $edge_data) {
|
||||
$data[] = array(
|
||||
'relation' => $rel_type,
|
||||
'objectPHID' => $dst_phid,
|
||||
'reasonPHID' => null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$revision->attachRelationships($data);
|
||||
}
|
||||
}
|
||||
|
||||
private function loadCommitPHIDs($conn_r, array $revisions) {
|
||||
assert_instances_of($revisions, 'DifferentialRevision');
|
||||
$commit_phids = queryfx_all(
|
||||
|
@ -972,21 +919,28 @@ final class DifferentialRevisionQuery
|
|||
}
|
||||
|
||||
private function loadReviewers(
|
||||
AphrontDatabaseConnection $conn_r,
|
||||
AphrontDatabaseConnection $conn,
|
||||
array $revisions) {
|
||||
|
||||
assert_instances_of($revisions, 'DifferentialRevision');
|
||||
$edge_type = DifferentialRevisionHasReviewerEdgeType::EDGECONST;
|
||||
|
||||
$edges = id(new PhabricatorEdgeQuery())
|
||||
->withSourcePHIDs(mpull($revisions, 'getPHID'))
|
||||
->withEdgeTypes(array($edge_type))
|
||||
->needEdgeData(true)
|
||||
->setOrder(PhabricatorEdgeQuery::ORDER_OLDEST_FIRST)
|
||||
->execute();
|
||||
$reviewer_table = new DifferentialReviewer();
|
||||
$reviewer_rows = queryfx_all(
|
||||
$conn,
|
||||
'SELECT * FROM %T WHERE revisionPHID IN (%Ls)
|
||||
ORDER BY id ASC',
|
||||
$reviewer_table->getTableName(),
|
||||
mpull($revisions, 'getPHID'));
|
||||
$reviewer_list = $reviewer_table->loadAllFromArray($reviewer_rows);
|
||||
$reviewer_map = mgroup($reviewer_list, 'getRevisionPHID');
|
||||
|
||||
foreach ($reviewer_map as $key => $reviewers) {
|
||||
$reviewer_map[$key] = mpull($reviewers, null, 'getReviewerPHID');
|
||||
}
|
||||
|
||||
$viewer = $this->getViewer();
|
||||
$viewer_phid = $viewer->getPHID();
|
||||
|
||||
$allow_key = 'differential.allow-self-accept';
|
||||
$allow_self = PhabricatorEnv::getEnvConfig($allow_key);
|
||||
|
||||
|
@ -994,18 +948,13 @@ final class DifferentialRevisionQuery
|
|||
if ($this->needReviewerAuthority && $viewer_phid) {
|
||||
$authority = $this->loadReviewerAuthority(
|
||||
$revisions,
|
||||
$edges,
|
||||
$reviewer_map,
|
||||
$allow_self);
|
||||
}
|
||||
|
||||
foreach ($revisions as $revision) {
|
||||
$revision_edges = $edges[$revision->getPHID()][$edge_type];
|
||||
$reviewers = array();
|
||||
foreach ($revision_edges as $reviewer_phid => $edge) {
|
||||
$reviewer = new DifferentialReviewerProxy(
|
||||
$reviewer_phid,
|
||||
$edge['data']);
|
||||
|
||||
$reviewers = idx($reviewer_map, $revision->getPHID(), array());
|
||||
foreach ($reviewers as $reviewer_phid => $reviewer) {
|
||||
if ($this->needReviewerAuthority) {
|
||||
if (!$viewer_phid) {
|
||||
// Logged-out users never have authority.
|
||||
|
@ -1025,13 +974,13 @@ final class DifferentialRevisionQuery
|
|||
$reviewers[$reviewer_phid] = $reviewer;
|
||||
}
|
||||
|
||||
$revision->attachReviewerStatus($reviewers);
|
||||
$revision->attachReviewers($reviewers);
|
||||
}
|
||||
}
|
||||
|
||||
private function loadReviewerAuthority(
|
||||
array $revisions,
|
||||
array $edges,
|
||||
array $reviewers,
|
||||
$allow_self) {
|
||||
|
||||
$revision_map = mpull($revisions, null, 'getPHID');
|
||||
|
@ -1044,10 +993,9 @@ final class DifferentialRevisionQuery
|
|||
$project_type = PhabricatorProjectProjectPHIDType::TYPECONST;
|
||||
$package_type = PhabricatorOwnersPackagePHIDType::TYPECONST;
|
||||
|
||||
$edge_type = DifferentialRevisionHasReviewerEdgeType::EDGECONST;
|
||||
foreach ($edges as $src => $types) {
|
||||
foreach ($reviewers as $revision_phid => $reviewer_list) {
|
||||
if (!$allow_self) {
|
||||
if ($revision_map[$src]->getAuthorPHID() == $viewer_phid) {
|
||||
if ($revision_map[$revision_phid]->getAuthorPHID() == $viewer_phid) {
|
||||
// If self-review isn't permitted, the user will never have
|
||||
// authority over projects on revisions they authored because you
|
||||
// can't accept your own revisions, so we don't need to load any
|
||||
|
@ -1055,14 +1003,14 @@ final class DifferentialRevisionQuery
|
|||
continue;
|
||||
}
|
||||
}
|
||||
$edge_data = idx($types, $edge_type, array());
|
||||
foreach ($edge_data as $dst => $data) {
|
||||
$phid_type = phid_get_type($dst);
|
||||
|
||||
foreach ($reviewer_list as $reviewer_phid => $reviewer) {
|
||||
$phid_type = phid_get_type($reviewer_phid);
|
||||
if ($phid_type == $project_type) {
|
||||
$project_phids[] = $dst;
|
||||
$project_phids[] = $reviewer_phid;
|
||||
}
|
||||
if ($phid_type == $package_type) {
|
||||
$package_phids[] = $dst;
|
||||
$package_phids[] = $reviewer_phid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,14 @@ final class DifferentialRevisionRequiredActionResultBucket
|
|||
}
|
||||
$phids = array_fuse($phids);
|
||||
|
||||
// Before continuing, throw away any revisions which responsible users
|
||||
// have explicitly resigned from.
|
||||
|
||||
// The goal is to allow users to resign from revisions they don't want to
|
||||
// review to get these revisions off their dashboard, even if there are
|
||||
// other project or package reviewers which they have authority over.
|
||||
$this->filterResigned($phids);
|
||||
|
||||
$groups = array();
|
||||
|
||||
$groups[] = $this->newGroup()
|
||||
|
@ -229,4 +237,25 @@ final class DifferentialRevisionRequiredActionResultBucket
|
|||
return $results;
|
||||
}
|
||||
|
||||
private function filterResigned(array $phids) {
|
||||
$resigned = array(
|
||||
DifferentialReviewerStatus::STATUS_RESIGNED,
|
||||
);
|
||||
$resigned = array_fuse($resigned);
|
||||
|
||||
$objects = $this->getRevisionsNotAuthored($this->objects, $phids);
|
||||
|
||||
$results = array();
|
||||
foreach ($objects as $key => $object) {
|
||||
if (!$this->hasReviewersWithStatus($object, $phids, $resigned)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$results[$key] = $object;
|
||||
unset($this->objects[$key]);
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -56,13 +56,13 @@ abstract class DifferentialRevisionResultBucket
|
|||
array $phids,
|
||||
array $statuses) {
|
||||
|
||||
foreach ($revision->getReviewerStatus() as $reviewer) {
|
||||
foreach ($revision->getReviewers() as $reviewer) {
|
||||
$reviewer_phid = $reviewer->getReviewerPHID();
|
||||
if (empty($phids[$reviewer_phid])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$status = $reviewer->getStatus();
|
||||
$status = $reviewer->getReviewerStatus();
|
||||
if (empty($statuses[$status])) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -19,8 +19,7 @@ final class DifferentialRevisionSearchEngine
|
|||
return id(new DifferentialRevisionQuery())
|
||||
->needFlags(true)
|
||||
->needDrafts(true)
|
||||
->needRelationships(true)
|
||||
->needReviewerStatus(true);
|
||||
->needReviewers(true);
|
||||
}
|
||||
|
||||
protected function buildQueryFromParameters(array $map) {
|
||||
|
@ -163,10 +162,13 @@ final class DifferentialRevisionSearchEngine
|
|||
$groups = $bucket->newResultGroups($query, $revisions);
|
||||
|
||||
foreach ($groups as $group) {
|
||||
$views[] = id(clone $template)
|
||||
->setHeader($group->getName())
|
||||
->setNoDataString($group->getNoDataString())
|
||||
->setRevisions($group->getObjects());
|
||||
// Don't show groups in Dashboard Panels
|
||||
if ($group->getObjects() || !$this->isPanelContext()) {
|
||||
$views[] = id(clone $template)
|
||||
->setHeader($group->getName())
|
||||
->setNoDataString($group->getNoDataString())
|
||||
->setRevisions($group->getObjects());
|
||||
}
|
||||
}
|
||||
} catch (Exception $ex) {
|
||||
$this->addError($ex->getMessage());
|
||||
|
@ -177,6 +179,12 @@ final class DifferentialRevisionSearchEngine
|
|||
->setHandles(array());
|
||||
}
|
||||
|
||||
if (!$views) {
|
||||
$views[] = id(new DifferentialRevisionListView())
|
||||
->setUser($viewer)
|
||||
->setNoDataString(pht('No revisions found.'));
|
||||
}
|
||||
|
||||
$phids = array_mergev(mpull($views, 'getRequiredHandlePHIDs'));
|
||||
if ($phids) {
|
||||
$handles = id(new PhabricatorHandleQuery())
|
||||
|
|
|
@ -10,11 +10,11 @@ final class DifferentialRevisionFulltextEngine
|
|||
$revision = id(new DifferentialRevisionQuery())
|
||||
->setViewer($this->getViewer())
|
||||
->withPHIDs(array($object->getPHID()))
|
||||
->needReviewerStatus(true)
|
||||
->needReviewers(true)
|
||||
->executeOne();
|
||||
|
||||
// TODO: This isn't very clean, but custom fields currently rely on it.
|
||||
$object->attachReviewerStatus($revision->getReviewerStatus());
|
||||
$object->attachReviewers($revision->getReviewers());
|
||||
|
||||
$document->setDocumentTitle($revision->getTitle());
|
||||
|
||||
|
@ -36,8 +36,9 @@ final class DifferentialRevisionFulltextEngine
|
|||
// owner is the author (e.g., accepted, rejected, closed).
|
||||
$status_review = ArcanistDifferentialRevisionStatus::NEEDS_REVIEW;
|
||||
if ($revision->getStatus() == $status_review) {
|
||||
$reviewers = $revision->getReviewerStatus();
|
||||
$reviewers = mpull($reviewers, 'getReviewerPHID', 'getReviewerPHID');
|
||||
$reviewers = $revision->getReviewerPHIDs();
|
||||
$reviewers = array_fuse($reviewers);
|
||||
|
||||
if ($reviewers) {
|
||||
foreach ($reviewers as $phid) {
|
||||
$document->addRelationship(
|
||||
|
|
|
@ -6,19 +6,81 @@ final class DifferentialReviewer
|
|||
protected $revisionPHID;
|
||||
protected $reviewerPHID;
|
||||
protected $reviewerStatus;
|
||||
protected $lastActionDiffPHID;
|
||||
protected $lastCommentDiffPHID;
|
||||
protected $lastActorPHID;
|
||||
|
||||
private $authority = array();
|
||||
|
||||
protected function getConfiguration() {
|
||||
return array(
|
||||
self::CONFIG_COLUMN_SCHEMA => array(
|
||||
'reviewerStatus' => 'text64',
|
||||
'lastActionDiffPHID' => 'phid?',
|
||||
'lastCommentDiffPHID' => 'phid?',
|
||||
'lastActorPHID' => 'phid?',
|
||||
),
|
||||
self::CONFIG_KEY_SCHEMA => array(
|
||||
'key_revision' => array(
|
||||
'columns' => array('revisionPHID', 'reviewerPHID'),
|
||||
'unique' => true,
|
||||
),
|
||||
'key_reviewer' => array(
|
||||
'columns' => array('reviewerPHID', 'revisionPHID'),
|
||||
),
|
||||
),
|
||||
) + parent::getConfiguration();
|
||||
}
|
||||
|
||||
public function isUser() {
|
||||
$user_type = PhabricatorPeopleUserPHIDType::TYPECONST;
|
||||
return (phid_get_type($this->getReviewerPHID()) == $user_type);
|
||||
}
|
||||
|
||||
public function attachAuthority(PhabricatorUser $user, $has_authority) {
|
||||
$this->authority[$user->getCacheFragment()] = $has_authority;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hasAuthority(PhabricatorUser $viewer) {
|
||||
$cache_fragment = $viewer->getCacheFragment();
|
||||
return $this->assertAttachedKey($this->authority, $cache_fragment);
|
||||
}
|
||||
|
||||
public function isResigned() {
|
||||
$status_resigned = DifferentialReviewerStatus::STATUS_RESIGNED;
|
||||
return ($this->getReviewerStatus() == $status_resigned);
|
||||
}
|
||||
|
||||
public function isAccepted($diff_phid) {
|
||||
$status_accepted = DifferentialReviewerStatus::STATUS_ACCEPTED;
|
||||
|
||||
if ($this->getReviewerStatus() != $status_accepted) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$diff_phid) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$action_phid = $this->getLastActionDiffPHID();
|
||||
|
||||
if (!$action_phid) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($action_phid == $diff_phid) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$sticky_key = 'differential.sticky-accept';
|
||||
$is_sticky = PhabricatorEnv::getEnvConfig($sticky_key);
|
||||
|
||||
if ($is_sticky) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class DifferentialReviewerProxy extends Phobject {
|
||||
|
||||
private $reviewerPHID;
|
||||
private $status;
|
||||
private $diffID;
|
||||
private $authority = array();
|
||||
|
||||
public function __construct($reviewer_phid, array $edge_data) {
|
||||
$this->reviewerPHID = $reviewer_phid;
|
||||
$this->status = idx($edge_data, 'status');
|
||||
$this->diffID = idx($edge_data, 'diff');
|
||||
}
|
||||
|
||||
public function getReviewerPHID() {
|
||||
return $this->reviewerPHID;
|
||||
}
|
||||
|
||||
public function getStatus() {
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
public function getDiffID() {
|
||||
return $this->diffID;
|
||||
}
|
||||
|
||||
public function isUser() {
|
||||
$user_type = PhabricatorPeopleUserPHIDType::TYPECONST;
|
||||
return (phid_get_type($this->getReviewerPHID()) == $user_type);
|
||||
}
|
||||
|
||||
public function attachAuthority(PhabricatorUser $user, $has_authority) {
|
||||
$this->authority[$user->getPHID()] = $has_authority;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hasAuthority(PhabricatorUser $viewer) {
|
||||
// It would be nice to use assertAttachedKey() here, but we don't extend
|
||||
// PhabricatorLiskDAO, and faking that seems sketchy.
|
||||
|
||||
$viewer_phid = $viewer->getPHID();
|
||||
if (!array_key_exists($viewer_phid, $this->authority)) {
|
||||
throw new Exception(pht('You must %s first!', 'attachAuthority()'));
|
||||
}
|
||||
return $this->authority[$viewer_phid];
|
||||
}
|
||||
|
||||
public function getEdgeData() {
|
||||
return array(
|
||||
'status' => $this->status,
|
||||
'diffID' => $this->diffID,
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -38,7 +38,6 @@ final class DifferentialRevision extends DifferentialDAO
|
|||
protected $editPolicy = PhabricatorPolicies::POLICY_USER;
|
||||
protected $properties = array();
|
||||
|
||||
private $relationships = self::ATTACHABLE;
|
||||
private $commits = self::ATTACHABLE;
|
||||
private $activeDiff = self::ATTACHABLE;
|
||||
private $diffIDs = self::ATTACHABLE;
|
||||
|
@ -69,10 +68,9 @@ final class DifferentialRevision extends DifferentialDAO
|
|||
return id(new DifferentialRevision())
|
||||
->setViewPolicy($view_policy)
|
||||
->setAuthorPHID($actor->getPHID())
|
||||
->attachRelationships(array())
|
||||
->attachRepository(null)
|
||||
->attachActiveDiff(null)
|
||||
->attachReviewerStatus(array())
|
||||
->attachReviewers(array())
|
||||
->setStatus(ArcanistDifferentialRevisionStatus::NEEDS_REVIEW);
|
||||
}
|
||||
|
||||
|
@ -238,73 +236,6 @@ final class DifferentialRevision extends DifferentialDAO
|
|||
return parent::save();
|
||||
}
|
||||
|
||||
public function loadRelationships() {
|
||||
if (!$this->getID()) {
|
||||
$this->relationships = array();
|
||||
return;
|
||||
}
|
||||
|
||||
$data = array();
|
||||
|
||||
$subscriber_phids = PhabricatorEdgeQuery::loadDestinationPHIDs(
|
||||
$this->getPHID(),
|
||||
PhabricatorObjectHasSubscriberEdgeType::EDGECONST);
|
||||
$subscriber_phids = array_reverse($subscriber_phids);
|
||||
foreach ($subscriber_phids as $phid) {
|
||||
$data[] = array(
|
||||
'relation' => self::RELATION_SUBSCRIBED,
|
||||
'objectPHID' => $phid,
|
||||
'reasonPHID' => null,
|
||||
);
|
||||
}
|
||||
|
||||
$reviewer_phids = PhabricatorEdgeQuery::loadDestinationPHIDs(
|
||||
$this->getPHID(),
|
||||
DifferentialRevisionHasReviewerEdgeType::EDGECONST);
|
||||
$reviewer_phids = array_reverse($reviewer_phids);
|
||||
foreach ($reviewer_phids as $phid) {
|
||||
$data[] = array(
|
||||
'relation' => self::RELATION_REVIEWER,
|
||||
'objectPHID' => $phid,
|
||||
'reasonPHID' => null,
|
||||
);
|
||||
}
|
||||
|
||||
return $this->attachRelationships($data);
|
||||
}
|
||||
|
||||
public function attachRelationships(array $relationships) {
|
||||
$this->relationships = igroup($relationships, 'relation');
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getReviewers() {
|
||||
return $this->getRelatedPHIDs(self::RELATION_REVIEWER);
|
||||
}
|
||||
|
||||
public function getCCPHIDs() {
|
||||
return $this->getRelatedPHIDs(self::RELATION_SUBSCRIBED);
|
||||
}
|
||||
|
||||
private function getRelatedPHIDs($relation) {
|
||||
$this->assertAttached($this->relationships);
|
||||
|
||||
return ipull($this->getRawRelations($relation), 'objectPHID');
|
||||
}
|
||||
|
||||
public function getRawRelations($relation) {
|
||||
return idx($this->relationships, $relation, array());
|
||||
}
|
||||
|
||||
public function getPrimaryReviewer() {
|
||||
$reviewers = $this->getReviewers();
|
||||
$last = $this->lastReviewerPHID;
|
||||
if (!$last || !in_array($last, $reviewers)) {
|
||||
return head($this->getReviewers());
|
||||
}
|
||||
return $last;
|
||||
}
|
||||
|
||||
public function getHashes() {
|
||||
return $this->assertAttached($this->hashes);
|
||||
}
|
||||
|
@ -401,26 +332,31 @@ final class DifferentialRevision extends DifferentialDAO
|
|||
);
|
||||
}
|
||||
|
||||
public function getReviewerStatus() {
|
||||
public function getReviewers() {
|
||||
return $this->assertAttached($this->reviewerStatus);
|
||||
}
|
||||
|
||||
public function attachReviewerStatus(array $reviewers) {
|
||||
assert_instances_of($reviewers, 'DifferentialReviewerProxy');
|
||||
|
||||
public function attachReviewers(array $reviewers) {
|
||||
assert_instances_of($reviewers, 'DifferentialReviewer');
|
||||
$reviewers = mpull($reviewers, null, 'getReviewerPHID');
|
||||
$this->reviewerStatus = $reviewers;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getReviewerPHIDs() {
|
||||
$reviewers = $this->getReviewers();
|
||||
return mpull($reviewers, 'getReviewerPHID');
|
||||
}
|
||||
|
||||
public function getReviewerPHIDsForEdit() {
|
||||
$reviewers = $this->getReviewerStatus();
|
||||
$reviewers = $this->getReviewers();
|
||||
|
||||
$status_blocking = DifferentialReviewerStatus::STATUS_BLOCKING;
|
||||
|
||||
$value = array();
|
||||
foreach ($reviewers as $reviewer) {
|
||||
$phid = $reviewer->getReviewerPHID();
|
||||
if ($reviewer->getStatus() == $status_blocking) {
|
||||
if ($reviewer->getReviewerStatus() == $status_blocking) {
|
||||
$value[] = 'blocking('.$phid.')';
|
||||
} else {
|
||||
$value[] = $phid;
|
||||
|
@ -543,11 +479,11 @@ final class DifferentialRevision extends DifferentialDAO
|
|||
$reviewers = id(new DifferentialRevisionQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withPHIDs(array($this->getPHID()))
|
||||
->needReviewerStatus(true)
|
||||
->needReviewers(true)
|
||||
->executeOne()
|
||||
->getReviewerStatus();
|
||||
->getReviewers();
|
||||
} else {
|
||||
$reviewers = $this->getReviewerStatus();
|
||||
$reviewers = $this->getReviewers();
|
||||
}
|
||||
|
||||
foreach ($reviewers as $reviewer) {
|
||||
|
|
|
@ -212,13 +212,6 @@ final class DifferentialTransaction
|
|||
$tags[] = self::MAILTAG_UPDATED;
|
||||
}
|
||||
break;
|
||||
case PhabricatorTransactions::TYPE_EDGE:
|
||||
switch ($this->getMetadataValue('edge:type')) {
|
||||
case DifferentialRevisionHasReviewerEdgeType::EDGECONST:
|
||||
$tags[] = self::MAILTAG_REVIEWERS;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case PhabricatorTransactions::TYPE_COMMENT:
|
||||
case self::TYPE_INLINE:
|
||||
$tags[] = self::MAILTAG_COMMENT;
|
||||
|
@ -598,14 +591,6 @@ final class DifferentialTransaction
|
|||
|
||||
public function getNoEffectDescription() {
|
||||
switch ($this->getTransactionType()) {
|
||||
case PhabricatorTransactions::TYPE_EDGE:
|
||||
switch ($this->getMetadataValue('edge:type')) {
|
||||
case DifferentialRevisionHasReviewerEdgeType::EDGECONST:
|
||||
return pht(
|
||||
'The reviewers you are trying to add are already reviewing '.
|
||||
'this revision.');
|
||||
}
|
||||
break;
|
||||
case self::TYPE_ACTION:
|
||||
switch ($this->getNewValue()) {
|
||||
case DifferentialAction::ACTION_CLOSE:
|
||||
|
@ -624,18 +609,10 @@ final class DifferentialTransaction
|
|||
return pht('This revision already requires changes.');
|
||||
case DifferentialAction::ACTION_REQUEST:
|
||||
return pht('Review is already requested for this revision.');
|
||||
case DifferentialAction::ACTION_RESIGN:
|
||||
return pht(
|
||||
'You can not resign from this revision because you are not '.
|
||||
'a reviewer.');
|
||||
case DifferentialAction::ACTION_CLAIM:
|
||||
return pht(
|
||||
'You can not commandeer this revision because you already own '.
|
||||
'it.');
|
||||
case DifferentialAction::ACTION_ACCEPT:
|
||||
return pht('You have already accepted this revision.');
|
||||
case DifferentialAction::ACTION_REJECT:
|
||||
return pht('You have already requested changes to this revision.');
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ final class DifferentialReviewersView extends AphrontView {
|
|||
private $diff;
|
||||
|
||||
public function setReviewers(array $reviewers) {
|
||||
assert_instances_of($reviewers, 'DifferentialReviewerProxy');
|
||||
assert_instances_of($reviewers, 'DifferentialReviewer');
|
||||
$this->reviewers = $reviewers;
|
||||
return $this;
|
||||
}
|
||||
|
@ -25,53 +25,74 @@ final class DifferentialReviewersView extends AphrontView {
|
|||
|
||||
public function render() {
|
||||
$viewer = $this->getUser();
|
||||
$reviewers = $this->reviewers;
|
||||
|
||||
$view = new PHUIStatusListView();
|
||||
foreach ($this->reviewers as $reviewer) {
|
||||
|
||||
// Move resigned reviewers to the bottom.
|
||||
$head = array();
|
||||
$tail = array();
|
||||
foreach ($reviewers as $key => $reviewer) {
|
||||
if ($reviewer->isResigned()) {
|
||||
$tail[$key] = $reviewer;
|
||||
} else {
|
||||
$head[$key] = $reviewer;
|
||||
}
|
||||
}
|
||||
|
||||
$reviewers = $head + $tail;
|
||||
foreach ($reviewers as $reviewer) {
|
||||
$phid = $reviewer->getReviewerPHID();
|
||||
$handle = $this->handles[$phid];
|
||||
|
||||
// If we're missing either the diff or action information for the
|
||||
// reviewer, render information as current.
|
||||
$is_current = (!$this->diff) ||
|
||||
(!$reviewer->getDiffID()) ||
|
||||
($this->diff->getID() == $reviewer->getDiffID());
|
||||
$action_phid = $reviewer->getLastActionDiffPHID();
|
||||
$is_current_action = $this->isCurrent($action_phid);
|
||||
|
||||
$comment_phid = $reviewer->getLastCommentDiffPHID();
|
||||
$is_current_comment = $this->isCurrent($comment_phid);
|
||||
|
||||
$item = new PHUIStatusItemView();
|
||||
|
||||
$item->setHighlighted($reviewer->hasAuthority($viewer));
|
||||
|
||||
switch ($reviewer->getStatus()) {
|
||||
switch ($reviewer->getReviewerStatus()) {
|
||||
case DifferentialReviewerStatus::STATUS_ADDED:
|
||||
$item->setIcon(
|
||||
PHUIStatusItemView::ICON_OPEN,
|
||||
'bluegrey',
|
||||
pht('Review Requested'));
|
||||
if ($comment_phid) {
|
||||
if ($is_current_comment) {
|
||||
$item->setIcon(
|
||||
'fa-comment',
|
||||
'blue',
|
||||
pht('Commented'));
|
||||
} else {
|
||||
$item->setIcon(
|
||||
'fa-comment-o',
|
||||
'bluegrey',
|
||||
pht('Commented Previously'));
|
||||
}
|
||||
} else {
|
||||
$item->setIcon(
|
||||
PHUIStatusItemView::ICON_OPEN,
|
||||
'bluegrey',
|
||||
pht('Review Requested'));
|
||||
}
|
||||
break;
|
||||
|
||||
case DifferentialReviewerStatus::STATUS_ACCEPTED:
|
||||
if ($is_current) {
|
||||
if ($is_current_action) {
|
||||
$item->setIcon(
|
||||
PHUIStatusItemView::ICON_ACCEPT,
|
||||
'green',
|
||||
pht('Accepted'));
|
||||
} else {
|
||||
$item->setIcon(
|
||||
PHUIStatusItemView::ICON_ACCEPT,
|
||||
'fa-check-circle-o',
|
||||
'bluegrey',
|
||||
pht('Accepted Prior Diff'));
|
||||
}
|
||||
break;
|
||||
|
||||
case DifferentialReviewerStatus::STATUS_ACCEPTED_OLDER:
|
||||
$item->setIcon(
|
||||
'fa-check-circle-o',
|
||||
'bluegrey',
|
||||
pht('Accepted Prior Diff'));
|
||||
break;
|
||||
|
||||
case DifferentialReviewerStatus::STATUS_REJECTED:
|
||||
if ($is_current) {
|
||||
if ($is_current_action) {
|
||||
$item->setIcon(
|
||||
PHUIStatusItemView::ICON_REJECT,
|
||||
'red',
|
||||
|
@ -84,27 +105,6 @@ final class DifferentialReviewersView extends AphrontView {
|
|||
}
|
||||
break;
|
||||
|
||||
case DifferentialReviewerStatus::STATUS_REJECTED_OLDER:
|
||||
$item->setIcon(
|
||||
'fa-times-circle-o',
|
||||
'bluegrey',
|
||||
pht('Rejected Prior Diff'));
|
||||
break;
|
||||
|
||||
case DifferentialReviewerStatus::STATUS_COMMENTED:
|
||||
if ($is_current) {
|
||||
$item->setIcon(
|
||||
'fa-question-circle',
|
||||
'blue',
|
||||
pht('Commented'));
|
||||
} else {
|
||||
$item->setIcon(
|
||||
'fa-question-circle-o',
|
||||
'bluegrey',
|
||||
pht('Commented Previously'));
|
||||
}
|
||||
break;
|
||||
|
||||
case DifferentialReviewerStatus::STATUS_BLOCKING:
|
||||
$item->setIcon(
|
||||
PHUIStatusItemView::ICON_MINUS,
|
||||
|
@ -112,11 +112,18 @@ final class DifferentialReviewersView extends AphrontView {
|
|||
pht('Blocking Review'));
|
||||
break;
|
||||
|
||||
case DifferentialReviewerStatus::STATUS_RESIGNED:
|
||||
$item->setIcon(
|
||||
'fa-times',
|
||||
'grey',
|
||||
pht('Resigned'));
|
||||
break;
|
||||
|
||||
default:
|
||||
$item->setIcon(
|
||||
PHUIStatusItemView::ICON_QUESTION,
|
||||
'bluegrey',
|
||||
pht('%s?', $reviewer->getStatus()));
|
||||
pht('%s?', $reviewer->getReviewerStatus()));
|
||||
break;
|
||||
|
||||
}
|
||||
|
@ -128,4 +135,26 @@ final class DifferentialReviewersView extends AphrontView {
|
|||
return $view;
|
||||
}
|
||||
|
||||
private function isCurrent($action_phid) {
|
||||
if (!$this->diff) {
|
||||
echo "A\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!$action_phid) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$diff_phid = $this->diff->getPHID();
|
||||
if (!$diff_phid) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($diff_phid == $action_phid) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -52,10 +52,7 @@ final class DifferentialRevisionListView extends AphrontView {
|
|||
$phids = array();
|
||||
foreach ($this->revisions as $revision) {
|
||||
$phids[] = array($revision->getAuthorPHID());
|
||||
|
||||
// TODO: Switch to getReviewerStatus(), but not all callers pass us
|
||||
// revisions with this data loaded.
|
||||
$phids[] = $revision->getReviewers();
|
||||
$phids[] = $revision->getReviewerPHIDs();
|
||||
}
|
||||
return array_mergev($phids);
|
||||
}
|
||||
|
@ -132,8 +129,7 @@ final class DifferentialRevisionListView extends AphrontView {
|
|||
}
|
||||
|
||||
$reviewers = array();
|
||||
// TODO: As above, this should be based on `getReviewerStatus()`.
|
||||
foreach ($revision->getReviewers() as $reviewer) {
|
||||
foreach ($revision->getReviewerPHIDs() as $reviewer) {
|
||||
$reviewers[] = $this->handles[$reviewer]->renderLink();
|
||||
}
|
||||
if (!$reviewers) {
|
||||
|
|
|
@ -48,6 +48,72 @@ final class DifferentialRevisionAcceptTransaction
|
|||
return pht('Accept a revision.');
|
||||
}
|
||||
|
||||
protected function getActionOptions(
|
||||
PhabricatorUser $viewer,
|
||||
DifferentialRevision $revision) {
|
||||
|
||||
$reviewers = $revision->getReviewers();
|
||||
|
||||
$options = array();
|
||||
$value = array();
|
||||
|
||||
// Put the viewer's user reviewer first, if it exists, so that "Accept as
|
||||
// yourself" is always at the top.
|
||||
$head = array();
|
||||
$tail = array();
|
||||
foreach ($reviewers as $key => $reviewer) {
|
||||
if ($reviewer->isUser()) {
|
||||
$head[$key] = $reviewer;
|
||||
} else {
|
||||
$tail[$key] = $reviewer;
|
||||
}
|
||||
}
|
||||
$reviewers = $head + $tail;
|
||||
|
||||
$diff_phid = $this->getActiveDiffPHID($revision);
|
||||
$reviewer_phids = array();
|
||||
|
||||
// If the viewer isn't a reviewer, add them to the list of options first.
|
||||
// This happens when you navigate to some revision you aren't involved in:
|
||||
// you can accept and become a reviewer.
|
||||
|
||||
$viewer_phid = $viewer->getPHID();
|
||||
if ($viewer_phid) {
|
||||
if (!isset($reviewers[$viewer_phid])) {
|
||||
$reviewer_phids[$viewer_phid] = $viewer_phid;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($reviewers as $reviewer) {
|
||||
if (!$reviewer->hasAuthority($viewer)) {
|
||||
// If the viewer doesn't have authority to act on behalf of a reviewer,
|
||||
// don't include that reviewer as an option.
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($reviewer->isAccepted($diff_phid)) {
|
||||
// If a reviewer is already in a full "accepted" state, don't
|
||||
// include that reviewer as an option.
|
||||
continue;
|
||||
}
|
||||
|
||||
$reviewer_phid = $reviewer->getReviewerPHID();
|
||||
$reviewer_phids[$reviewer_phid] = $reviewer_phid;
|
||||
}
|
||||
|
||||
$handles = $viewer->loadHandles($reviewer_phids);
|
||||
|
||||
foreach ($reviewer_phids as $reviewer_phid) {
|
||||
$options[$reviewer_phid] = pht(
|
||||
'Accept as %s',
|
||||
$viewer->renderHandle($reviewer_phid));
|
||||
|
||||
$value[] = $reviewer_phid;
|
||||
}
|
||||
|
||||
return array($options, $value);
|
||||
}
|
||||
|
||||
public function generateOldValue($object) {
|
||||
$actor = $this->getActor();
|
||||
return $this->isViewerFullyAccepted($object, $actor);
|
||||
|
@ -87,10 +153,39 @@ final class DifferentialRevisionAcceptTransaction
|
|||
}
|
||||
}
|
||||
|
||||
protected function validateOptionValue($object, $actor, array $value) {
|
||||
if (!$value) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'When accepting a revision, you must accept on behalf of at '.
|
||||
'least one reviewer.'));
|
||||
}
|
||||
|
||||
list($options) = $this->getActionOptions($actor, $object);
|
||||
foreach ($value as $phid) {
|
||||
if (!isset($options[$phid])) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Reviewer "%s" is not a valid reviewer which you have authority '.
|
||||
'to accept on behalf of.',
|
||||
$phid));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getTitle() {
|
||||
return pht(
|
||||
'%s accepted this revision.',
|
||||
$this->renderAuthor());
|
||||
$new = $this->getNewValue();
|
||||
if (is_array($new) && $new) {
|
||||
return pht(
|
||||
'%s accepted this revision as %s reviewer(s): %s.',
|
||||
$this->renderAuthor(),
|
||||
phutil_count($new),
|
||||
$this->renderHandleList($new));
|
||||
} else {
|
||||
return pht(
|
||||
'%s accepted this revision.',
|
||||
$this->renderAuthor());
|
||||
}
|
||||
}
|
||||
|
||||
public function getTitleForFeed() {
|
||||
|
|
|
@ -19,6 +19,10 @@ abstract class DifferentialRevisionActionTransaction
|
|||
abstract protected function validateAction($object, PhabricatorUser $viewer);
|
||||
abstract protected function getRevisionActionLabel();
|
||||
|
||||
protected function validateOptionValue($object, $actor, array $value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getCommandKeyword() {
|
||||
return null;
|
||||
}
|
||||
|
@ -70,6 +74,15 @@ abstract class DifferentialRevisionActionTransaction
|
|||
return ($viewer->getPHID() === $revision->getAuthorPHID());
|
||||
}
|
||||
|
||||
protected function getActionOptions(
|
||||
PhabricatorUser $viewer,
|
||||
DifferentialRevision $revision) {
|
||||
return array(
|
||||
array(),
|
||||
null,
|
||||
);
|
||||
}
|
||||
|
||||
public function newEditField(
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $viewer) {
|
||||
|
@ -107,6 +120,12 @@ abstract class DifferentialRevisionActionTransaction
|
|||
// It's not clear that these combinations are actually useful, so just
|
||||
// keep things simple for now.
|
||||
$field->setActionConflictKey('revision.action');
|
||||
|
||||
list($options, $value) = $this->getActionOptions($viewer, $revision);
|
||||
if (count($options) > 1) {
|
||||
$field->setOptions($options);
|
||||
$field->setValue($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -129,6 +148,20 @@ abstract class DifferentialRevisionActionTransaction
|
|||
$errors[] = $this->newInvalidError(
|
||||
$action_exception->getMessage(),
|
||||
$xaction);
|
||||
continue;
|
||||
}
|
||||
|
||||
$new = $xaction->getNewValue();
|
||||
if (!is_array($new)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->validateOptionValue($object, $actor, $new);
|
||||
} catch (Exception $ex) {
|
||||
$errors[] = $this->newInvalidError(
|
||||
$ex->getMessage(),
|
||||
$xaction);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,9 @@ final class DifferentialRevisionResignTransaction
|
|||
|
||||
public function generateOldValue($object) {
|
||||
$actor = $this->getActor();
|
||||
return !$this->isViewerAnyReviewer($object, $actor);
|
||||
$resigned = DifferentialReviewerStatus::STATUS_RESIGNED;
|
||||
|
||||
return ($this->getViewerReviewerStatus($object, $actor) == $resigned);
|
||||
}
|
||||
|
||||
public function applyExternalEffects($object, $value) {
|
||||
|
@ -61,12 +63,19 @@ final class DifferentialRevisionResignTransaction
|
|||
'been closed. You can only resign from open revisions.'));
|
||||
}
|
||||
|
||||
if (!$this->isViewerAnyReviewer($object, $viewer)) {
|
||||
$resigned = DifferentialReviewerStatus::STATUS_RESIGNED;
|
||||
if ($this->getViewerReviewerStatus($object, $viewer) == $resigned) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'You can not resign from this revision because you have already '.
|
||||
'resigned.'));
|
||||
}
|
||||
|
||||
if (!$this->isViewerAnyAuthority($object, $viewer)) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'You can not resign from this revision because you are not a '.
|
||||
'reviewer. You can only resign from revisions where you are a '.
|
||||
'reviewer.'));
|
||||
'reviewer, and do not have authority over any reviewer.'));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,12 +7,46 @@ abstract class DifferentialRevisionReviewTransaction
|
|||
return DifferentialRevisionEditEngine::ACTIONGROUP_REVIEW;
|
||||
}
|
||||
|
||||
public function generateNewValue($object, $value) {
|
||||
if (!is_array($value)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the list of options is the same as the default list, just treat this
|
||||
// as a "take the default action" transaction.
|
||||
$viewer = $this->getActor();
|
||||
list($options, $default) = $this->getActionOptions($viewer, $object);
|
||||
|
||||
sort($default);
|
||||
sort($value);
|
||||
|
||||
if ($default === $value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
protected function isViewerAnyReviewer(
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $viewer) {
|
||||
return ($this->getViewerReviewerStatus($revision, $viewer) !== null);
|
||||
}
|
||||
|
||||
protected function isViewerAnyAuthority(
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $viewer) {
|
||||
|
||||
$reviewers = $revision->getReviewers();
|
||||
foreach ($revision->getReviewers() as $reviewer) {
|
||||
if ($reviewer->hasAuthority($viewer)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function isViewerFullyAccepted(
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $viewer) {
|
||||
|
@ -21,7 +55,8 @@ abstract class DifferentialRevisionReviewTransaction
|
|||
$viewer,
|
||||
array(
|
||||
DifferentialReviewerStatus::STATUS_ACCEPTED,
|
||||
));
|
||||
),
|
||||
true);
|
||||
}
|
||||
|
||||
protected function isViewerFullyRejected(
|
||||
|
@ -32,7 +67,8 @@ abstract class DifferentialRevisionReviewTransaction
|
|||
$viewer,
|
||||
array(
|
||||
DifferentialReviewerStatus::STATUS_REJECTED,
|
||||
));
|
||||
),
|
||||
true);
|
||||
}
|
||||
|
||||
protected function getViewerReviewerStatus(
|
||||
|
@ -43,12 +79,12 @@ abstract class DifferentialRevisionReviewTransaction
|
|||
return null;
|
||||
}
|
||||
|
||||
foreach ($revision->getReviewerStatus() as $reviewer) {
|
||||
foreach ($revision->getReviewers() as $reviewer) {
|
||||
if ($reviewer->getReviewerPHID() != $viewer->getPHID()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return $reviewer->getStatus();
|
||||
return $reviewer->getReviewerStatus();
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -57,7 +93,8 @@ abstract class DifferentialRevisionReviewTransaction
|
|||
protected function isViewerReviewerStatusFullyAmong(
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $viewer,
|
||||
array $status_list) {
|
||||
array $status_list,
|
||||
$require_current) {
|
||||
|
||||
// If the user themselves is not a reviewer, the reviews they have
|
||||
// authority over can not all be in any set of states since their own
|
||||
|
@ -67,18 +104,26 @@ abstract class DifferentialRevisionReviewTransaction
|
|||
return false;
|
||||
}
|
||||
|
||||
$active_phid = $this->getActiveDiffPHID($revision);
|
||||
|
||||
// Otherwise, check that all reviews they have authority over are in
|
||||
// the desired set of states.
|
||||
$status_map = array_fuse($status_list);
|
||||
foreach ($revision->getReviewerStatus() as $reviewer) {
|
||||
foreach ($revision->getReviewers() as $reviewer) {
|
||||
if (!$reviewer->hasAuthority($viewer)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$status = $reviewer->getStatus();
|
||||
$status = $reviewer->getReviewerStatus();
|
||||
if (!isset($status_map[$status])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($require_current) {
|
||||
if ($reviewer->getLastActionDiffPHID() != $active_phid) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -97,7 +142,7 @@ abstract class DifferentialRevisionReviewTransaction
|
|||
// yourself.
|
||||
$with_authority = ($status != DifferentialReviewerStatus::STATUS_RESIGNED);
|
||||
if ($with_authority) {
|
||||
foreach ($revision->getReviewerStatus() as $reviewer) {
|
||||
foreach ($revision->getReviewers() as $reviewer) {
|
||||
if ($reviewer->hasAuthority($viewer)) {
|
||||
$map[$reviewer->getReviewerPHID()] = $status;
|
||||
}
|
||||
|
@ -107,6 +152,12 @@ abstract class DifferentialRevisionReviewTransaction
|
|||
// In all cases, you affect yourself.
|
||||
$map[$viewer->getPHID()] = $status;
|
||||
|
||||
// If the user has submitted a specific list of reviewers to act as (by
|
||||
// unchecking some checkboxes under "Accept"), only affect those reviewers.
|
||||
if (is_array($value)) {
|
||||
$map = array_select_keys($map, $value);
|
||||
}
|
||||
|
||||
// Convert reviewer statuses into edge data.
|
||||
foreach ($map as $reviewer_phid => $reviewer_status) {
|
||||
$map[$reviewer_phid] = array(
|
||||
|
@ -138,6 +189,13 @@ abstract class DifferentialRevisionReviewTransaction
|
|||
// Now, do the new write.
|
||||
|
||||
if ($map) {
|
||||
$diff = $this->getEditor()->getActiveDiff($revision);
|
||||
if ($diff) {
|
||||
$diff_phid = $diff->getPHID();
|
||||
} else {
|
||||
$diff_phid = null;
|
||||
}
|
||||
|
||||
$table = new DifferentialReviewer();
|
||||
|
||||
$reviewers = $table->loadAllWhere(
|
||||
|
@ -154,18 +212,21 @@ abstract class DifferentialRevisionReviewTransaction
|
|||
->setReviewerPHID($dst_phid);
|
||||
}
|
||||
|
||||
$old_status = $reviewer->getReviewerStatus();
|
||||
$reviewer->setReviewerStatus($status);
|
||||
|
||||
if ($status == DifferentialReviewerStatus::STATUS_RESIGNED) {
|
||||
if ($reviewer->getID()) {
|
||||
$reviewer->delete();
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
$reviewer->save();
|
||||
} catch (AphrontDuplicateKeyQueryException $ex) {
|
||||
// At least for now, just ignore it if we lost a race.
|
||||
}
|
||||
if ($diff_phid) {
|
||||
$reviewer->setLastActionDiffPHID($diff_phid);
|
||||
}
|
||||
|
||||
if ($old_status !== $status) {
|
||||
$reviewer->setLastActorPHID($this->getActingAsPHID());
|
||||
}
|
||||
|
||||
try {
|
||||
$reviewer->save();
|
||||
} catch (AphrontDuplicateKeyQueryException $ex) {
|
||||
// At least for now, just ignore it if we lost a race.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@ final class DifferentialRevisionReviewersTransaction
|
|||
const EDITKEY = 'reviewers';
|
||||
|
||||
public function generateOldValue($object) {
|
||||
$reviewers = $object->getReviewerStatus();
|
||||
$reviewers = mpull($reviewers, 'getStatus', 'getReviewerPHID');
|
||||
$reviewers = $object->getReviewers();
|
||||
$reviewers = mpull($reviewers, 'getReviewerStatus', 'getReviewerPHID');
|
||||
return $reviewers;
|
||||
}
|
||||
|
||||
|
|
|
@ -57,4 +57,16 @@ abstract class DifferentialRevisionTransactionType
|
|||
$xaction);
|
||||
}
|
||||
|
||||
protected function getActiveDiffPHID(DifferentialRevision $revision) {
|
||||
try {
|
||||
$diff = $revision->getActiveDiff();
|
||||
if (!$diff) {
|
||||
return null;
|
||||
}
|
||||
return $diff->getPHID();
|
||||
} catch (Exception $ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1765,7 +1765,7 @@ final class DiffusionBrowseController extends DiffusionController {
|
|||
->withUpdatedEpochBetween($recent, null)
|
||||
->setOrder(DifferentialRevisionQuery::ORDER_MODIFIED)
|
||||
->setLimit(10)
|
||||
->needRelationships(true)
|
||||
->needReviewers(true)
|
||||
->needFlags(true)
|
||||
->needDrafts(true)
|
||||
->execute();
|
||||
|
|
|
@ -20,7 +20,7 @@ final class DiffusionCommitRevisionReviewersHeraldField
|
|||
return array();
|
||||
}
|
||||
|
||||
return $revision->getReviewers();
|
||||
return $revision->getReviewerPHIDs();
|
||||
}
|
||||
|
||||
protected function getHeraldFieldStandardType() {
|
||||
|
|
|
@ -20,8 +20,8 @@ final class DiffusionPreCommitContentRevisionReviewersHeraldField
|
|||
return array();
|
||||
}
|
||||
|
||||
return $revision->getReviewers();
|
||||
}
|
||||
return $revision->getReviewerPHIDs();
|
||||
}
|
||||
|
||||
protected function getHeraldFieldStandardType() {
|
||||
return self::STANDARD_PHID_LIST;
|
||||
|
|
|
@ -190,8 +190,7 @@ final class HeraldCommitAdapter
|
|||
$revision = id(new DifferentialRevisionQuery())
|
||||
->withIDs(array($revision_id))
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->needRelationships(true)
|
||||
->needReviewerStatus(true)
|
||||
->needReviewers(true)
|
||||
->executeOne();
|
||||
if ($revision) {
|
||||
$this->affectedRevision = $revision;
|
||||
|
|
|
@ -190,7 +190,7 @@ final class HeraldPreCommitContentAdapter extends HeraldPreCommitAdapter {
|
|||
$this->revision = id(new DifferentialRevisionQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withIDs(array($revision_id))
|
||||
->needRelationships(true)
|
||||
->needReviewers(true)
|
||||
->executeOne();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -119,6 +119,7 @@ final class PhabricatorFilesComposeAvatarBuiltinFile
|
|||
foreach ($list as $file) {
|
||||
$map['alphanumeric/'.$file] = $root.$file;
|
||||
}
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
||||
|
@ -138,11 +139,11 @@ final class PhabricatorFilesComposeAvatarBuiltinFile
|
|||
$border_seed = $username.'_border';
|
||||
|
||||
$pack_key =
|
||||
PhabricatorHash::digestToRange($pack_seed, 1, $pack_count);
|
||||
PhabricatorHash::digestToRange($pack_seed, 0, $pack_count - 1);
|
||||
$color_key =
|
||||
PhabricatorHash::digestToRange($color_seed, 1, $color_count);
|
||||
PhabricatorHash::digestToRange($color_seed, 0, $color_count - 1);
|
||||
$border_key =
|
||||
PhabricatorHash::digestToRange($border_seed, 1, $border_count);
|
||||
PhabricatorHash::digestToRange($border_seed, 0, $border_count - 1);
|
||||
|
||||
$pack = $pack_map[$pack_key];
|
||||
$icon = 'alphanumeric/'.$pack.'/'.$file.'.png';
|
||||
|
@ -188,7 +189,7 @@ final class PhabricatorFilesComposeAvatarBuiltinFile
|
|||
->withFollowSymlinks(false)
|
||||
->find();
|
||||
|
||||
return $map;
|
||||
return array_values($map);
|
||||
}
|
||||
|
||||
public static function getBorderMap() {
|
||||
|
|
|
@ -10,13 +10,7 @@ final class PhabricatorPeopleProfileBadgesController
|
|||
$user = id(new PhabricatorPeopleQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($id))
|
||||
->needProfile(true)
|
||||
->needProfileImage(true)
|
||||
->needAvailability(true)
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
))
|
||||
->executeOne();
|
||||
if (!$user) {
|
||||
return new Aphront404Response();
|
||||
|
@ -50,6 +44,7 @@ final class PhabricatorPeopleProfileBadgesController
|
|||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->setLimit(1)
|
||||
->execute();
|
||||
|
||||
$button = id(new PHUIButtonView())
|
||||
|
@ -59,7 +54,7 @@ final class PhabricatorPeopleProfileBadgesController
|
|||
->setWorkflow(true)
|
||||
->setHref('/badges/award/'.$user->getID().'/');
|
||||
|
||||
if (count($badges)) {
|
||||
if ($badges) {
|
||||
$header->addActionLink($button);
|
||||
}
|
||||
|
||||
|
@ -80,47 +75,43 @@ final class PhabricatorPeopleProfileBadgesController
|
|||
|
||||
private function buildBadgesView(PhabricatorUser $user) {
|
||||
$viewer = $this->getViewer();
|
||||
$request = $this->getRequest();
|
||||
|
||||
$awards = id(new PhabricatorBadgesAwardQuery())
|
||||
$pager = id(new AphrontCursorPagerView())
|
||||
->readFromRequest($request);
|
||||
|
||||
$query = id(new PhabricatorBadgesAwardQuery())
|
||||
->setViewer($viewer)
|
||||
->withRecipientPHIDs(array($user->getPHID()))
|
||||
->withBadgeStatuses(array(PhabricatorBadgesBadge::STATUS_ACTIVE))
|
||||
->execute();
|
||||
$awards = mpull($awards, null, 'getBadgePHID');
|
||||
->withBadgeStatuses(array(PhabricatorBadgesBadge::STATUS_ACTIVE));
|
||||
|
||||
$badges = array();
|
||||
foreach ($awards as $award) {
|
||||
$badge = $award->getBadge();
|
||||
$badges[$award->getBadgePHID()] = $badge;
|
||||
}
|
||||
$awards = $query->executeWithCursorPager($pager);
|
||||
|
||||
if (count($badges)) {
|
||||
if ($awards) {
|
||||
$flex = new PHUIBadgeBoxView();
|
||||
foreach ($awards as $award) {
|
||||
$badge = $award->getBadge();
|
||||
|
||||
foreach ($badges as $badge) {
|
||||
if ($badge) {
|
||||
$awarder_info = array();
|
||||
$awarder_info = array();
|
||||
|
||||
$award = idx($awards, $badge->getPHID(), null);
|
||||
$awarder_phid = $award->getAwarderPHID();
|
||||
$awarder_handle = $viewer->renderHandle($awarder_phid);
|
||||
$awarded_date = phabricator_date($award->getDateCreated(), $viewer);
|
||||
$awarder_phid = $award->getAwarderPHID();
|
||||
$awarder_handle = $viewer->renderHandle($awarder_phid);
|
||||
$awarded_date = phabricator_date($award->getDateCreated(), $viewer);
|
||||
|
||||
$awarder_info = pht(
|
||||
'Awarded by %s',
|
||||
$awarder_handle->render());
|
||||
$awarder_info = pht(
|
||||
'Awarded by %s',
|
||||
$awarder_handle->render());
|
||||
|
||||
$item = id(new PHUIBadgeView())
|
||||
->setIcon($badge->getIcon())
|
||||
->setHeader($badge->getName())
|
||||
->setSubhead($badge->getFlavor())
|
||||
->setQuality($badge->getQuality())
|
||||
->setHref($badge->getViewURI())
|
||||
->addByLine($awarder_info)
|
||||
->addByLine($awarded_date);
|
||||
$item = id(new PHUIBadgeView())
|
||||
->setIcon($badge->getIcon())
|
||||
->setHeader($badge->getName())
|
||||
->setSubhead($badge->getFlavor())
|
||||
->setQuality($badge->getQuality())
|
||||
->setHref($badge->getViewURI())
|
||||
->addByLine($awarder_info)
|
||||
->addByLine($awarded_date);
|
||||
|
||||
$flex->addItem($item);
|
||||
}
|
||||
$flex->addItem($item);
|
||||
}
|
||||
} else {
|
||||
$flex = id(new PHUIInfoView())
|
||||
|
@ -128,6 +119,9 @@ final class PhabricatorPeopleProfileBadgesController
|
|||
->appendChild(pht('User has not been awarded any badges.'));
|
||||
}
|
||||
|
||||
return $flex;
|
||||
return array(
|
||||
$flex,
|
||||
$pager,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -138,6 +138,10 @@ final class PhabricatorProjectApplication extends PhabricatorApplication {
|
|||
);
|
||||
}
|
||||
|
||||
public function getApplicationOrder() {
|
||||
return 0.150;
|
||||
}
|
||||
|
||||
public function getHelpDocumentationArticles(PhabricatorUser $viewer) {
|
||||
return array(
|
||||
array(
|
||||
|
|
|
@ -228,7 +228,10 @@ final class PhabricatorRepositoryPullLocalDaemon
|
|||
continue;
|
||||
}
|
||||
|
||||
$this->waitForUpdates($min_sleep, $retry_after);
|
||||
$should_hibernate = $this->waitForUpdates($min_sleep, $retry_after);
|
||||
if ($should_hibernate) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -492,6 +495,10 @@ final class PhabricatorRepositoryPullLocalDaemon
|
|||
while (($sleep_until - time()) > 0) {
|
||||
$sleep_duration = ($sleep_until - time());
|
||||
|
||||
if ($this->shouldHibernate($sleep_duration)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->log(
|
||||
pht(
|
||||
'Sleeping for %s more second(s)...',
|
||||
|
@ -501,7 +508,7 @@ final class PhabricatorRepositoryPullLocalDaemon
|
|||
|
||||
if ($this->shouldExit()) {
|
||||
$this->log(pht('Awakened from sleep by graceful shutdown!'));
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->loadRepositoryUpdateMessages()) {
|
||||
|
@ -509,6 +516,8 @@ final class PhabricatorRepositoryPullLocalDaemon
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorRepositoryPullLocalDaemonModule
|
||||
extends PhutilDaemonOverseerModule {
|
||||
|
||||
private $cursor = 0;
|
||||
|
||||
public function shouldWakePool(PhutilDaemonPool $pool) {
|
||||
$class = $pool->getPoolDaemonClass();
|
||||
if ($class != 'PhabricatorRepositoryPullLocalDaemon') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->shouldThrottle($class, 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$table = new PhabricatorRepositoryStatusMessage();
|
||||
$table_name = $table->getTableName();
|
||||
$conn = $table->establishConnection('r');
|
||||
|
||||
$row = queryfx_one(
|
||||
$conn,
|
||||
'SELECT id FROM %T WHERE statusType = %s
|
||||
AND id > %d ORDER BY id DESC LIMIT 1',
|
||||
$table_name,
|
||||
PhabricatorRepositoryStatusMessage::TYPE_NEEDS_UPDATE,
|
||||
$this->cursor);
|
||||
|
||||
if (!$row) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->cursor = (int)$row['id'];
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -67,7 +67,7 @@ final class PhabricatorRepositoryCommitOwnersWorker
|
|||
$revision = id(new DifferentialRevisionQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($revision_id))
|
||||
->needReviewerStatus(true)
|
||||
->needReviewers(true)
|
||||
->executeOne();
|
||||
} else {
|
||||
$revision = null;
|
||||
|
@ -165,7 +165,7 @@ final class PhabricatorRepositoryCommitOwnersWorker
|
|||
$accepted_statuses = array_fuse($accepted_statuses);
|
||||
|
||||
$found_accept = false;
|
||||
foreach ($revision->getReviewerStatus() as $reviewer) {
|
||||
foreach ($revision->getReviewers() as $reviewer) {
|
||||
$reviewer_phid = $reviewer->getReviewerPHID();
|
||||
|
||||
// If this reviewer isn't a package owner, just ignore them.
|
||||
|
@ -175,7 +175,7 @@ final class PhabricatorRepositoryCommitOwnersWorker
|
|||
|
||||
// If this reviewer accepted the revision and owns the package, we're
|
||||
// all clear and do not need to trigger an audit.
|
||||
if (isset($accepted_statuses[$reviewer->getStatus()])) {
|
||||
if (isset($accepted_statuses[$reviewer->getReviewerStatus()])) {
|
||||
$found_accept = true;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -178,7 +178,7 @@ abstract class PhabricatorRepositoryCommitMessageParserWorker
|
|||
$revision_query = id(new DifferentialRevisionQuery())
|
||||
->withIDs(array($revision_id))
|
||||
->setViewer($actor)
|
||||
->needReviewerStatus(true)
|
||||
->needReviewers(true)
|
||||
->needActiveDiffs(true);
|
||||
|
||||
$revision = $revision_query->executeOne();
|
||||
|
|
|
@ -555,8 +555,9 @@ final class PhabricatorApplicationSearchController
|
|||
->setTag('a')
|
||||
->setHref('#')
|
||||
->setText(pht('Use Results...'))
|
||||
->setIcon('fa-road')
|
||||
->setDropdownMenu($action_list);
|
||||
->setIcon('fa-bars')
|
||||
->setDropdownMenu($action_list)
|
||||
->addClass('dropdown');
|
||||
}
|
||||
|
||||
private function newOverflowingView() {
|
||||
|
@ -600,9 +601,32 @@ final class PhabricatorApplicationSearchController
|
|||
|
||||
private function newBuiltinUseActions() {
|
||||
$actions = array();
|
||||
$request = $this->getRequest();
|
||||
$viewer = $request->getUser();
|
||||
|
||||
$is_dev = PhabricatorEnv::getEnvConfig('phabricator.developer-mode');
|
||||
|
||||
$engine = $this->getSearchEngine();
|
||||
$engine_class = get_class($engine);
|
||||
$query_key = $this->getQueryKey();
|
||||
if (!$query_key) {
|
||||
$query_key = head_key($engine->loadEnabledNamedQueries());
|
||||
}
|
||||
|
||||
$can_use = $engine->canUseInPanelContext();
|
||||
$is_installed = PhabricatorApplication::isClassInstalledForViewer(
|
||||
'PhabricatorDashboardApplication',
|
||||
$viewer);
|
||||
|
||||
if ($can_use && $is_installed) {
|
||||
$dashboard_uri = '/dashboard/install/';
|
||||
$actions[] = id(new PhabricatorActionView())
|
||||
->setIcon('fa-dashboard')
|
||||
->setName(pht('Add to Dasbhoard'))
|
||||
->setWorkflow(true)
|
||||
->setHref("/dashboard/panel/install/{$engine_class}/{$query_key}/");
|
||||
}
|
||||
|
||||
if ($is_dev) {
|
||||
$engine = $this->getSearchEngine();
|
||||
$nux_uri = $engine->getQueryBaseURI();
|
||||
|
@ -610,8 +634,8 @@ final class PhabricatorApplicationSearchController
|
|||
->setQueryParam('nux', true);
|
||||
|
||||
$actions[] = id(new PhabricatorActionView())
|
||||
->setIcon('fa-bug')
|
||||
->setName(pht('Developer: Show New User State'))
|
||||
->setIcon('fa-user-plus')
|
||||
->setName(pht('DEV: New User State'))
|
||||
->setHref($nux_uri);
|
||||
}
|
||||
|
||||
|
@ -620,8 +644,8 @@ final class PhabricatorApplicationSearchController
|
|||
->setQueryParam('overheated', true);
|
||||
|
||||
$actions[] = id(new PhabricatorActionView())
|
||||
->setIcon('fa-bug')
|
||||
->setName(pht('Developer: Show Overheated State'))
|
||||
->setIcon('fa-fire')
|
||||
->setName(pht('DEV: Overheated State'))
|
||||
->setHref($overheated_uri);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorEditEngineCheckboxesCommentAction
|
||||
extends PhabricatorEditEngineCommentAction {
|
||||
|
||||
private $options = array();
|
||||
|
||||
public function setOptions(array $options) {
|
||||
$this->options = $options;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getOptions() {
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
public function getPHUIXControlType() {
|
||||
return 'checkboxes';
|
||||
}
|
||||
|
||||
public function getPHUIXControlSpecification() {
|
||||
$options = $this->getOptions();
|
||||
|
||||
$labels = array();
|
||||
foreach ($options as $key => $option) {
|
||||
$labels[$key] = hsprintf('%s', $option);
|
||||
}
|
||||
|
||||
return array(
|
||||
'value' => $this->getValue(),
|
||||
'keys' => array_keys($options),
|
||||
'labels' => $labels,
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -163,15 +163,6 @@ final class PhabricatorEditEngineConfigurationViewController
|
|||
->setDisabled(!$can_edit));
|
||||
}
|
||||
|
||||
$curtain->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Change Default Values'))
|
||||
->setIcon('fa-paint-brush')
|
||||
->setHref($defaults_uri)
|
||||
->setWorkflow(!$can_edit)
|
||||
->setDisabled(!$can_edit));
|
||||
|
||||
|
||||
$disable_uri = "{$base_uri}/disable/{$form_key}/";
|
||||
|
||||
if ($config->getIsDisabled()) {
|
||||
|
|
|
@ -996,8 +996,12 @@ abstract class PhabricatorEditEngine
|
|||
$config = $this->getEditEngineConfiguration()
|
||||
->attachEngine($this);
|
||||
|
||||
// NOTE: Don't prompt users to override locks when creating objects,
|
||||
// even if the default settings would create a locked object.
|
||||
|
||||
$can_interact = PhabricatorPolicyFilter::canInteract($viewer, $object);
|
||||
if (!$can_interact &&
|
||||
!$this->getIsCreate() &&
|
||||
!$request->getBool('editEngine') &&
|
||||
!$request->getBool('overrideLock')) {
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ final class PhabricatorApplyEditField
|
|||
|
||||
private $actionDescription;
|
||||
private $actionConflictKey;
|
||||
private $options;
|
||||
|
||||
protected function newControl() {
|
||||
return null;
|
||||
|
@ -28,8 +29,21 @@ final class PhabricatorApplyEditField
|
|||
return $this->actionConflictKey;
|
||||
}
|
||||
|
||||
public function setOptions(array $options) {
|
||||
$this->options = $options;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getOptions() {
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
protected function newHTTPParameterType() {
|
||||
return new AphrontBoolHTTPParameterType();
|
||||
if ($this->getOptions()) {
|
||||
return new AphrontPHIDListHTTPParameterType();
|
||||
} else {
|
||||
return new AphrontBoolHTTPParameterType();
|
||||
}
|
||||
}
|
||||
|
||||
protected function newConduitParameterType() {
|
||||
|
@ -43,9 +57,16 @@ final class PhabricatorApplyEditField
|
|||
}
|
||||
|
||||
protected function newCommentAction() {
|
||||
return id(new PhabricatorEditEngineStaticCommentAction())
|
||||
->setDescription($this->getActionDescription())
|
||||
->setConflictKey($this->getActionConflictKey());
|
||||
$options = $this->getOptions();
|
||||
if ($options) {
|
||||
return id(new PhabricatorEditEngineCheckboxesCommentAction())
|
||||
->setConflictKey($this->getActionConflictKey())
|
||||
->setOptions($options);
|
||||
} else {
|
||||
return id(new PhabricatorEditEngineStaticCommentAction())
|
||||
->setConflictKey($this->getActionConflictKey())
|
||||
->setDescription($this->getActionDescription());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -92,6 +92,7 @@ final class PhabricatorApplicationTransactionCommentEditor
|
|||
$editor
|
||||
->setContentSource($this->getContentSource())
|
||||
->setContinueOnNoEffect(true)
|
||||
->setContinueOnMissingFields(true)
|
||||
->applyTransactions($object, $support_xactions);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -932,7 +932,15 @@ abstract class PhabricatorApplicationTransaction
|
|||
$type = $this->getMetadata('edge:type');
|
||||
$type = head($type);
|
||||
|
||||
$type_obj = PhabricatorEdgeType::getByConstant($type);
|
||||
try {
|
||||
$type_obj = PhabricatorEdgeType::getByConstant($type);
|
||||
} catch (Exception $ex) {
|
||||
// Recover somewhat gracefully from edge transactions which
|
||||
// we don't have the classes for.
|
||||
return pht(
|
||||
'%s edited an edge.',
|
||||
$this->renderHandleLink($author_phid));
|
||||
}
|
||||
|
||||
if ($add && $rem) {
|
||||
return $type_obj->getTransactionEditString(
|
||||
|
|
|
@ -121,5 +121,3 @@ Conpherence room on this install, and you can ask questions in
|
|||
are not upstream support channels and you may not receive a response to
|
||||
questions, but someone in the community may be able to point you in the right
|
||||
direction.
|
||||
|
||||
There is also a community IRC channel in `#phabricator` on FreeNode.
|
||||
|
|
|
@ -48,7 +48,7 @@ Once the import completes, disable the **Observe** URI to automatically convert
|
|||
it into a hosted repository.
|
||||
|
||||
**Push to Empty Repository**: Create an activate an empty repository, then push
|
||||
all of your changes to empty the repository.
|
||||
all of your changes to the empty repository.
|
||||
|
||||
In Git and Mercurial, you can do this with `git push` or `hg push`.
|
||||
|
||||
|
|
|
@ -42,10 +42,3 @@ Then set your "Editor Link" to:
|
|||
|
||||
lang=uri
|
||||
txmt://open/?url=file:///Users/alincoln/editor_links/%r/%f&line=%l
|
||||
|
||||
== Configuring: Other Editors ==
|
||||
|
||||
General instructions for configuring some other editors and environments can be
|
||||
found here:
|
||||
|
||||
http://wiki.nette.org/en/howto-editor-link
|
||||
|
|
|
@ -10,18 +10,9 @@ final class PhabricatorDaemonOverseerModule
|
|||
extends PhutilDaemonOverseerModule {
|
||||
|
||||
private $configVersion;
|
||||
private $timestamp;
|
||||
|
||||
public function __construct() {
|
||||
$this->timestamp = PhabricatorTime::getNow();
|
||||
}
|
||||
|
||||
public function shouldReloadDaemons() {
|
||||
$now = PhabricatorTime::getNow();
|
||||
$ago = ($now - $this->timestamp);
|
||||
|
||||
// Don't check more than once every 10 seconds.
|
||||
if ($ago < 10) {
|
||||
if ($this->shouldThrottle('reload', 10)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -47,25 +38,23 @@ final class PhabricatorDaemonOverseerModule
|
|||
}
|
||||
|
||||
/**
|
||||
* Update the configuration version and timestamp.
|
||||
* Check and update the configuration version.
|
||||
*
|
||||
* @return bool True if the daemons should restart, otherwise false.
|
||||
*/
|
||||
private function updateConfigVersion() {
|
||||
$config_version = $this->loadConfigVersion();
|
||||
$this->timestamp = PhabricatorTime::getNow();
|
||||
$old_version = $this->configVersion;
|
||||
$new_version = $this->loadConfigVersion();
|
||||
|
||||
if (!$this->configVersion) {
|
||||
$this->configVersion = $config_version;
|
||||
$this->configVersion = $new_version;
|
||||
|
||||
// Don't trigger a reload if we're loading the config for the very
|
||||
// first time.
|
||||
if ($old_version === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->configVersion != $config_version) {
|
||||
$this->configVersion = $config_version;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return ($old_version != $new_version);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -43,6 +43,11 @@ final class PhabricatorTaskmasterDaemon extends PhabricatorDaemon {
|
|||
|
||||
$sleep = 0;
|
||||
} else {
|
||||
|
||||
if ($this->shouldHibernate(60)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// When there's no work, sleep for one second. The pool will
|
||||
// autoscale down if we're continuously idle for an extended period
|
||||
// of time.
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorTaskmasterDaemonModule
|
||||
extends PhutilDaemonOverseerModule {
|
||||
|
||||
public function shouldWakePool(PhutilDaemonPool $pool) {
|
||||
$class = $pool->getPoolDaemonClass();
|
||||
|
||||
if ($class != 'PhabricatorTaskmasterDaemon') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->shouldThrottle($class, 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$table = new PhabricatorWorkerActiveTask();
|
||||
$conn = $table->establishConnection('r');
|
||||
|
||||
$row = queryfx_one(
|
||||
$conn,
|
||||
'SELECT id FROM %T WHERE leaseOwner IS NULL
|
||||
OR leaseExpires <= %d LIMIT 1',
|
||||
$table->getTableName(),
|
||||
PhabricatorTime::getNow());
|
||||
if (!$row) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -1608,6 +1608,8 @@ final class PhabricatorUSEnglishTranslation
|
|||
),
|
||||
),
|
||||
|
||||
'%s accepted this revision as %s reviewer(s): %s.' =>
|
||||
'%s accepted this revision as: %3$s.',
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -88,9 +88,10 @@ final class PhabricatorHash extends Phobject {
|
|||
}
|
||||
|
||||
$hash = sha1($string, $raw_output = true);
|
||||
$value = head(unpack('L', $hash));
|
||||
// Make sure this ends up positive, even on 32-bit machines.
|
||||
$value = head(unpack('L', $hash)) & 0x7FFFFFFF;
|
||||
|
||||
return $min + ($value % ($max - $min));
|
||||
return $min + ($value % (1 + $max - $min));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -216,7 +216,6 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView
|
|||
require_celerity_resource('phabricator-standard-page-view');
|
||||
require_celerity_resource('conpherence-durable-column-view');
|
||||
require_celerity_resource('font-lato');
|
||||
require_celerity_resource('font-aleo');
|
||||
|
||||
Javelin::initBehavior('workflow', array());
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
.conpherence-header-pane .phui-header-header {
|
||||
font-size: 16px;
|
||||
font-family: 'Aleo', {$fontfamily};
|
||||
color: #000;
|
||||
}
|
||||
|
||||
|
|
|
@ -139,7 +139,6 @@
|
|||
.phame-next-post-view {
|
||||
margin: 0 auto;
|
||||
padding: 12px 0;
|
||||
font-family: 'Aleo', {$fontfamily};
|
||||
}
|
||||
|
||||
.phame-next {
|
||||
|
@ -294,7 +293,6 @@
|
|||
color: #000;
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
font-family: 'Aleo', {$fontfamily};
|
||||
padding-top: 24px;
|
||||
}
|
||||
|
||||
|
@ -305,7 +303,6 @@
|
|||
.phame-mega-header .phame-header-subtitle {
|
||||
color: {$greytext};
|
||||
font-size: 20px;
|
||||
font-family: 'Aleo', {$fontfamily};
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
|
||||
.project-card-view .phui-header-shell .phui-header-header {
|
||||
font-size: 18px;
|
||||
font-family: 'Aleo', {$fontfamily};
|
||||
width: 290px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
|
@ -71,7 +70,6 @@
|
|||
|
||||
.project-card-header .project-card-name {
|
||||
font-size: 20px;
|
||||
font-family: 'Aleo', {$fontfamily};
|
||||
font-weight: bold;
|
||||
color: #000;
|
||||
margin-bottom: 2px;
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
/**
|
||||
* @provides font-aleo
|
||||
* @requires phui-fontkit-css
|
||||
*/
|
||||
|
||||
@font-face {
|
||||
font-family: 'Aleo';
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
src: url(/rsrc/externals/font/aleo/aleo-bold.eot);
|
||||
src: url(/rsrc/externals/font/aleo/aleo-bold.eot?#iefix)
|
||||
format('embedded-opentype'),
|
||||
url(/rsrc/externals/font/aleo/aleo-bold.woff2)
|
||||
format('woff2'),
|
||||
url(/rsrc/externals/font/aleo/aleo-bold.woff)
|
||||
format('woff'),
|
||||
url(/rsrc/externals/font/aleo/aleo-bold.ttf)
|
||||
format('truetype'),
|
||||
url(/rsrc/externals/font/aleo/aleo-bold.svg#aleo-bold)
|
||||
format('svg');
|
||||
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Aleo';
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
src: url(/rsrc/externals/font/aleo/aleo-regular.eot);
|
||||
src: url(/rsrc/externals/font/aleo/aleo-regular.eot?#iefix)
|
||||
format('embedded-opentype'),
|
||||
url(/rsrc/externals/font/aleo/aleo-regular.woff2)
|
||||
format('woff2'),
|
||||
url(/rsrc/externals/font/aleo/aleo-regular.woff)
|
||||
format('woff'),
|
||||
url(/rsrc/externals/font/aleo/aleo-regular.ttf)
|
||||
format('truetype'),
|
||||
url(/rsrc/externals/font/aleo/aleo-regular.svg#aleo-regular)
|
||||
format('svg');
|
||||
|
||||
}
|
|
@ -2,30 +2,10 @@
|
|||
* @provides phui-fontkit-css
|
||||
*/
|
||||
|
||||
/* - Roboto Slab ---------------------------------------------------------------
|
||||
|
||||
Used as Primary Headers in Object Boxes, Headers in Documents
|
||||
|
||||
*/
|
||||
|
||||
.diviner-document-section .phui-header-header {
|
||||
font-family: 'Aleo', {$fontfamily};
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.phui-document-view .phui-header-tall .phui-header-header {
|
||||
font-family: 'Aleo', {$fontfamily};
|
||||
}
|
||||
|
||||
.phui-document-view .phabricator-remarkup h1.remarkup-header,
|
||||
.phui-document-view .phabricator-remarkup h2.remarkup-header,
|
||||
.phui-document-view .phabricator-remarkup h3.remarkup-header,
|
||||
.phui-document-view .phabricator-remarkup h4.remarkup-header,
|
||||
.phui-document-view .phabricator-remarkup h5.remarkup-header,
|
||||
.phui-document-view .phabricator-remarkup h6.remarkup-header {
|
||||
font-family: 'Aleo', {$fontfamily};
|
||||
}
|
||||
|
||||
.phui-document-view .phabricator-remarkup .remarkup-header {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
|
|
@ -548,3 +548,16 @@ properly, and submit values. */
|
|||
padding: 4px;
|
||||
color: {$bluetext};
|
||||
}
|
||||
|
||||
.phuix-form-checkbox-action {
|
||||
padding: 4px;
|
||||
color: {$bluetext};
|
||||
}
|
||||
|
||||
.phuix-form-checkbox-action input[type=checkbox] {
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
.phuix-form-checkbox-label {
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
|
|
@ -345,7 +345,6 @@ body .phui-header-shell.phui-bleed-header
|
|||
}
|
||||
|
||||
.phui-profile-header.phui-header-shell .phui-header-header {
|
||||
font-family: 'Aleo', {$fontfamily};
|
||||
font-size: 24px;
|
||||
color: #000;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
.phui-two-column-header .phui-header-header {
|
||||
font-size: 20px;
|
||||
font-family: 'Aleo', {$fontfamily};
|
||||
color: #000;
|
||||
}
|
||||
|
||||
|
|
203
webroot/rsrc/externals/font/aleo/LICENSE.txt
vendored
203
webroot/rsrc/externals/font/aleo/LICENSE.txt
vendored
|
@ -1,203 +0,0 @@
|
|||
Font data copyright Google 2013
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
BIN
webroot/rsrc/externals/font/aleo/aleo-bold.eot
vendored
BIN
webroot/rsrc/externals/font/aleo/aleo-bold.eot
vendored
Binary file not shown.
5078
webroot/rsrc/externals/font/aleo/aleo-bold.svg
vendored
5078
webroot/rsrc/externals/font/aleo/aleo-bold.svg
vendored
File diff suppressed because it is too large
Load diff
Before Width: | Height: | Size: 310 KiB |
BIN
webroot/rsrc/externals/font/aleo/aleo-bold.ttf
vendored
BIN
webroot/rsrc/externals/font/aleo/aleo-bold.ttf
vendored
Binary file not shown.
BIN
webroot/rsrc/externals/font/aleo/aleo-bold.woff
vendored
BIN
webroot/rsrc/externals/font/aleo/aleo-bold.woff
vendored
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue