1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-01-10 14:51:06 +01:00

(stable) Promote 2018 Week 37

This commit is contained in:
epriestley 2018-09-15 08:17:04 -07:00
commit f65b846ecf
72 changed files with 1513 additions and 459 deletions

View file

@ -9,7 +9,7 @@ return array(
'names' => array( 'names' => array(
'conpherence.pkg.css' => 'e68cf1fa', 'conpherence.pkg.css' => 'e68cf1fa',
'conpherence.pkg.js' => '15191c65', 'conpherence.pkg.js' => '15191c65',
'core.pkg.css' => 'badf3f16', 'core.pkg.css' => '2574c199',
'core.pkg.js' => 'b5a949ca', 'core.pkg.js' => 'b5a949ca',
'differential.pkg.css' => '06dc617c', 'differential.pkg.css' => '06dc617c',
'differential.pkg.js' => 'c1cfa143', 'differential.pkg.js' => 'c1cfa143',
@ -122,7 +122,7 @@ return array(
'rsrc/css/layout/phabricator-source-code-view.css' => '2ab25dfa', 'rsrc/css/layout/phabricator-source-code-view.css' => '2ab25dfa',
'rsrc/css/phui/button/phui-button-bar.css' => 'f1ff5494', 'rsrc/css/phui/button/phui-button-bar.css' => 'f1ff5494',
'rsrc/css/phui/button/phui-button-simple.css' => '8e1baf68', 'rsrc/css/phui/button/phui-button-simple.css' => '8e1baf68',
'rsrc/css/phui/button/phui-button.css' => '1863cc6e', 'rsrc/css/phui/button/phui-button.css' => '6ccb303c',
'rsrc/css/phui/calendar/phui-calendar-day.css' => '572b1893', 'rsrc/css/phui/calendar/phui-calendar-day.css' => '572b1893',
'rsrc/css/phui/calendar/phui-calendar-list.css' => '576be600', 'rsrc/css/phui/calendar/phui-calendar-list.css' => '576be600',
'rsrc/css/phui/calendar/phui-calendar-month.css' => '21154caf', 'rsrc/css/phui/calendar/phui-calendar-month.css' => '21154caf',
@ -146,12 +146,12 @@ return array(
'rsrc/css/phui/phui-comment-panel.css' => 'f50152ad', 'rsrc/css/phui/phui-comment-panel.css' => 'f50152ad',
'rsrc/css/phui/phui-crumbs-view.css' => '10728aaa', 'rsrc/css/phui/phui-crumbs-view.css' => '10728aaa',
'rsrc/css/phui/phui-curtain-view.css' => '2bdaf026', 'rsrc/css/phui/phui-curtain-view.css' => '2bdaf026',
'rsrc/css/phui/phui-document-pro.css' => '1a08ef4b', 'rsrc/css/phui/phui-document-pro.css' => 'd033e8d5',
'rsrc/css/phui/phui-document-summary.css' => '9ca48bdf', 'rsrc/css/phui/phui-document-summary.css' => '9ca48bdf',
'rsrc/css/phui/phui-document.css' => 'c4ac41f9', 'rsrc/css/phui/phui-document.css' => 'c4ac41f9',
'rsrc/css/phui/phui-feed-story.css' => '44a9c8e9', 'rsrc/css/phui/phui-feed-story.css' => '44a9c8e9',
'rsrc/css/phui/phui-fontkit.css' => '1320ed01', 'rsrc/css/phui/phui-fontkit.css' => '1320ed01',
'rsrc/css/phui/phui-form-view.css' => 'f808e5be', 'rsrc/css/phui/phui-form-view.css' => '2f43fae7',
'rsrc/css/phui/phui-form.css' => '7aaa04e3', 'rsrc/css/phui/phui-form.css' => '7aaa04e3',
'rsrc/css/phui/phui-head-thing.css' => 'fd311e5f', 'rsrc/css/phui/phui-head-thing.css' => 'fd311e5f',
'rsrc/css/phui/phui-header-view.css' => '1ba8b707', 'rsrc/css/phui/phui-header-view.css' => '1ba8b707',
@ -423,7 +423,7 @@ return array(
'rsrc/js/application/search/behavior-reorder-profile-menu-items.js' => 'e2e0a072', 'rsrc/js/application/search/behavior-reorder-profile-menu-items.js' => 'e2e0a072',
'rsrc/js/application/search/behavior-reorder-queries.js' => 'e9581f08', 'rsrc/js/application/search/behavior-reorder-queries.js' => 'e9581f08',
'rsrc/js/application/slowvote/behavior-slowvote-embed.js' => '887ad43f', 'rsrc/js/application/slowvote/behavior-slowvote-embed.js' => '887ad43f',
'rsrc/js/application/transactions/behavior-comment-actions.js' => '54110499', 'rsrc/js/application/transactions/behavior-comment-actions.js' => '038bf27f',
'rsrc/js/application/transactions/behavior-reorder-configs.js' => 'd7a74243', 'rsrc/js/application/transactions/behavior-reorder-configs.js' => 'd7a74243',
'rsrc/js/application/transactions/behavior-reorder-fields.js' => 'b59e1e96', 'rsrc/js/application/transactions/behavior-reorder-fields.js' => 'b59e1e96',
'rsrc/js/application/transactions/behavior-show-older-transactions.js' => '8f29b364', 'rsrc/js/application/transactions/behavior-show-older-transactions.js' => '8f29b364',
@ -575,7 +575,7 @@ return array(
'javelin-behavior-bulk-job-reload' => 'edf8a145', 'javelin-behavior-bulk-job-reload' => 'edf8a145',
'javelin-behavior-calendar-month-view' => 'fe33e256', 'javelin-behavior-calendar-month-view' => 'fe33e256',
'javelin-behavior-choose-control' => '327a00d1', 'javelin-behavior-choose-control' => '327a00d1',
'javelin-behavior-comment-actions' => '54110499', 'javelin-behavior-comment-actions' => '038bf27f',
'javelin-behavior-config-reorder-fields' => 'b6993408', 'javelin-behavior-config-reorder-fields' => 'b6993408',
'javelin-behavior-conpherence-menu' => '4047cd35', 'javelin-behavior-conpherence-menu' => '4047cd35',
'javelin-behavior-conpherence-participant-pane' => 'd057e45a', 'javelin-behavior-conpherence-participant-pane' => 'd057e45a',
@ -800,7 +800,7 @@ return array(
'phui-box-css' => '4bd6cdb9', 'phui-box-css' => '4bd6cdb9',
'phui-bulk-editor-css' => '9a81e5d5', 'phui-bulk-editor-css' => '9a81e5d5',
'phui-button-bar-css' => 'f1ff5494', 'phui-button-bar-css' => 'f1ff5494',
'phui-button-css' => '1863cc6e', 'phui-button-css' => '6ccb303c',
'phui-button-simple-css' => '8e1baf68', 'phui-button-simple-css' => '8e1baf68',
'phui-calendar-css' => 'f1ddf11c', 'phui-calendar-css' => 'f1ddf11c',
'phui-calendar-day-css' => '572b1893', 'phui-calendar-day-css' => '572b1893',
@ -814,12 +814,12 @@ return array(
'phui-curtain-view-css' => '2bdaf026', 'phui-curtain-view-css' => '2bdaf026',
'phui-document-summary-view-css' => '9ca48bdf', 'phui-document-summary-view-css' => '9ca48bdf',
'phui-document-view-css' => 'c4ac41f9', 'phui-document-view-css' => 'c4ac41f9',
'phui-document-view-pro-css' => '1a08ef4b', 'phui-document-view-pro-css' => 'd033e8d5',
'phui-feed-story-css' => '44a9c8e9', 'phui-feed-story-css' => '44a9c8e9',
'phui-font-icon-base-css' => '870a7360', 'phui-font-icon-base-css' => '870a7360',
'phui-fontkit-css' => '1320ed01', 'phui-fontkit-css' => '1320ed01',
'phui-form-css' => '7aaa04e3', 'phui-form-css' => '7aaa04e3',
'phui-form-view-css' => 'f808e5be', 'phui-form-view-css' => '2f43fae7',
'phui-head-thing-view-css' => 'fd311e5f', 'phui-head-thing-view-css' => 'fd311e5f',
'phui-header-view-css' => '1ba8b707', 'phui-header-view-css' => '1ba8b707',
'phui-hovercard' => '1bd28176', 'phui-hovercard' => '1bd28176',
@ -905,6 +905,15 @@ return array(
'javelin-behavior', 'javelin-behavior',
'javelin-uri', 'javelin-uri',
), ),
'038bf27f' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-workflow',
'javelin-dom',
'phuix-form-control-view',
'phuix-icon-view',
'javelin-behavior-phabricator-gesture',
),
'040fce04' => array( '040fce04' => array(
'javelin-behavior', 'javelin-behavior',
'javelin-request', 'javelin-request',
@ -1251,15 +1260,6 @@ return array(
'javelin-vector', 'javelin-vector',
'javelin-typeahead-static-source', 'javelin-typeahead-static-source',
), ),
54110499 => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-workflow',
'javelin-dom',
'phuix-form-control-view',
'phuix-icon-view',
'javelin-behavior-phabricator-gesture',
),
'549459b8' => array( '549459b8' => array(
'javelin-behavior', 'javelin-behavior',
), ),

View file

@ -0,0 +1,54 @@
<?php
$table = new PhabricatorSavedQuery();
$conn = $table->establishConnection('w');
$status_map = array(
0 => 'none',
1 => 'needs-audit',
2 => 'concern-raised',
3 => 'partially-audited',
4 => 'audited',
5 => 'needs-verification',
);
foreach (new LiskMigrationIterator($table) as $query) {
if ($query->getEngineClassName() !== 'PhabricatorCommitSearchEngine') {
continue;
}
$parameters = $query->getParameters();
$status = idx($parameters, 'statuses');
if (!$status) {
// No saved "status" constraint.
continue;
}
if (!is_array($status)) {
// Saved constraint isn't a list.
continue;
}
// Migrate old integer values to new string values.
$old_status = $status;
foreach ($status as $key => $value) {
if (is_numeric($value)) {
$status[$key] = $status_map[$value];
}
}
if ($status === $old_status) {
// Nothing changed.
continue;
}
$parameters['statuses'] = $status;
queryfx(
$conn,
'UPDATE %T SET parameters = %s WHERE id = %d',
$table->getTableName(),
phutil_json_encode($parameters),
$query->getID());
}

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_repository.repository_commit
CHANGE auditStatus auditStatus VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT};

View file

@ -0,0 +1,28 @@
<?php
$table = new PhabricatorRepositoryCommit();
$conn = $table->establishConnection('w');
$status_map = array(
0 => 'none',
1 => 'needs-audit',
2 => 'concern-raised',
3 => 'partially-audited',
4 => 'audited',
5 => 'needs-verification',
);
foreach (new LiskMigrationIterator($table) as $commit) {
$status = $commit->getAuditStatus();
if (!isset($status_map[$status])) {
continue;
}
queryfx(
$conn,
'UPDATE %T SET auditStatus = %s WHERE id = %d',
$table->getTableName(),
$status_map[$status],
$commit->getID());
}

View file

@ -0,0 +1,48 @@
<?php
$table = new PhabricatorAuditTransaction();
$conn = $table->establishConnection('w');
$status_map = array(
0 => 'none',
1 => 'needs-audit',
2 => 'concern-raised',
3 => 'partially-audited',
4 => 'audited',
5 => 'needs-verification',
);
$state_type = DiffusionCommitStateTransaction::TRANSACTIONTYPE;
foreach (new LiskMigrationIterator($table) as $xaction) {
if ($xaction->getTransactionType() !== $state_type) {
continue;
}
$old_value = $xaction->getOldValue();
$new_value = $xaction->getNewValue();
$any_change = false;
if (isset($status_map[$old_value])) {
$old_value = $status_map[$old_value];
$any_change = true;
}
if (isset($status_map[$new_value])) {
$new_value = $status_map[$new_value];
$any_change = true;
}
if (!$any_change) {
continue;
}
queryfx(
$conn,
'UPDATE %T SET oldValue = %s, newValue = %s WHERE id = %d',
$table->getTableName(),
phutil_json_encode($old_value),
phutil_json_encode($new_value),
$xaction->getID());
}

View file

@ -0,0 +1,26 @@
<?php
$commit_table = new PhabricatorRepositoryCommit();
$commit_conn = $commit_table->establishConnection('w');
$commit_name = $commit_table->getTableName();
$properties_table = new PhabricatorMetaMTAMailProperties();
$conn = $properties_table->establishConnection('w');
$iterator = new LiskRawMigrationIterator($commit_conn, $commit_name);
foreach ($iterator as $commit) {
queryfx(
$conn,
'INSERT IGNORE INTO %T
(objectPHID, mailProperties, dateCreated, dateModified)
VALUES
(%s, %s, %d, %d)',
$properties_table->getTableName(),
$commit['phid'],
phutil_json_encode(
array(
'mailKey' => $commit['mailKey'],
)),
PhabricatorTime::getNow(),
PhabricatorTime::getNow());
}

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_repository.repository_commit
DROP mailKey;

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_drydock.drydock_log
ADD operationPHID VARBINARY(64);

View file

@ -704,6 +704,7 @@ phutil_register_library_map(array(
'DiffusionCommitAcceptTransaction' => 'applications/diffusion/xaction/DiffusionCommitAcceptTransaction.php', 'DiffusionCommitAcceptTransaction' => 'applications/diffusion/xaction/DiffusionCommitAcceptTransaction.php',
'DiffusionCommitActionTransaction' => 'applications/diffusion/xaction/DiffusionCommitActionTransaction.php', 'DiffusionCommitActionTransaction' => 'applications/diffusion/xaction/DiffusionCommitActionTransaction.php',
'DiffusionCommitAffectedFilesHeraldField' => 'applications/diffusion/herald/DiffusionCommitAffectedFilesHeraldField.php', 'DiffusionCommitAffectedFilesHeraldField' => 'applications/diffusion/herald/DiffusionCommitAffectedFilesHeraldField.php',
'DiffusionCommitAuditStatus' => 'applications/diffusion/DiffusionCommitAuditStatus.php',
'DiffusionCommitAuditTransaction' => 'applications/diffusion/xaction/DiffusionCommitAuditTransaction.php', 'DiffusionCommitAuditTransaction' => 'applications/diffusion/xaction/DiffusionCommitAuditTransaction.php',
'DiffusionCommitAuditorsHeraldField' => 'applications/diffusion/herald/DiffusionCommitAuditorsHeraldField.php', 'DiffusionCommitAuditorsHeraldField' => 'applications/diffusion/herald/DiffusionCommitAuditorsHeraldField.php',
'DiffusionCommitAuditorsTransaction' => 'applications/diffusion/xaction/DiffusionCommitAuditorsTransaction.php', 'DiffusionCommitAuditorsTransaction' => 'applications/diffusion/xaction/DiffusionCommitAuditorsTransaction.php',
@ -1167,6 +1168,7 @@ phutil_register_library_map(array(
'DrydockManagementUpdateResourceWorkflow' => 'applications/drydock/management/DrydockManagementUpdateResourceWorkflow.php', 'DrydockManagementUpdateResourceWorkflow' => 'applications/drydock/management/DrydockManagementUpdateResourceWorkflow.php',
'DrydockManagementWorkflow' => 'applications/drydock/management/DrydockManagementWorkflow.php', 'DrydockManagementWorkflow' => 'applications/drydock/management/DrydockManagementWorkflow.php',
'DrydockObjectAuthorizationView' => 'applications/drydock/view/DrydockObjectAuthorizationView.php', 'DrydockObjectAuthorizationView' => 'applications/drydock/view/DrydockObjectAuthorizationView.php',
'DrydockOperationWorkLogType' => 'applications/drydock/logtype/DrydockOperationWorkLogType.php',
'DrydockQuery' => 'applications/drydock/query/DrydockQuery.php', 'DrydockQuery' => 'applications/drydock/query/DrydockQuery.php',
'DrydockRepositoryOperation' => 'applications/drydock/storage/DrydockRepositoryOperation.php', 'DrydockRepositoryOperation' => 'applications/drydock/storage/DrydockRepositoryOperation.php',
'DrydockRepositoryOperationController' => 'applications/drydock/controller/DrydockRepositoryOperationController.php', 'DrydockRepositoryOperationController' => 'applications/drydock/controller/DrydockRepositoryOperationController.php',
@ -1204,6 +1206,7 @@ phutil_register_library_map(array(
'DrydockSlotLockException' => 'applications/drydock/exception/DrydockSlotLockException.php', 'DrydockSlotLockException' => 'applications/drydock/exception/DrydockSlotLockException.php',
'DrydockSlotLockFailureLogType' => 'applications/drydock/logtype/DrydockSlotLockFailureLogType.php', 'DrydockSlotLockFailureLogType' => 'applications/drydock/logtype/DrydockSlotLockFailureLogType.php',
'DrydockTestRepositoryOperation' => 'applications/drydock/operation/DrydockTestRepositoryOperation.php', 'DrydockTestRepositoryOperation' => 'applications/drydock/operation/DrydockTestRepositoryOperation.php',
'DrydockTextLogType' => 'applications/drydock/logtype/DrydockTextLogType.php',
'DrydockWebrootInterface' => 'applications/drydock/interface/webroot/DrydockWebrootInterface.php', 'DrydockWebrootInterface' => 'applications/drydock/interface/webroot/DrydockWebrootInterface.php',
'DrydockWorker' => 'applications/drydock/worker/DrydockWorker.php', 'DrydockWorker' => 'applications/drydock/worker/DrydockWorker.php',
'DrydockWorkingCopyBlueprintImplementation' => 'applications/drydock/blueprint/DrydockWorkingCopyBlueprintImplementation.php', 'DrydockWorkingCopyBlueprintImplementation' => 'applications/drydock/blueprint/DrydockWorkingCopyBlueprintImplementation.php',
@ -2147,7 +2150,6 @@ phutil_register_library_map(array(
'PhabricatorAuditActionConstants' => 'applications/audit/constants/PhabricatorAuditActionConstants.php', 'PhabricatorAuditActionConstants' => 'applications/audit/constants/PhabricatorAuditActionConstants.php',
'PhabricatorAuditApplication' => 'applications/audit/application/PhabricatorAuditApplication.php', 'PhabricatorAuditApplication' => 'applications/audit/application/PhabricatorAuditApplication.php',
'PhabricatorAuditCommentEditor' => 'applications/audit/editor/PhabricatorAuditCommentEditor.php', 'PhabricatorAuditCommentEditor' => 'applications/audit/editor/PhabricatorAuditCommentEditor.php',
'PhabricatorAuditCommitStatusConstants' => 'applications/audit/constants/PhabricatorAuditCommitStatusConstants.php',
'PhabricatorAuditController' => 'applications/audit/controller/PhabricatorAuditController.php', 'PhabricatorAuditController' => 'applications/audit/controller/PhabricatorAuditController.php',
'PhabricatorAuditEditor' => 'applications/audit/editor/PhabricatorAuditEditor.php', 'PhabricatorAuditEditor' => 'applications/audit/editor/PhabricatorAuditEditor.php',
'PhabricatorAuditInlineComment' => 'applications/audit/storage/PhabricatorAuditInlineComment.php', 'PhabricatorAuditInlineComment' => 'applications/audit/storage/PhabricatorAuditInlineComment.php',
@ -5021,6 +5023,9 @@ phutil_register_library_map(array(
'PhrictionDocumentController' => 'applications/phriction/controller/PhrictionDocumentController.php', 'PhrictionDocumentController' => 'applications/phriction/controller/PhrictionDocumentController.php',
'PhrictionDocumentDatasource' => 'applications/phriction/typeahead/PhrictionDocumentDatasource.php', 'PhrictionDocumentDatasource' => 'applications/phriction/typeahead/PhrictionDocumentDatasource.php',
'PhrictionDocumentDeleteTransaction' => 'applications/phriction/xaction/PhrictionDocumentDeleteTransaction.php', 'PhrictionDocumentDeleteTransaction' => 'applications/phriction/xaction/PhrictionDocumentDeleteTransaction.php',
'PhrictionDocumentDraftTransaction' => 'applications/phriction/xaction/PhrictionDocumentDraftTransaction.php',
'PhrictionDocumentEditEngine' => 'applications/phriction/editor/PhrictionDocumentEditEngine.php',
'PhrictionDocumentEditTransaction' => 'applications/phriction/xaction/PhrictionDocumentEditTransaction.php',
'PhrictionDocumentFerretEngine' => 'applications/phriction/search/PhrictionDocumentFerretEngine.php', 'PhrictionDocumentFerretEngine' => 'applications/phriction/search/PhrictionDocumentFerretEngine.php',
'PhrictionDocumentFulltextEngine' => 'applications/phriction/search/PhrictionDocumentFulltextEngine.php', 'PhrictionDocumentFulltextEngine' => 'applications/phriction/search/PhrictionDocumentFulltextEngine.php',
'PhrictionDocumentHeraldAdapter' => 'applications/phriction/herald/PhrictionDocumentHeraldAdapter.php', 'PhrictionDocumentHeraldAdapter' => 'applications/phriction/herald/PhrictionDocumentHeraldAdapter.php',
@ -5042,6 +5047,7 @@ phutil_register_library_map(array(
'PhrictionDocumentVersionTransaction' => 'applications/phriction/xaction/PhrictionDocumentVersionTransaction.php', 'PhrictionDocumentVersionTransaction' => 'applications/phriction/xaction/PhrictionDocumentVersionTransaction.php',
'PhrictionEditConduitAPIMethod' => 'applications/phriction/conduit/PhrictionEditConduitAPIMethod.php', 'PhrictionEditConduitAPIMethod' => 'applications/phriction/conduit/PhrictionEditConduitAPIMethod.php',
'PhrictionEditController' => 'applications/phriction/controller/PhrictionEditController.php', 'PhrictionEditController' => 'applications/phriction/controller/PhrictionEditController.php',
'PhrictionEditEngineController' => 'applications/phriction/controller/PhrictionEditEngineController.php',
'PhrictionHistoryConduitAPIMethod' => 'applications/phriction/conduit/PhrictionHistoryConduitAPIMethod.php', 'PhrictionHistoryConduitAPIMethod' => 'applications/phriction/conduit/PhrictionHistoryConduitAPIMethod.php',
'PhrictionHistoryController' => 'applications/phriction/controller/PhrictionHistoryController.php', 'PhrictionHistoryController' => 'applications/phriction/controller/PhrictionHistoryController.php',
'PhrictionInfoConduitAPIMethod' => 'applications/phriction/conduit/PhrictionInfoConduitAPIMethod.php', 'PhrictionInfoConduitAPIMethod' => 'applications/phriction/conduit/PhrictionInfoConduitAPIMethod.php',
@ -6066,6 +6072,7 @@ phutil_register_library_map(array(
'DiffusionCommitAcceptTransaction' => 'DiffusionCommitAuditTransaction', 'DiffusionCommitAcceptTransaction' => 'DiffusionCommitAuditTransaction',
'DiffusionCommitActionTransaction' => 'DiffusionCommitTransactionType', 'DiffusionCommitActionTransaction' => 'DiffusionCommitTransactionType',
'DiffusionCommitAffectedFilesHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitAffectedFilesHeraldField' => 'DiffusionCommitHeraldField',
'DiffusionCommitAuditStatus' => 'Phobject',
'DiffusionCommitAuditTransaction' => 'DiffusionCommitActionTransaction', 'DiffusionCommitAuditTransaction' => 'DiffusionCommitActionTransaction',
'DiffusionCommitAuditorsHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitAuditorsHeraldField' => 'DiffusionCommitHeraldField',
'DiffusionCommitAuditorsTransaction' => 'DiffusionCommitTransactionType', 'DiffusionCommitAuditorsTransaction' => 'DiffusionCommitTransactionType',
@ -6570,6 +6577,7 @@ phutil_register_library_map(array(
'DrydockManagementUpdateResourceWorkflow' => 'DrydockManagementWorkflow', 'DrydockManagementUpdateResourceWorkflow' => 'DrydockManagementWorkflow',
'DrydockManagementWorkflow' => 'PhabricatorManagementWorkflow', 'DrydockManagementWorkflow' => 'PhabricatorManagementWorkflow',
'DrydockObjectAuthorizationView' => 'AphrontView', 'DrydockObjectAuthorizationView' => 'AphrontView',
'DrydockOperationWorkLogType' => 'DrydockLogType',
'DrydockQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'DrydockQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'DrydockRepositoryOperation' => array( 'DrydockRepositoryOperation' => array(
'DrydockDAO', 'DrydockDAO',
@ -6613,6 +6621,7 @@ phutil_register_library_map(array(
'DrydockSlotLockException' => 'Exception', 'DrydockSlotLockException' => 'Exception',
'DrydockSlotLockFailureLogType' => 'DrydockLogType', 'DrydockSlotLockFailureLogType' => 'DrydockLogType',
'DrydockTestRepositoryOperation' => 'DrydockRepositoryOperationType', 'DrydockTestRepositoryOperation' => 'DrydockRepositoryOperationType',
'DrydockTextLogType' => 'DrydockLogType',
'DrydockWebrootInterface' => 'DrydockInterface', 'DrydockWebrootInterface' => 'DrydockInterface',
'DrydockWorker' => 'PhabricatorWorker', 'DrydockWorker' => 'PhabricatorWorker',
'DrydockWorkingCopyBlueprintImplementation' => 'DrydockBlueprintImplementation', 'DrydockWorkingCopyBlueprintImplementation' => 'DrydockBlueprintImplementation',
@ -7715,7 +7724,6 @@ phutil_register_library_map(array(
'PhabricatorAuditActionConstants' => 'Phobject', 'PhabricatorAuditActionConstants' => 'Phobject',
'PhabricatorAuditApplication' => 'PhabricatorApplication', 'PhabricatorAuditApplication' => 'PhabricatorApplication',
'PhabricatorAuditCommentEditor' => 'PhabricatorEditor', 'PhabricatorAuditCommentEditor' => 'PhabricatorEditor',
'PhabricatorAuditCommitStatusConstants' => 'Phobject',
'PhabricatorAuditController' => 'PhabricatorController', 'PhabricatorAuditController' => 'PhabricatorController',
'PhabricatorAuditEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorAuditEditor' => 'PhabricatorApplicationTransactionEditor',
'PhabricatorAuditInlineComment' => array( 'PhabricatorAuditInlineComment' => array(
@ -11136,10 +11144,13 @@ phutil_register_library_map(array(
), ),
'PhrictionDocumentAuthorHeraldField' => 'PhrictionDocumentHeraldField', 'PhrictionDocumentAuthorHeraldField' => 'PhrictionDocumentHeraldField',
'PhrictionDocumentContentHeraldField' => 'PhrictionDocumentHeraldField', 'PhrictionDocumentContentHeraldField' => 'PhrictionDocumentHeraldField',
'PhrictionDocumentContentTransaction' => 'PhrictionDocumentVersionTransaction', 'PhrictionDocumentContentTransaction' => 'PhrictionDocumentEditTransaction',
'PhrictionDocumentController' => 'PhrictionController', 'PhrictionDocumentController' => 'PhrictionController',
'PhrictionDocumentDatasource' => 'PhabricatorTypeaheadDatasource', 'PhrictionDocumentDatasource' => 'PhabricatorTypeaheadDatasource',
'PhrictionDocumentDeleteTransaction' => 'PhrictionDocumentVersionTransaction', 'PhrictionDocumentDeleteTransaction' => 'PhrictionDocumentVersionTransaction',
'PhrictionDocumentDraftTransaction' => 'PhrictionDocumentEditTransaction',
'PhrictionDocumentEditEngine' => 'PhabricatorEditEngine',
'PhrictionDocumentEditTransaction' => 'PhrictionDocumentVersionTransaction',
'PhrictionDocumentFerretEngine' => 'PhabricatorFerretEngine', 'PhrictionDocumentFerretEngine' => 'PhabricatorFerretEngine',
'PhrictionDocumentFulltextEngine' => 'PhabricatorFulltextEngine', 'PhrictionDocumentFulltextEngine' => 'PhabricatorFulltextEngine',
'PhrictionDocumentHeraldAdapter' => 'HeraldAdapter', 'PhrictionDocumentHeraldAdapter' => 'HeraldAdapter',
@ -11161,6 +11172,7 @@ phutil_register_library_map(array(
'PhrictionDocumentVersionTransaction' => 'PhrictionDocumentTransactionType', 'PhrictionDocumentVersionTransaction' => 'PhrictionDocumentTransactionType',
'PhrictionEditConduitAPIMethod' => 'PhrictionConduitAPIMethod', 'PhrictionEditConduitAPIMethod' => 'PhrictionConduitAPIMethod',
'PhrictionEditController' => 'PhrictionController', 'PhrictionEditController' => 'PhrictionController',
'PhrictionEditEngineController' => 'PhrictionController',
'PhrictionHistoryConduitAPIMethod' => 'PhrictionConduitAPIMethod', 'PhrictionHistoryConduitAPIMethod' => 'PhrictionConduitAPIMethod',
'PhrictionHistoryController' => 'PhrictionController', 'PhrictionHistoryController' => 'PhrictionController',
'PhrictionInfoConduitAPIMethod' => 'PhrictionConduitAPIMethod', 'PhrictionInfoConduitAPIMethod' => 'PhrictionConduitAPIMethod',

View file

@ -68,17 +68,17 @@ final class AuditQueryConduitAPIMethod extends AuditConduitAPIMethod {
$status_map = array( $status_map = array(
self::AUDIT_LEGACYSTATUS_OPEN => array( self::AUDIT_LEGACYSTATUS_OPEN => array(
PhabricatorAuditCommitStatusConstants::NEEDS_AUDIT, DiffusionCommitAuditStatus::NEEDS_AUDIT,
PhabricatorAuditCommitStatusConstants::CONCERN_RAISED, DiffusionCommitAuditStatus::CONCERN_RAISED,
), ),
self::AUDIT_LEGACYSTATUS_CONCERN => array( self::AUDIT_LEGACYSTATUS_CONCERN => array(
PhabricatorAuditCommitStatusConstants::CONCERN_RAISED, DiffusionCommitAuditStatus::CONCERN_RAISED,
), ),
self::AUDIT_LEGACYSTATUS_ACCEPTED => array( self::AUDIT_LEGACYSTATUS_ACCEPTED => array(
PhabricatorAuditCommitStatusConstants::FULLY_AUDITED, DiffusionCommitAuditStatus::AUDITED,
), ),
self::AUDIT_LEGACYSTATUS_PARTIAL => array( self::AUDIT_LEGACYSTATUS_PARTIAL => array(
PhabricatorAuditCommitStatusConstants::PARTIALLY_AUDITED, DiffusionCommitAuditStatus::PARTIALLY_AUDITED,
), ),
); );

View file

@ -1,140 +0,0 @@
<?php
final class PhabricatorAuditCommitStatusConstants extends Phobject {
private $key;
private $spec = array();
const NONE = 0;
const NEEDS_AUDIT = 1;
const CONCERN_RAISED = 2;
const PARTIALLY_AUDITED = 3;
const FULLY_AUDITED = 4;
const NEEDS_VERIFICATION = 5;
const MODERN_NONE = 'none';
const MODERN_NEEDS_AUDIT = 'needs-audit';
const MODERN_CONCERN_RAISED = 'concern-raised';
const MODERN_PARTIALLY_AUDITED = 'partially-audited';
const MODERN_AUDITED = 'audited';
const MODERN_NEEDS_VERIFICATION = 'needs-verification';
public static function newForLegacyStatus($status) {
$map = self::getMap();
foreach ($map as $key => $spec) {
if (idx($spec, 'legacy') == $status) {
return self::newForStatus($key);
}
}
return self::newForStatus($status);
}
public static function newForStatus($status) {
$result = new self();
$result->key = $status;
$map = self::getMap();
if (isset($map[$status])) {
$result->spec = $map[$status];
}
return $result;
}
public function getKey() {
return $this->key;
}
public function getIcon() {
return idx($this->spec, 'icon');
}
public function getColor() {
return idx($this->spec, 'color');
}
public function getName() {
return idx($this->spec, 'name', pht('Unknown ("%s")', $this->key));
}
public static function getStatusNameMap() {
$map = self::getMap();
return ipull($map, 'name', 'legacy');
}
public static function getStatusName($code) {
return idx(self::getStatusNameMap(), $code, pht('Unknown'));
}
public static function getOpenStatusConstants() {
$constants = array();
foreach (self::getMap() as $map) {
if (!$map['closed']) {
$constants[] = $map['legacy'];
}
}
return $constants;
}
public static function getStatusColor($code) {
$map = self::getMap();
$map = ipull($map, 'color', 'legacy');
return idx($map, $code);
}
public static function getStatusIcon($code) {
$map = self::getMap();
$map = ipull($map, 'icon', 'legacy');
return idx($map, $code);
}
private static function getMap() {
return array(
self::MODERN_NONE => array(
'name' => pht('No Audits'),
'legacy' => self::NONE,
'icon' => 'fa-check',
'color' => 'bluegrey',
'closed' => true,
),
self::MODERN_NEEDS_AUDIT => array(
'name' => pht('Audit Required'),
'legacy' => self::NEEDS_AUDIT,
'icon' => 'fa-exclamation-circle',
'color' => 'orange',
'closed' => false,
),
self::MODERN_CONCERN_RAISED => array(
'name' => pht('Concern Raised'),
'legacy' => self::CONCERN_RAISED,
'icon' => 'fa-times-circle',
'color' => 'red',
'closed' => false,
),
self::MODERN_PARTIALLY_AUDITED => array(
'name' => pht('Partially Audited'),
'legacy' => self::PARTIALLY_AUDITED,
'icon' => 'fa-check-circle-o',
'color' => 'yellow',
'closed' => false,
),
self::MODERN_AUDITED => array(
'name' => pht('Audited'),
'legacy' => self::FULLY_AUDITED,
'icon' => 'fa-check-circle',
'color' => 'green',
'closed' => true,
),
self::MODERN_NEEDS_VERIFICATION => array(
'name' => pht('Needs Verification'),
'legacy' => self::NEEDS_VERIFICATION,
'icon' => 'fa-refresh',
'color' => 'indigo',
'closed' => false,
),
);
}
}

View file

@ -206,12 +206,10 @@ final class PhabricatorAuditEditor
$object->writeImportStatusFlag($import_status_flag); $object->writeImportStatusFlag($import_status_flag);
} }
$partial_status = PhabricatorAuditCommitStatusConstants::PARTIALLY_AUDITED;
// If the commit has changed state after this edit, add an informational // If the commit has changed state after this edit, add an informational
// transaction about the state change. // transaction about the state change.
if ($old_status != $new_status) { if ($old_status != $new_status) {
if ($new_status == $partial_status) { if ($object->isAuditStatusPartiallyAudited()) {
// This state isn't interesting enough to get a transaction. The // This state isn't interesting enough to get a transaction. The
// best way we could lead the user forward is something like "This // best way we could lead the user forward is something like "This
// commit still requires additional audits." but that's redundant and // commit still requires additional audits." but that's redundant and

View file

@ -15,6 +15,7 @@ final class PhabricatorCommitSearchEngine
return id(new DiffusionCommitQuery()) return id(new DiffusionCommitQuery())
->needAuditRequests(true) ->needAuditRequests(true)
->needCommitData(true) ->needCommitData(true)
->needIdentities(true)
->needDrafts(true); ->needDrafts(true);
} }
@ -92,7 +93,9 @@ final class PhabricatorCommitSearchEngine
->setLabel(pht('Audit Status')) ->setLabel(pht('Audit Status'))
->setKey('statuses') ->setKey('statuses')
->setAliases(array('status')) ->setAliases(array('status'))
->setOptions(PhabricatorAuditCommitStatusConstants::getStatusNameMap()) ->setOptions(DiffusionCommitAuditStatus::newOptions())
->setDeprecatedOptions(
DiffusionCommitAuditStatus::newDeprecatedOptions())
->setDescription(pht('Find commits with given audit statuses.')), ->setDescription(pht('Find commits with given audit statuses.')),
id(new PhabricatorSearchDatasourceField()) id(new PhabricatorSearchDatasourceField())
->setLabel(pht('Repositories')) ->setLabel(pht('Repositories'))
@ -160,7 +163,7 @@ final class PhabricatorCommitSearchEngine
case 'active': case 'active':
$bucket_key = DiffusionCommitRequiredActionResultBucket::BUCKETKEY; $bucket_key = DiffusionCommitRequiredActionResultBucket::BUCKETKEY;
$open = PhabricatorAuditCommitStatusConstants::getOpenStatusConstants(); $open = DiffusionCommitAuditStatus::getOpenStatusConstants();
$query $query
->setParameter('responsiblePHIDs', array($viewer_phid)) ->setParameter('responsiblePHIDs', array($viewer_phid))

View file

@ -490,8 +490,7 @@ final class PhabricatorAuthSessionEngine extends Phobject {
PhabricatorAuthSession $session, PhabricatorAuthSession $session,
$force = false) { $force = false) {
$until = $session->getHighSecurityUntil(); if ($session->isHighSecuritySession() || $force) {
if ($until > time() || $force) {
return new PhabricatorAuthHighSecurityToken(); return new PhabricatorAuthHighSecurityToken();
} }

View file

@ -74,6 +74,22 @@ final class PhabricatorAuthSession extends PhabricatorAuthDAO
} }
} }
public function isHighSecuritySession() {
$until = $this->getHighSecurityUntil();
if (!$until) {
return false;
}
$now = PhabricatorTime::getNow();
if ($until < $now) {
return false;
}
return true;
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */ /* -( PhabricatorPolicyInterface )----------------------------------------- */

View file

@ -4,6 +4,7 @@ final class ConduitConstantDescription extends Phobject {
private $key; private $key;
private $value; private $value;
private $isDeprecated;
public function setKey($key) { public function setKey($key) {
$this->key = $key; $this->key = $key;
@ -23,4 +24,13 @@ final class ConduitConstantDescription extends Phobject {
return $this->value; return $this->value;
} }
public function setIsDeprecated($is_deprecated) {
$this->isDeprecated = $is_deprecated;
return $this;
}
public function getIsDeprecated() {
return $this->isDeprecated;
}
} }

View file

@ -0,0 +1,173 @@
<?php
final class DiffusionCommitAuditStatus extends Phobject {
private $key;
private $spec = array();
const NONE = 'none';
const NEEDS_AUDIT = 'needs-audit';
const CONCERN_RAISED = 'concern-raised';
const PARTIALLY_AUDITED = 'partially-audited';
const AUDITED = 'audited';
const NEEDS_VERIFICATION = 'needs-verification';
public static function newModernKeys(array $values) {
$map = self::getMap();
$modern = array();
foreach ($map as $key => $spec) {
if (isset($spec['legacy'])) {
$modern[$spec['legacy']] = $key;
}
}
foreach ($values as $key => $value) {
$values[$key] = idx($modern, $value, $value);
}
return $values;
}
public static function newForStatus($status) {
$result = new self();
$result->key = $status;
$map = self::getMap();
if (isset($map[$status])) {
$result->spec = $map[$status];
}
return $result;
}
public function getKey() {
return $this->key;
}
public function getIcon() {
return idx($this->spec, 'icon');
}
public function getColor() {
return idx($this->spec, 'color');
}
public function getAnsiColor() {
return idx($this->spec, 'color.ansi');
}
public function getName() {
return idx($this->spec, 'name', pht('Unknown ("%s")', $this->key));
}
public function isNoAudit() {
return ($this->key == self::NONE);
}
public function isNeedsAudit() {
return ($this->key == self::NEEDS_AUDIT);
}
public function isConcernRaised() {
return ($this->key == self::CONCERN_RAISED);
}
public function isNeedsVerification() {
return ($this->key == self::NEEDS_VERIFICATION);
}
public function isPartiallyAudited() {
return ($this->key == self::PARTIALLY_AUDITED);
}
public function isAudited() {
return ($this->key == self::AUDITED);
}
public function getIsClosed() {
return idx($this->spec, 'closed');
}
public static function getOpenStatusConstants() {
$constants = array();
foreach (self::getMap() as $key => $map) {
if (!$map['closed']) {
$constants[] = $key;
}
}
return $constants;
}
public static function newOptions() {
$map = self::getMap();
return ipull($map, 'name');
}
public static function newDeprecatedOptions() {
$map = self::getMap();
$results = array();
foreach ($map as $key => $spec) {
if (isset($spec['legacy'])) {
$results[$spec['legacy']] = $key;
}
}
return $results;
}
private static function getMap() {
return array(
self::NONE => array(
'name' => pht('No Audits'),
'legacy' => 0,
'icon' => 'fa-check',
'color' => 'bluegrey',
'closed' => true,
'color.ansi' => null,
),
self::NEEDS_AUDIT => array(
'name' => pht('Audit Required'),
'legacy' => 1,
'icon' => 'fa-exclamation-circle',
'color' => 'orange',
'closed' => false,
'color.ansi' => 'magenta',
),
self::CONCERN_RAISED => array(
'name' => pht('Concern Raised'),
'legacy' => 2,
'icon' => 'fa-times-circle',
'color' => 'red',
'closed' => false,
'color.ansi' => 'red',
),
self::PARTIALLY_AUDITED => array(
'name' => pht('Partially Audited'),
'legacy' => 3,
'icon' => 'fa-check-circle-o',
'color' => 'yellow',
'closed' => false,
'color.ansi' => 'yellow',
),
self::AUDITED => array(
'name' => pht('Audited'),
'legacy' => 4,
'icon' => 'fa-check-circle',
'color' => 'green',
'closed' => true,
'color.ansi' => 'green',
),
self::NEEDS_VERIFICATION => array(
'name' => pht('Needs Verification'),
'legacy' => 5,
'icon' => 'fa-refresh',
'color' => 'indigo',
'closed' => false,
'color.ansi' => 'magenta',
),
);
}
}

View file

@ -171,13 +171,12 @@ final class DiffusionCommitController extends DiffusionController {
->setHeaderIcon('fa-code-fork') ->setHeaderIcon('fa-code-fork')
->addTag($commit_tag); ->addTag($commit_tag);
if ($commit->getAuditStatus()) { if (!$commit->isAuditStatusNoAudit()) {
$icon = PhabricatorAuditCommitStatusConstants::getStatusIcon( $status = $commit->getAuditStatusObject();
$commit->getAuditStatus());
$color = PhabricatorAuditCommitStatusConstants::getStatusColor( $icon = $status->getIcon();
$commit->getAuditStatus()); $color = $status->getColor();
$status = PhabricatorAuditCommitStatusConstants::getStatusName( $status = $status->getName();
$commit->getAuditStatus());
$header->setStatus($icon, $color, $status); $header->setStatus($icon, $color, $status);
} }

View file

@ -31,8 +31,6 @@ final class DiffusionDoorkeeperCommitFeedStoryPublisher
// After ApplicationTransactions, we could annotate feed stories more // After ApplicationTransactions, we could annotate feed stories more
// explicitly. // explicitly.
$fully_audited = PhabricatorAuditCommitStatusConstants::FULLY_AUDITED;
$story = $this->getFeedStory(); $story = $this->getFeedStory();
$xaction = $story->getPrimaryTransaction(); $xaction = $story->getPrimaryTransaction();
switch ($xaction->getTransactionType()) { switch ($xaction->getTransactionType()) {
@ -41,7 +39,7 @@ final class DiffusionDoorkeeperCommitFeedStoryPublisher
case PhabricatorAuditActionConstants::CLOSE: case PhabricatorAuditActionConstants::CLOSE:
return true; return true;
case PhabricatorAuditActionConstants::ACCEPT: case PhabricatorAuditActionConstants::ACCEPT:
if ($object->getAuditStatus() == $fully_audited) { if ($object->isAuditStatusAudited()) {
return true; return true;
} }
break; break;
@ -165,14 +163,7 @@ final class DiffusionDoorkeeperCommitFeedStoryPublisher
} }
public function isObjectClosed($object) { public function isObjectClosed($object) {
switch ($object->getAuditStatus()) { return $object->getAuditStatusObject()->getIsClosed();
case PhabricatorAuditCommitStatusConstants::NEEDS_AUDIT:
case PhabricatorAuditCommitStatusConstants::CONCERN_RAISED:
case PhabricatorAuditCommitStatusConstants::PARTIALLY_AUDITED:
return false;
default:
return true;
}
} }
public function getResponsibilityTitle($object) { public function getResponsibilityTitle($object) {

View file

@ -41,12 +41,12 @@ final class DiffusionHovercardEngineExtension
$hovercard->addField(pht('Date'), $hovercard->addField(pht('Date'),
phabricator_date($commit->getEpoch(), $viewer)); phabricator_date($commit->getEpoch(), $viewer));
if ($commit->getAuditStatus() != if (!$commit->isAuditStatusNoAudit()) {
PhabricatorAuditCommitStatusConstants::NONE) { $status = $commit->getAuditStatusObject();
$hovercard->addField(pht('Audit Status'), $hovercard->addField(
PhabricatorAuditCommitStatusConstants::getStatusName( pht('Audit Status'),
$commit->getAuditStatus())); $status->getName());
} }
} }

View file

@ -714,10 +714,13 @@ final class DiffusionCommitQuery
} }
if ($this->statuses !== null) { if ($this->statuses !== null) {
$statuses = DiffusionCommitAuditStatus::newModernKeys(
$this->statuses);
$where[] = qsprintf( $where[] = qsprintf(
$conn, $conn,
'commit.auditStatus IN (%Ld)', 'commit.auditStatus IN (%Ls)',
$this->statuses); $statuses);
} }
if ($this->packagePHIDs !== null) { if ($this->packagePHIDs !== null) {

View file

@ -69,14 +69,12 @@ final class DiffusionCommitRequiredActionResultBucket
$results = array(); $results = array();
$objects = $this->objects; $objects = $this->objects;
$status_concern = PhabricatorAuditCommitStatusConstants::CONCERN_RAISED;
foreach ($objects as $key => $object) { foreach ($objects as $key => $object) {
if (empty($phids[$object->getAuthorPHID()])) { if (empty($phids[$object->getAuthorPHID()])) {
continue; continue;
} }
if ($object->getAuditStatus() != $status_concern) { if (!$object->isAuditStatusConcernRaised()) {
continue; continue;
} }
@ -91,7 +89,6 @@ final class DiffusionCommitRequiredActionResultBucket
$results = array(); $results = array();
$objects = $this->objects; $objects = $this->objects;
$status_verify = PhabricatorAuditCommitStatusConstants::NEEDS_VERIFICATION;
$has_concern = array( $has_concern = array(
PhabricatorAuditStatusConstants::CONCERNED, PhabricatorAuditStatusConstants::CONCERNED,
); );
@ -102,7 +99,7 @@ final class DiffusionCommitRequiredActionResultBucket
continue; continue;
} }
if ($object->getAuditStatus() != $status_verify) { if (!$object->isAuditStatusNeedsVerification()) {
continue; continue;
} }
@ -147,10 +144,8 @@ final class DiffusionCommitRequiredActionResultBucket
$results = array(); $results = array();
$objects = $this->objects; $objects = $this->objects;
$status_concern = PhabricatorAuditCommitStatusConstants::CONCERN_RAISED;
foreach ($objects as $key => $object) { foreach ($objects as $key => $object) {
if ($object->getAuditStatus() != $status_concern) { if (!$object->isAuditStatusConcernRaised()) {
continue; continue;
} }
@ -169,15 +164,13 @@ final class DiffusionCommitRequiredActionResultBucket
$results = array(); $results = array();
$objects = $this->objects; $objects = $this->objects;
$status_waiting = array(
PhabricatorAuditCommitStatusConstants::NEEDS_AUDIT,
PhabricatorAuditCommitStatusConstants::NEEDS_VERIFICATION,
PhabricatorAuditCommitStatusConstants::PARTIALLY_AUDITED,
);
$status_waiting = array_fuse($status_waiting);
foreach ($objects as $key => $object) { foreach ($objects as $key => $object) {
if (empty($status_waiting[$object->getAuditStatus()])) { $any_waiting =
$object->isAuditStatusNeedsAudit() ||
$object->isAuditStatusNeedsVerification() ||
$object->isAuditStatusPartiallyAudited();
if (!$any_waiting) {
continue; continue;
} }

View file

@ -33,8 +33,7 @@ final class DiffusionCommitConcernTransaction
public function applyInternalEffects($object, $value) { public function applyInternalEffects($object, $value) {
// NOTE: We force the commit directly into "Concern Raised" so that we // NOTE: We force the commit directly into "Concern Raised" so that we
// override a possible "Needs Verification" state. // override a possible "Needs Verification" state.
$object->setAuditStatus( $object->setAuditStatus(DiffusionCommitAuditStatus::CONCERN_RAISED);
PhabricatorAuditCommitStatusConstants::CONCERN_RAISED);
} }
public function applyExternalEffects($object, $value) { public function applyExternalEffects($object, $value) {
@ -54,10 +53,8 @@ final class DiffusionCommitConcernTransaction
// Even if you've already raised a concern, you can raise again as long // Even if you've already raised a concern, you can raise again as long
// as the author requested you verify. // as the author requested you verify.
$state_verify = PhabricatorAuditCommitStatusConstants::NEEDS_VERIFICATION;
if ($this->isViewerFullyRejected($object, $viewer)) { if ($this->isViewerFullyRejected($object, $viewer)) {
if ($object->getAuditStatus() != $state_verify) { if (!$object->isAuditStatusNeedsVerification()) {
throw new Exception( throw new Exception(
pht( pht(
'You can not raise a concern with this commit because you have '. 'You can not raise a concern with this commit because you have '.

View file

@ -11,29 +11,32 @@ final class DiffusionCommitStateTransaction
throw new PhutilMethodNotImplementedException(); throw new PhutilMethodNotImplementedException();
} }
public function getIcon() { private function getAuditStatusObject() {
$new = $this->getNewValue(); $new = $this->getNewValue();
return PhabricatorAuditCommitStatusConstants::getStatusIcon($new); return DiffusionCommitAuditStatus::newForStatus($new);
}
public function getIcon() {
return $this->getAuditStatusObject()->getIcon();
} }
public function getColor() { public function getColor() {
$new = $this->getNewValue(); return $this->getAuditStatusObject()->getColor();
return PhabricatorAuditCommitStatusConstants::getStatusColor($new);
} }
public function getTitle() { public function getTitle() {
$new = $this->getNewValue(); $status = $this->getAuditStatusObject();
switch ($new) { switch ($status->getKey()) {
case PhabricatorAuditCommitStatusConstants::NONE: case DiffusionCommitAuditStatus::NONE:
return pht('This commit no longer requires audit.'); return pht('This commit no longer requires audit.');
case PhabricatorAuditCommitStatusConstants::NEEDS_AUDIT: case DiffusionCommitAuditStatus::NEEDS_AUDIT:
return pht('This commit now requires audit.'); return pht('This commit now requires audit.');
case PhabricatorAuditCommitStatusConstants::CONCERN_RAISED: case DiffusionCommitAuditStatus::CONCERN_RAISED:
return pht('This commit now has outstanding concerns.'); return pht('This commit now has outstanding concerns.');
case PhabricatorAuditCommitStatusConstants::NEEDS_VERIFICATION: case DiffusionCommitAuditStatus::NEEDS_VERIFICATION:
return pht('This commit now requires verification by auditors.'); return pht('This commit now requires verification by auditors.');
case PhabricatorAuditCommitStatusConstants::FULLY_AUDITED: case DiffusionCommitAuditStatus::AUDITED:
return pht('All concerns with this commit have now been addressed.'); return pht('All concerns with this commit have now been addressed.');
} }
@ -41,26 +44,26 @@ final class DiffusionCommitStateTransaction
} }
public function getTitleForFeed() { public function getTitleForFeed() {
$new = $this->getNewValue(); $status = $this->getAuditStatusObject();
switch ($new) { switch ($status->getKey()) {
case PhabricatorAuditCommitStatusConstants::NONE: case DiffusionCommitAuditStatus::NONE:
return pht( return pht(
'%s no longer requires audit.', '%s no longer requires audit.',
$this->renderObject()); $this->renderObject());
case PhabricatorAuditCommitStatusConstants::NEEDS_AUDIT: case DiffusionCommitAuditStatus::NEEDS_AUDIT:
return pht( return pht(
'%s now requires audit.', '%s now requires audit.',
$this->renderObject()); $this->renderObject());
case PhabricatorAuditCommitStatusConstants::CONCERN_RAISED: case DiffusionCommitAuditStatus::CONCERN_RAISED:
return pht( return pht(
'%s now has outstanding concerns.', '%s now has outstanding concerns.',
$this->renderObject()); $this->renderObject());
case PhabricatorAuditCommitStatusConstants::NEEDS_VERIFICATION: case DiffusionCommitAuditStatus::NEEDS_VERIFICATION:
return pht( return pht(
'%s now requires verification by auditors.', '%s now requires verification by auditors.',
$this->renderObject()); $this->renderObject());
case PhabricatorAuditCommitStatusConstants::FULLY_AUDITED: case DiffusionCommitAuditStatus::AUDITED:
return pht( return pht(
'All concerns with %s have now been addressed.', 'All concerns with %s have now been addressed.',
$this->renderObject()); $this->renderObject());

View file

@ -36,8 +36,7 @@ final class DiffusionCommitVerifyTransaction
} }
public function applyInternalEffects($object, $value) { public function applyInternalEffects($object, $value) {
$object->setAuditStatus( $object->setAuditStatus(DiffusionCommitAuditStatus::NEEDS_VERIFICATION);
PhabricatorAuditCommitStatusConstants::NEEDS_VERIFICATION);
} }
protected function validateAction($object, PhabricatorUser $viewer) { protected function validateAction($object, PhabricatorUser $viewer) {
@ -48,8 +47,7 @@ final class DiffusionCommitVerifyTransaction
'are not the author.')); 'are not the author.'));
} }
$status = $object->getAuditStatus(); if (!$object->isAuditStatusConcernRaised()) {
if ($status != PhabricatorAuditCommitStatusConstants::CONCERN_RAISED) {
throw new Exception( throw new Exception(
pht( pht(
'You can not request verification of this commit because no '. 'You can not request verification of this commit because no '.

View file

@ -93,6 +93,8 @@ final class PhabricatorDrydockApplication extends PhabricatorApplication {
'' => 'DrydockRepositoryOperationViewController', '' => 'DrydockRepositoryOperationViewController',
'status/' => 'DrydockRepositoryOperationStatusController', 'status/' => 'DrydockRepositoryOperationStatusController',
'dismiss/' => 'DrydockRepositoryOperationDismissController', 'dismiss/' => 'DrydockRepositoryOperationDismissController',
'logs/(?:query/(?P<queryKey>[^/]+)/)?' =>
'DrydockLogListController',
), ),
), ),
), ),

View file

@ -58,8 +58,11 @@ final class DrydockBlueprintViewController extends DrydockBlueprintController {
$log_query = id(new DrydockLogQuery()) $log_query = id(new DrydockLogQuery())
->withBlueprintPHIDs(array($blueprint->getPHID())); ->withBlueprintPHIDs(array($blueprint->getPHID()));
$log_table = $this->buildLogTable($log_query)
->setHideBlueprints(true);
$logs = $this->buildLogBox( $logs = $this->buildLogBox(
$log_query, $log_table,
$this->getApplicationURI("blueprint/{$id}/logs/query/all/")); $this->getApplicationURI("blueprint/{$id}/logs/query/all/"));
$view = id(new PHUITwoColumnView()) $view = id(new PHUITwoColumnView())

View file

@ -79,7 +79,7 @@ abstract class DrydockController extends PhabricatorController {
->addRawContent($table); ->addRawContent($table);
} }
protected function buildLogBox(DrydockLogQuery $query, $all_uri) { protected function buildLogTable(DrydockLogQuery $query) {
$viewer = $this->getViewer(); $viewer = $this->getViewer();
$logs = $query $logs = $query
@ -89,9 +89,12 @@ abstract class DrydockController extends PhabricatorController {
$log_table = id(new DrydockLogListView()) $log_table = id(new DrydockLogListView())
->setUser($viewer) ->setUser($viewer)
->setLogs($logs) ->setLogs($logs);
->render();
return $log_table;
}
protected function buildLogBox(DrydockLogListView $log_table, $all_uri) {
$log_header = id(new PHUIHeaderView()) $log_header = id(new PHUIHeaderView())
->setHeader(pht('Logs')) ->setHeader(pht('Logs'))
->addActionLink( ->addActionLink(

View file

@ -43,8 +43,11 @@ final class DrydockLeaseViewController extends DrydockLeaseController {
$log_query = id(new DrydockLogQuery()) $log_query = id(new DrydockLogQuery())
->withLeasePHIDs(array($lease->getPHID())); ->withLeasePHIDs(array($lease->getPHID()));
$log_table = $this->buildLogTable($log_query)
->setHideLeases(true);
$logs = $this->buildLogBox( $logs = $this->buildLogBox(
$log_query, $log_table,
$this->getApplicationURI("lease/{$id}/logs/query/all/")); $this->getApplicationURI("lease/{$id}/logs/query/all/"));
$crumbs = $this->buildApplicationCrumbs(); $crumbs = $this->buildApplicationCrumbs();

View file

@ -6,6 +6,7 @@ abstract class DrydockLogController
private $blueprint; private $blueprint;
private $resource; private $resource;
private $lease; private $lease;
private $operation;
public function setBlueprint(DrydockBlueprint $blueprint) { public function setBlueprint(DrydockBlueprint $blueprint) {
$this->blueprint = $blueprint; $this->blueprint = $blueprint;
@ -34,6 +35,15 @@ abstract class DrydockLogController
return $this->lease; return $this->lease;
} }
public function setOperation(DrydockRepositoryOperation $operation) {
$this->operation = $operation;
return $this;
}
public function getOperation() {
return $this->operation;
}
public function buildSideNavView() { public function buildSideNavView() {
$nav = new AphrontSideNavFilterView(); $nav = new AphrontSideNavFilterView();
$nav->setBaseURI(new PhutilURI($this->getApplicationURI())); $nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
@ -56,6 +66,11 @@ abstract class DrydockLogController
$engine->setLease($lease); $engine->setLease($lease);
} }
$operation = $this->getOperation();
if ($operation) {
$engine->setOperation($operation);
}
$engine->addNavigationItems($nav->getMenu()); $engine->addNavigationItems($nav->getMenu());
$nav->selectFilter(null); $nav->selectFilter(null);
@ -66,9 +81,12 @@ abstract class DrydockLogController
protected function buildApplicationCrumbs() { protected function buildApplicationCrumbs() {
$crumbs = parent::buildApplicationCrumbs(); $crumbs = parent::buildApplicationCrumbs();
$viewer = $this->getViewer();
$blueprint = $this->getBlueprint(); $blueprint = $this->getBlueprint();
$resource = $this->getResource(); $resource = $this->getResource();
$lease = $this->getLease(); $lease = $this->getLease();
$operation = $this->getOperation();
if ($blueprint) { if ($blueprint) {
$id = $blueprint->getID(); $id = $blueprint->getID();
@ -111,6 +129,20 @@ abstract class DrydockLogController
$crumbs->addTextCrumb( $crumbs->addTextCrumb(
pht('Logs'), pht('Logs'),
$this->getApplicationURI("lease/{$id}/logs/")); $this->getApplicationURI("lease/{$id}/logs/"));
} else if ($operation) {
$id = $operation->getID();
$crumbs->addTextCrumb(
pht('Operations'),
$this->getApplicationURI('operation/'));
$crumbs->addTextCrumb(
pht('Repository Operation %d', $id),
$this->getApplicationURI("operation/{$id}/"));
$crumbs->addTextCrumb(
pht('Logs'),
$this->getApplicationURI("operation/{$id}/logs/"));
} }
return $crumbs; return $crumbs;

View file

@ -46,6 +46,17 @@ final class DrydockLogListController extends DrydockLogController {
$engine->setLease($lease); $engine->setLease($lease);
$this->setLease($lease); $this->setLease($lease);
break; break;
case 'operation':
$operation = id(new DrydockRepositoryOperationQuery())
->setViewer($viewer)
->withIDs(array($id))
->executeOne();
if (!$operation) {
return new Aphront404Response();
}
$engine->setOperation($operation);
$this->setOperation($operation);
break;
default: default:
return new Aphront404Response(); return new Aphront404Response();
} }

View file

@ -47,13 +47,25 @@ final class DrydockRepositoryOperationViewController
->setUser($viewer) ->setUser($viewer)
->setOperation($operation); ->setOperation($operation);
$log_query = id(new DrydockLogQuery())
->withOperationPHIDs(array($operation->getPHID()));
$log_table = $this->buildLogTable($log_query)
->setHideOperations(true);
$logs = $this->buildLogBox(
$log_table,
$this->getApplicationURI("operation/{$id}/logs/query/all/"));
$view = id(new PHUITwoColumnView()) $view = id(new PHUITwoColumnView())
->setHeader($header) ->setHeader($header)
->setCurtain($curtain) ->setCurtain($curtain)
->addPropertySection(pht('Properties'), $properties) ->addPropertySection(pht('Properties'), $properties)
->setMainColumn(array( ->setMainColumn(
$status_view, array(
)); $status_view,
$logs,
));
return $this->newPage() return $this->newPage()
->setTitle($title) ->setTitle($title)

View file

@ -48,8 +48,11 @@ final class DrydockResourceViewController extends DrydockResourceController {
$log_query = id(new DrydockLogQuery()) $log_query = id(new DrydockLogQuery())
->withResourcePHIDs(array($resource->getPHID())); ->withResourcePHIDs(array($resource->getPHID()));
$log_box = $this->buildLogBox( $log_table = $this->buildLogTable($log_query)
$log_query, ->setHideResources(true);
$logs = $this->buildLogBox(
$log_table,
$this->getApplicationURI("resource/{$id}/logs/query/all/")); $this->getApplicationURI("resource/{$id}/logs/query/all/"));
$crumbs = $this->buildApplicationCrumbs(); $crumbs = $this->buildApplicationCrumbs();
@ -86,11 +89,12 @@ final class DrydockResourceViewController extends DrydockResourceController {
$view = id(new PHUITwoColumnView()) $view = id(new PHUITwoColumnView())
->setHeader($header) ->setHeader($header)
->setCurtain($curtain) ->setCurtain($curtain)
->setMainColumn(array( ->setMainColumn(
$object_box, array(
$lease_box, $object_box,
$log_box, $lease_box,
)); $logs,
));
return $this->newPage() return $this->newPage()
->setTitle($title) ->setTitle($title)

View file

@ -0,0 +1,19 @@
<?php
final class DrydockOperationWorkLogType extends DrydockLogType {
const LOGCONST = 'core.operation.work';
public function getLogTypeName() {
return pht('Started Work');
}
public function getLogTypeIcon(array $data) {
return 'fa-check green';
}
public function renderLog(array $data) {
return pht('Started this operation in a working copy.');
}
}

View file

@ -0,0 +1,27 @@
<?php
/**
* Simple convenience log type for logging arbitrary text.
*
* Drydock logs can be given formal types, which allows them to be translated
* and filtered. If you don't particularly care about fancy logging features,
* you can use this log type to just dump some text into the log. Maybe you
* could upgrade to more formal logging later.
*/
final class DrydockTextLogType extends DrydockLogType {
const LOGCONST = 'core.text';
public function getLogTypeName() {
return pht('Text');
}
public function getLogTypeIcon(array $data) {
return 'fa-file-text-o grey';
}
public function renderLog(array $data) {
return idx($data, 'text');
}
}

View file

@ -5,7 +5,7 @@ final class DrydockRepositoryOperationPHIDType extends PhabricatorPHIDType {
const TYPECONST = 'DRYO'; const TYPECONST = 'DRYO';
public function getTypeName() { public function getTypeName() {
return pht('Drydock Repository Operation'); return pht('Repository Operation');
} }
public function newObject() { public function newObject() {
@ -33,7 +33,7 @@ final class DrydockRepositoryOperationPHIDType extends PhabricatorPHIDType {
$operation = $objects[$phid]; $operation = $objects[$phid];
$id = $operation->getID(); $id = $operation->getID();
$handle->setName(pht('Drydock Repository Operation %d', $id)); $handle->setName(pht('Repository Operation %d', $id));
$handle->setURI("/drydock/operation/{$id}/"); $handle->setURI("/drydock/operation/{$id}/");
} }
} }

View file

@ -5,6 +5,7 @@ final class DrydockLogQuery extends DrydockQuery {
private $blueprintPHIDs; private $blueprintPHIDs;
private $resourcePHIDs; private $resourcePHIDs;
private $leasePHIDs; private $leasePHIDs;
private $operationPHIDs;
public function withBlueprintPHIDs(array $phids) { public function withBlueprintPHIDs(array $phids) {
$this->blueprintPHIDs = $phids; $this->blueprintPHIDs = $phids;
@ -21,6 +22,11 @@ final class DrydockLogQuery extends DrydockQuery {
return $this; return $this;
} }
public function withOperationPHIDs(array $phids) {
$this->operationPHIDs = $phids;
return $this;
}
public function newResultObject() { public function newResultObject() {
return new DrydockLog(); return new DrydockLog();
} }
@ -93,6 +99,27 @@ final class DrydockLogQuery extends DrydockQuery {
$log->attachLease($lease); $log->attachLease($lease);
} }
$operation_phids = array_filter(mpull($logs, 'getOperationPHID'));
if ($operation_phids) {
$operations = id(new DrydockRepositoryOperationQuery())
->setParentQuery($this)
->setViewer($this->getViewer())
->withPHIDs($operation_phids)
->execute();
$operations = mpull($operations, null, 'getPHID');
} else {
$operations = array();
}
foreach ($logs as $key => $log) {
$operation = null;
$operation_phid = $log->getOperationPHID();
if ($operation_phid) {
$operation = idx($operations, $operation_phid);
}
$log->attachOperation($operation);
}
return $logs; return $logs;
} }
@ -120,6 +147,13 @@ final class DrydockLogQuery extends DrydockQuery {
$this->leasePHIDs); $this->leasePHIDs);
} }
if ($this->operationPHIDs !== null) {
$where[] = qsprintf(
$conn,
'operationPHID IN (%Ls)',
$this->operationPHIDs);
}
return $where; return $where;
} }

View file

@ -5,6 +5,7 @@ final class DrydockLogSearchEngine extends PhabricatorApplicationSearchEngine {
private $blueprint; private $blueprint;
private $resource; private $resource;
private $lease; private $lease;
private $operation;
public function setBlueprint(DrydockBlueprint $blueprint) { public function setBlueprint(DrydockBlueprint $blueprint) {
$this->blueprint = $blueprint; $this->blueprint = $blueprint;
@ -33,6 +34,15 @@ final class DrydockLogSearchEngine extends PhabricatorApplicationSearchEngine {
return $this->lease; return $this->lease;
} }
public function setOperation(DrydockRepositoryOperation $operation) {
$this->operation = $operation;
return $this;
}
public function getOperation() {
return $this->operation;
}
public function canUseInPanelContext() { public function canUseInPanelContext() {
// Prevent use on Dashboard panels since all log queries currently need a // Prevent use on Dashboard panels since all log queries currently need a
// parent object and these don't seem particularly useful in any case. // parent object and these don't seem particularly useful in any case.
@ -65,6 +75,11 @@ final class DrydockLogSearchEngine extends PhabricatorApplicationSearchEngine {
$query->withLeasePHIDs(array($lease->getPHID())); $query->withLeasePHIDs(array($lease->getPHID()));
} }
$operation = $this->getOperation();
if ($operation) {
$query->withOperationPHIDs(array($operation->getPHID()));
}
return $query; return $query;
} }
@ -97,9 +112,15 @@ final class DrydockLogSearchEngine extends PhabricatorApplicationSearchEngine {
return "/drydock/lease/{$id}/logs/{$path}"; return "/drydock/lease/{$id}/logs/{$path}";
} }
$operation = $this->getOperation();
if ($operation) {
$id = $operation->getID();
return "/drydock/operation/{$id}/logs/{$path}";
}
throw new Exception( throw new Exception(
pht( pht(
'Search engine has no blueprint, resource, or lease.')); 'Search engine has no blueprint, resource, lease, or operation.'));
} }
protected function getBuiltinQueryNames() { protected function getBuiltinQueryNames() {

View file

@ -6,6 +6,7 @@ final class DrydockLog extends DrydockDAO
protected $blueprintPHID; protected $blueprintPHID;
protected $resourcePHID; protected $resourcePHID;
protected $leasePHID; protected $leasePHID;
protected $operationPHID;
protected $epoch; protected $epoch;
protected $type; protected $type;
protected $data = array(); protected $data = array();
@ -13,6 +14,7 @@ final class DrydockLog extends DrydockDAO
private $blueprint = self::ATTACHABLE; private $blueprint = self::ATTACHABLE;
private $resource = self::ATTACHABLE; private $resource = self::ATTACHABLE;
private $lease = self::ATTACHABLE; private $lease = self::ATTACHABLE;
private $operation = self::ATTACHABLE;
protected function getConfiguration() { protected function getConfiguration() {
return array( return array(
@ -24,6 +26,7 @@ final class DrydockLog extends DrydockDAO
'blueprintPHID' => 'phid?', 'blueprintPHID' => 'phid?',
'resourcePHID' => 'phid?', 'resourcePHID' => 'phid?',
'leasePHID' => 'phid?', 'leasePHID' => 'phid?',
'operationPHID' => 'phid?',
'type' => 'text64', 'type' => 'text64',
), ),
self::CONFIG_KEY_SCHEMA => array( self::CONFIG_KEY_SCHEMA => array(
@ -36,6 +39,9 @@ final class DrydockLog extends DrydockDAO
'key_lease' => array( 'key_lease' => array(
'columns' => array('leasePHID', 'type'), 'columns' => array('leasePHID', 'type'),
), ),
'key_operation' => array(
'columns' => array('operationPHID', 'type'),
),
'epoch' => array( 'epoch' => array(
'columns' => array('epoch'), 'columns' => array('epoch'),
), ),
@ -70,6 +76,16 @@ final class DrydockLog extends DrydockDAO
return $this->assertAttached($this->lease); return $this->assertAttached($this->lease);
} }
public function attachOperation(
DrydockRepositoryOperation $operation = null) {
$this->operation = $operation;
return $this;
}
public function getOperation() {
return $this->assertAttached($this->operation);
}
public function isComplete() { public function isComplete() {
if ($this->getBlueprintPHID() && !$this->getBlueprint()) { if ($this->getBlueprintPHID() && !$this->getBlueprint()) {
return false; return false;
@ -83,6 +99,10 @@ final class DrydockLog extends DrydockDAO
return false; return false;
} }
if ($this->getOperationPHID() && !$this->getOperation()) {
return false;
}
return true; return true;
} }
@ -108,8 +128,8 @@ final class DrydockLog extends DrydockDAO
public function describeAutomaticCapability($capability) { public function describeAutomaticCapability($capability) {
return pht( return pht(
'To view log details, you must be able to view the associated '. 'To view log details, you must be able to view all associated '.
'blueprint, resource and lease.'); 'blueprints, resources, leases, and repository operations.');
} }
} }

View file

@ -25,6 +25,7 @@ final class DrydockRepositoryOperation extends DrydockDAO
private $repository = self::ATTACHABLE; private $repository = self::ATTACHABLE;
private $object = self::ATTACHABLE; private $object = self::ATTACHABLE;
private $implementation = self::ATTACHABLE; private $implementation = self::ATTACHABLE;
private $workingCopyLease = self::ATTACHABLE;
public static function initializeNewOperation( public static function initializeNewOperation(
DrydockRepositoryOperationType $op) { DrydockRepositoryOperationType $op) {
@ -90,6 +91,19 @@ final class DrydockRepositoryOperation extends DrydockDAO
return $this->implementation; return $this->implementation;
} }
public function getWorkingCopyLease() {
return $this->assertAttached($this->workingCopyLease);
}
public function attachWorkingCopyLease(DrydockLease $lease) {
$this->workingCopyLease = $lease;
return $this;
}
public function hasWorkingCopyLease() {
return ($this->workingCopyLease !== self::ATTACHABLE);
}
public function getProperty($key, $default = null) { public function getProperty($key, $default = null) {
return idx($this->properties, $key, $default); return idx($this->properties, $key, $default);
} }
@ -189,6 +203,37 @@ final class DrydockRepositoryOperation extends DrydockDAO
return $this->getProperty('exec.workingcopy.error'); return $this->getProperty('exec.workingcopy.error');
} }
public function logText($text) {
return $this->logEvent(
DrydockTextLogType::LOGCONST,
array(
'text' => $text,
));
}
public function logEvent($type, array $data = array()) {
$log = id(new DrydockLog())
->setEpoch(PhabricatorTime::getNow())
->setType($type)
->setData($data);
$log->setOperationPHID($this->getPHID());
if ($this->hasWorkingCopyLease()) {
$lease = $this->getWorkingCopyLease();
$log->setLeasePHID($lease->getPHID());
$resource_phid = $lease->getResourcePHID();
if ($resource_phid) {
$resource = $lease->getResource();
$log->setResourcePHID($resource->getPHID());
$log->setBlueprintPHID($resource->getBlueprintPHID());
}
}
return $log->save();
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */ /* -( PhabricatorPolicyInterface )----------------------------------------- */

View file

@ -3,6 +3,46 @@
final class DrydockLogListView extends AphrontView { final class DrydockLogListView extends AphrontView {
private $logs; private $logs;
private $hideBlueprints;
private $hideResources;
private $hideLeases;
private $hideOperations;
public function setHideBlueprints($hide_blueprints) {
$this->hideBlueprints = $hide_blueprints;
return $this;
}
public function getHideBlueprints() {
return $this->hideBlueprints;
}
public function setHideResources($hide_resources) {
$this->hideResources = $hide_resources;
return $this;
}
public function getHideResources() {
return $this->hideResources;
}
public function setHideLeases($hide_leases) {
$this->hideLeases = $hide_leases;
return $this;
}
public function getHideLeases() {
return $this->hideLeases;
}
public function setHideOperations($hide_operations) {
$this->hideOperations = $hide_operations;
return $this;
}
public function getHideOperations() {
return $this->hideOperations;
}
public function setLogs(array $logs) { public function setLogs(array $logs) {
assert_instances_of($logs, 'DrydockLog'); assert_instances_of($logs, 'DrydockLog');
@ -41,6 +81,13 @@ final class DrydockLogListView extends AphrontView {
$lease = null; $lease = null;
} }
$operation_phid = $log->getOperationPHID();
if ($operation_phid) {
$operation = $viewer->renderHandle($operation_phid);
} else {
$operation = null;
}
if ($log->isComplete()) { if ($log->isComplete()) {
$type_key = $log->getType(); $type_key = $log->getType();
if (isset($types[$type_key])) { if (isset($types[$type_key])) {
@ -72,6 +119,7 @@ final class DrydockLogListView extends AphrontView {
$blueprint, $blueprint,
$resource, $resource,
$lease, $lease,
$operation,
id(new PHUIIconView())->setIcon($icon), id(new PHUIIconView())->setIcon($icon),
$type, $type,
$data, $data,
@ -86,16 +134,25 @@ final class DrydockLogListView extends AphrontView {
pht('Blueprint'), pht('Blueprint'),
pht('Resource'), pht('Resource'),
pht('Lease'), pht('Lease'),
pht('Operation'),
null, null,
pht('Type'), pht('Type'),
pht('Data'), pht('Data'),
pht('Date'), pht('Date'),
)) ))
->setColumnVisibility(
array(
!$this->getHideBlueprints(),
!$this->getHideResources(),
!$this->getHideLeases(),
!$this->getHideOperations(),
))
->setColumnClasses( ->setColumnClasses(
array( array(
'', '',
'', '',
'', '',
'',
'icon', 'icon',
'', '',
'wide', 'wide',

View file

@ -59,6 +59,10 @@ final class DrydockRepositoryOperationUpdateWorker
// No matter what happens here, destroy the lease away once we're done. // No matter what happens here, destroy the lease away once we're done.
$lease->setReleaseOnDestruction(true); $lease->setReleaseOnDestruction(true);
$operation->attachWorkingCopyLease($lease);
$operation->logEvent(DrydockOperationWorkLogType::LOGCONST);
$operation->applyOperation($interface); $operation->applyOperation($interface);
} catch (PhabricatorWorkerYieldException $ex) { } catch (PhabricatorWorkerYieldException $ex) {

View file

@ -71,7 +71,7 @@ final class PhabricatorOwnersDetailController
'package' => $package->getPHID(), 'package' => $package->getPHID(),
)); ));
$status_concern = PhabricatorAuditCommitStatusConstants::CONCERN_RAISED; $status_concern = DiffusionCommitAuditStatus::CONCERN_RAISED;
$attention_commits = id(new DiffusionCommitQuery()) $attention_commits = id(new DiffusionCommitQuery())
->setViewer($request->getUser()) ->setViewer($request->getUser())

View file

@ -306,6 +306,14 @@ final class PhabricatorUser
return ($this->session !== self::ATTACHABLE); return ($this->session !== self::ATTACHABLE);
} }
public function hasHighSecuritySession() {
if (!$this->hasSession()) {
return false;
}
return $this->getSession()->isHighSecuritySession();
}
private function generateConduitCertificate() { private function generateConduitCertificate() {
return Filesystem::readRandomCharacters(255); return Filesystem::readRandomCharacters(255);
} }

View file

@ -63,6 +63,9 @@ final class PhabricatorPhrictionApplication extends PhabricatorApplication {
'preview/(?P<slug>.*/)' => 'PhrictionMarkupPreviewController', 'preview/(?P<slug>.*/)' => 'PhrictionMarkupPreviewController',
'diff/(?P<id>[1-9]\d*)/' => 'PhrictionDiffController', 'diff/(?P<id>[1-9]\d*)/' => 'PhrictionDiffController',
$this->getEditRoutePattern('document/edit/')
=> 'PhrictionEditEngineController',
), ),
); );
} }

View file

@ -95,7 +95,7 @@ final class PhrictionDiffController extends PhrictionController {
$navigation_table = null; $navigation_table = null;
if ($l + 1 == $r) { if ($l + 1 == $r) {
$nav_l = ($l > 1); $nav_l = ($l > 1);
$nav_r = ($r != $current->getVersion()); $nav_r = ($r != $document->getMaxVersion());
$uri = $request->getRequestURI(); $uri = $request->getRequestURI();
@ -191,30 +191,28 @@ final class PhrictionDiffController extends PhrictionController {
PhrictionChangeType::CHANGE_MOVE_AWAY => true, // Plain silly PhrictionChangeType::CHANGE_MOVE_AWAY => true, // Plain silly
PhrictionChangeType::CHANGE_STUB => true, // Utterly silly PhrictionChangeType::CHANGE_STUB => true, // Utterly silly
); );
if (isset($hidden_statuses[$content->getChangeType()])) { if (isset($hidden_statuses[$content->getChangeType()])) {
// Don't show an edit/revert button for changes which deleted, moved or // Don't show an edit/revert button for changes which deleted, moved or
// stubbed the content since it's silly. // stubbed the content since it's silly.
return null; return null;
} }
if ($content->getID() == $current->getID()) { if ($version == $current->getVersion()) {
return phutil_tag( $label = pht('Edit Current Version %s...', new PhutilNumber($version));
'a', } else if ($version < $current->getVersion()) {
array( $label = pht('Edit Older Version %s...', new PhutilNumber($version));
'href' => '/phriction/edit/'.$document_id.'/', } else {
'class' => 'button button-grey', $label = pht('Edit Draft Version %s...', new PhutilNumber($version));
),
pht('Edit Current Version'));
} }
return phutil_tag( return phutil_tag(
'a', 'a',
array( array(
'href' => '/phriction/edit/'.$document_id.'/?revert='.$version, 'href' => '/phriction/edit/'.$document_id.'/?revert='.$version,
'class' => 'button button-grey', 'class' => 'button button-grey',
), ),
pht('Revert to Version %s...', $version)); $label);
} }
private function renderComparisonTable(array $content) { private function renderComparisonTable(array $content) {

View file

@ -186,6 +186,35 @@ final class PhrictionDocumentController
); );
} else { } else {
$content = $document->getContent(); $content = $document->getContent();
if ($content->getVersion() < $document->getMaxVersion()) {
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$document,
PhabricatorPolicyCapability::CAN_EDIT);
if ($can_edit) {
$document_uri = new PhutilURI($document->getURI());
$draft_uri = $document_uri->alter('v', $document->getMaxVersion());
$draft_link = phutil_tag(
'a',
array(
'href' => $draft_uri,
),
pht('View Draft Version'));
$draft_link = phutil_tag('strong', array(), $draft_link);
$version_note = id(new PHUIInfoView())
->setSeverity(PHUIInfoView::SEVERITY_NOTICE)
->appendChild(
array(
pht('This document has unpublished draft changes.'),
' ',
$draft_link,
));
}
}
} }
$page_title = $content->getTitle(); $page_title = $content->getTitle();
@ -348,6 +377,17 @@ final class PhrictionDocumentController
$page_content->setCurtain($curtain); $page_content->setCurtain($curtain);
} }
$timeline = $this->buildTransactionTimeline(
$document,
new PhrictionTransactionQuery());
$edit_engine = id(new PhrictionDocumentEditEngine())
->setViewer($viewer)
->setTargetObject($document);
$comment_view = $edit_engine
->buildEditEngineCommentView($document);
return $this->newPage() return $this->newPage()
->setTitle($page_title) ->setTitle($page_title)
->setCrumbs($crumbs) ->setCrumbs($crumbs)
@ -356,7 +396,16 @@ final class PhrictionDocumentController
array( array(
$page_content, $page_content,
$prop_list, $prop_list,
$children, phutil_tag(
'div',
array(
'class' => 'phui-document-view-pro-box',
),
array(
$children,
$timeline,
$comment_view,
)),
)); ));
} }
@ -427,22 +476,31 @@ final class PhrictionDocumentController
if ($is_draft) { if ($is_draft) {
$publish_name = pht('Publish Draft'); $publish_name = pht('Publish Draft');
} else { } else {
$publish_name = pht('Publish Revert'); $publish_name = pht('Publish Older Version');
}
// If you're looking at the current version; and it's an unpublished
// draft; and you can publish it, add a UI hint that this might be an
// interesting action to take.
$hint_publish = false;
if ($is_draft) {
if ($can_publish) {
if ($document->getMaxVersion() == $content->getVersion()) {
$hint_publish = true;
}
}
} }
$publish_uri = "/phriction/publish/{$id}/{$content_id}/"; $publish_uri = "/phriction/publish/{$id}/{$content_id}/";
if (PhabricatorEnv::getEnvConfig('phabricator.show-prototypes')) { $curtain->addAction(
$publish_name = pht('Publish (Prototype!)'); id(new PhabricatorActionView())
->setName($publish_name)
$curtain->addAction( ->setIcon('fa-upload')
id(new PhabricatorActionView()) ->setSelected($hint_publish)
->setName($publish_name) ->setDisabled(!$can_publish)
->setIcon('fa-upload') ->setWorkflow(true)
->setDisabled(!$can_publish) ->setHref($publish_uri));
->setWorkflow(true)
->setHref($publish_uri));
}
if ($document->getStatus() == PhrictionDocumentStatus::STATUS_EXISTS) { if ($document->getStatus() == PhrictionDocumentStatus::STATUS_EXISTS) {
$curtain->addAction( $curtain->addAction(
@ -600,7 +658,7 @@ final class PhrictionDocumentController
), ),
$list))); $list)));
return phutil_tag_div('phui-document-view-pro-box', $box); return $box;
} }
private function renderChildDocumentLink(array $info) { private function renderChildDocumentLink(array $info) {

View file

@ -72,43 +72,6 @@ final class PhrictionEditController
} }
} }
if ($request->getBool('nodraft')) {
$draft = null;
$draft_key = null;
} else {
if ($document->getPHID()) {
$draft_key = $document->getPHID().':'.$content->getVersion();
} else {
$draft_key = 'phriction:'.$content->getSlug();
}
$draft = id(new PhabricatorDraft())->loadOneWhere(
'authorPHID = %s AND draftKey = %s',
$viewer->getPHID(),
$draft_key);
}
if ($draft &&
strlen($draft->getDraft()) &&
($draft->getDraft() != $content->getContent())) {
$content_text = $draft->getDraft();
$discard = phutil_tag(
'a',
array(
'href' => $request->getRequestURI()->alter('nodraft', true),
),
pht('discard this draft'));
$draft_note = new PHUIInfoView();
$draft_note->setSeverity(PHUIInfoView::SEVERITY_NOTICE);
$draft_note->setTitle(pht('Recovered Draft'));
$draft_note->appendChild(
pht('Showing a saved draft of your edits, you can %s.', $discard));
} else {
$content_text = $content->getContent();
$draft_note = null;
}
require_celerity_resource('phriction-document-css'); require_celerity_resource('phriction-document-css');
$e_title = true; $e_title = true;
@ -131,7 +94,15 @@ final class PhrictionEditController
$v_space = $document->getSpacePHID(); $v_space = $document->getSpacePHID();
$content_text = $content->getContent();
$is_draft_mode = ($document->getContent()->getVersion() != $max_version);
if ($request->isFormPost()) { if ($request->isFormPost()) {
if ($is_new) {
$save_as_draft = false;
} else {
$save_as_draft = ($is_draft_mode || $request->getExists('draft'));
}
$title = $request->getStr('title'); $title = $request->getStr('title');
$content_text = $request->getStr('content'); $content_text = $request->getStr('content');
@ -143,13 +114,19 @@ final class PhrictionEditController
$v_projects = $request->getArr('projects'); $v_projects = $request->getArr('projects');
$v_space = $request->getStr('spacePHID'); $v_space = $request->getStr('spacePHID');
if ($save_as_draft) {
$edit_type = PhrictionDocumentDraftTransaction::TRANSACTIONTYPE;
} else {
$edit_type = PhrictionDocumentContentTransaction::TRANSACTIONTYPE;
}
$xactions = array(); $xactions = array();
$xactions[] = id(new PhrictionTransaction()) $xactions[] = id(new PhrictionTransaction())
->setTransactionType(PhrictionDocumentTitleTransaction::TRANSACTIONTYPE) ->setTransactionType(PhrictionDocumentTitleTransaction::TRANSACTIONTYPE)
->setNewValue($title); ->setNewValue($title);
$xactions[] = id(new PhrictionTransaction()) $xactions[] = id(new PhrictionTransaction())
->setTransactionType( ->setTransactionType($edit_type)
PhrictionDocumentContentTransaction::TRANSACTIONTYPE)
->setNewValue($content_text); ->setNewValue($content_text);
$xactions[] = id(new PhrictionTransaction()) $xactions[] = id(new PhrictionTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY) ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY)
@ -181,11 +158,15 @@ final class PhrictionEditController
try { try {
$editor->applyTransactions($document, $xactions); $editor->applyTransactions($document, $xactions);
if ($draft) { $uri = PhrictionDocument::getSlugURI($document->getSlug());
$draft->delete(); $uri = new PhutilURI($uri);
// If the user clicked "Save as Draft", take them to the draft, not
// to the current published page.
if ($save_as_draft) {
$uri = $uri->alter('v', $document->getMaxVersion());
} }
$uri = PhrictionDocument::getSlugURI($document->getSlug());
return id(new AphrontRedirectResponse())->setURI($uri); return id(new AphrontRedirectResponse())->setURI($uri);
} catch (PhabricatorApplicationTransactionValidationException $ex) { } catch (PhabricatorApplicationTransactionValidationException $ex) {
$validation_exception = $ex; $validation_exception = $ex;
@ -215,7 +196,7 @@ final class PhrictionEditController
if ($overwrite) { if ($overwrite) {
$submit_button = pht('Overwrite Changes'); $submit_button = pht('Overwrite Changes');
} else { } else {
$submit_button = pht('Save Changes'); $submit_button = pht('Save and Publish');
} }
} else { } else {
$submit_button = pht('Create Document'); $submit_button = pht('Create Document');
@ -235,11 +216,9 @@ final class PhrictionEditController
$view_capability = PhabricatorPolicyCapability::CAN_VIEW; $view_capability = PhabricatorPolicyCapability::CAN_VIEW;
$edit_capability = PhabricatorPolicyCapability::CAN_EDIT; $edit_capability = PhabricatorPolicyCapability::CAN_EDIT;
$form = id(new AphrontFormView()) $form = id(new AphrontFormView())
->setUser($viewer) ->setUser($viewer)
->addHiddenInput('slug', $document->getSlug()) ->addHiddenInput('slug', $document->getSlug())
->addHiddenInput('nodraft', $request->getBool('nodraft'))
->addHiddenInput('contentVersion', $max_version) ->addHiddenInput('contentVersion', $max_version)
->addHiddenInput('overwrite', $overwrite) ->addHiddenInput('overwrite', $overwrite)
->appendChild( ->appendChild(
@ -293,11 +272,31 @@ final class PhrictionEditController
->setLabel(pht('Edit Notes')) ->setLabel(pht('Edit Notes'))
->setValue($notes) ->setValue($notes)
->setError(null) ->setError(null)
->setName('description')) ->setName('description'));
->appendChild(
if ($is_draft_mode) {
$form->appendControl(
id(new AphrontFormSubmitControl()) id(new AphrontFormSubmitControl())
->addCancelButton($cancel_uri) ->addCancelButton($cancel_uri)
->setValue($submit_button)); ->setValue(pht('Save Draft')));
} else {
$submit = id(new AphrontFormSubmitControl());
if (!$is_new) {
$draft_button = id(new PHUIButtonView())
->setTag('input')
->setName('draft')
->setText(pht('Save as Draft'))
->setColor(PHUIButtonView::GREEN);
$submit->addButton($draft_button);
}
$submit
->addCancelButton($cancel_uri)
->setValue($submit_button);
$form->appendControl($submit);
}
$form_box = id(new PHUIObjectBoxView()) $form_box = id(new PHUIObjectBoxView())
->setHeaderText($page_title) ->setHeaderText($page_title)
@ -325,7 +324,6 @@ final class PhrictionEditController
$view = id(new PHUITwoColumnView()) $view = id(new PHUITwoColumnView())
->setFooter( ->setFooter(
array( array(
$draft_note,
$form_box, $form_box,
$preview, $preview,
)); ));

View file

@ -0,0 +1,14 @@
<?php
final class PhrictionEditEngineController
extends PhrictionController {
public function handleRequest(AphrontRequest $request) {
// NOTE: For now, this controller is only used to handle comments.
return id(new PhrictionDocumentEditEngine())
->setController($this)
->buildResponse();
}
}

View file

@ -63,7 +63,7 @@ final class PhrictionPublishController
} }
if ($content->getVersion() < $document->getContent()->getVersion()) { if ($content->getVersion() < $document->getContent()->getVersion()) {
$title = pht('Revert Document?'); $title = pht('Publish Older Version?');
$body = pht( $body = pht(
'Revert the published version of this document to an older '. 'Revert the published version of this document to an older '.
'version?'); 'version?');

View file

@ -0,0 +1,85 @@
<?php
final class PhrictionDocumentEditEngine
extends PhabricatorEditEngine {
const ENGINECONST = 'phriction.document';
public function isEngineConfigurable() {
return false;
}
public function getEngineName() {
return pht('Phriction Document');
}
public function getSummaryHeader() {
return pht('Edit Phriction Document Configurations');
}
public function getSummaryText() {
return pht('This engine is used to edit Phriction documents.');
}
public function getEngineApplicationClass() {
return 'PhabricatorPhrictionApplication';
}
protected function newEditableObject() {
$viewer = $this->getViewer();
return PhrictionDocument::initializeNewDocument(
$viewer,
'/');
}
protected function newObjectQuery() {
return id(new PhrictionDocumentQuery())
->needContent(true);
}
protected function getObjectCreateTitleText($object) {
return pht('Create Document');
}
protected function getObjectCreateButtonText($object) {
return pht('Create Document');
}
protected function getObjectEditTitleText($object) {
return pht('Edit Document: %s', $object->getContent()->getTitle());
}
protected function getObjectEditShortText($object) {
return pht('Edit Document');
}
protected function getObjectCreateShortText() {
return pht('Create Document');
}
protected function getObjectName() {
return pht('Document');
}
protected function getEditorURI() {
return '/phriction/document/edit/';
}
protected function getObjectCreateCancelURI($object) {
return '/phriction/document/';
}
protected function getObjectViewURI($object) {
return $object->getURI();
}
protected function getCreateNewObjectPolicy() {
// NOTE: For now, this engine is only to support commenting.
return PhabricatorPolicies::POLICY_NOONE;
}
protected function buildCustomEditFields($object) {
return array();
}
}

View file

@ -74,6 +74,21 @@ final class PhrictionTransactionEditor
return $this; return $this;
} }
public function setShouldPublishContent(
PhrictionDocument $object,
$publish) {
if ($publish) {
$content_phid = $this->getNewContent()->getPHID();
} else {
$content_phid = $this->getOldContent()->getPHID();
}
$object->setContentPHID($content_phid);
return $this;
}
public function getEditorApplicationClass() { public function getEditorApplicationClass() {
return 'PhabricatorPhrictionApplication'; return 'PhabricatorPhrictionApplication';
} }

View file

@ -1,87 +1,25 @@
<?php <?php
final class PhrictionDocumentContentTransaction final class PhrictionDocumentContentTransaction
extends PhrictionDocumentVersionTransaction { extends PhrictionDocumentEditTransaction {
const TRANSACTIONTYPE = 'content'; const TRANSACTIONTYPE = 'content';
public function generateOldValue($object) {
if ($this->getEditor()->getIsNewObject()) {
return null;
}
return $object->getContent()->getContent();
}
public function generateNewValue($object, $value) {
return $value;
}
public function applyInternalEffects($object, $value) { public function applyInternalEffects($object, $value) {
parent::applyInternalEffects($object, $value);
$object->setStatus(PhrictionDocumentStatus::STATUS_EXISTS); $object->setStatus(PhrictionDocumentStatus::STATUS_EXISTS);
$content = $this->getNewDocumentContent($object); $this->getEditor()->setShouldPublishContent($object, true);
$content->setContent($value);
}
public function shouldHide() {
if ($this->getOldValue() === null) {
return true;
} else {
return false;
}
}
public function getActionStrength() {
return 1.3;
}
public function getActionName() {
return pht('Edited');
}
public function getTitle() {
return pht(
'%s edited the content of this document.',
$this->renderAuthor());
}
public function getTitleForFeed() {
return pht(
'%s edited the content of %s.',
$this->renderAuthor(),
$this->renderObject());
}
public function hasChangeDetailView() {
return true;
}
public function getMailDiffSectionHeader() {
return pht('CHANGES TO DOCUMENT CONTENT');
}
public function newChangeDetailView() {
$viewer = $this->getViewer();
return id(new PhabricatorApplicationTransactionTextDiffDetailView())
->setViewer($viewer)
->setOldText($this->getOldValue())
->setNewText($this->getNewValue());
}
public function newRemarkupChanges() {
$changes = array();
$changes[] = $this->newRemarkupChange()
->setOldValue($this->getOldValue())
->setNewValue($this->getNewValue());
return $changes;
} }
public function validateTransactions($object, array $xactions) { public function validateTransactions($object, array $xactions) {
$errors = array(); $errors = array();
// NOTE: This is slightly different from the draft validation. Here,
// we're validating that: you can't edit away a document; and you can't
// create an empty document.
$content = $object->getContent()->getContent(); $content = $object->getContent()->getContent();
if ($this->isEmptyTextTransaction($content, $xactions)) { if ($this->isEmptyTextTransaction($content, $xactions)) {
$errors[] = $this->newRequiredError( $errors[] = $this->newRequiredError(

View file

@ -0,0 +1,39 @@
<?php
final class PhrictionDocumentDraftTransaction
extends PhrictionDocumentEditTransaction {
const TRANSACTIONTYPE = 'draft';
public function applyInternalEffects($object, $value) {
parent::applyInternalEffects($object, $value);
$this->getEditor()->setShouldPublishContent($object, false);
}
public function shouldHideForFeed() {
return true;
}
public function validateTransactions($object, array $xactions) {
$errors = array();
// NOTE: We're only validating that you can't edit a document down to
// nothing in a draft transaction. Alone, this doesn't prevent you from
// creating a document with no content. The content transaction has
// validation for that.
if (!$xactions) {
return $errors;
}
$content = $object->getContent()->getContent();
if ($this->isEmptyTextTransaction($content, $xactions)) {
$errors[] = $this->newRequiredError(
pht('Documents must have content.'));
}
return $errors;
}
}

View file

@ -0,0 +1,82 @@
<?php
abstract class PhrictionDocumentEditTransaction
extends PhrictionDocumentVersionTransaction {
public function generateOldValue($object) {
if ($this->getEditor()->getIsNewObject()) {
return null;
}
// NOTE: We want to get the newest version of the content here, regardless
// of whether it's published or not.
$actor = $this->getActor();
return id(new PhrictionContentQuery())
->setViewer($actor)
->withDocumentPHIDs(array($object->getPHID()))
->setOrder('newest')
->setLimit(1)
->executeOne()
->getContent();
}
public function generateNewValue($object, $value) {
return $value;
}
public function applyInternalEffects($object, $value) {
$content = $this->getNewDocumentContent($object);
$content->setContent($value);
}
public function getActionStrength() {
return 1.3;
}
public function getActionName() {
return pht('Edited');
}
public function getTitle() {
return pht(
'%s edited the content of this document.',
$this->renderAuthor());
}
public function getTitleForFeed() {
return pht(
'%s edited the content of %s.',
$this->renderAuthor(),
$this->renderObject());
}
public function getMailDiffSectionHeader() {
return pht('CHANGES TO DOCUMENT CONTENT');
}
public function hasChangeDetailView() {
return true;
}
public function newChangeDetailView() {
$viewer = $this->getViewer();
return id(new PhabricatorApplicationTransactionTextDiffDetailView())
->setViewer($viewer)
->setOldText($this->getOldValue())
->setNewText($this->getNewValue());
}
public function newRemarkupChanges() {
$changes = array();
$changes[] = $this->newRemarkupChange()
->setOldValue($this->getOldValue())
->setNewValue($this->getNewValue());
return $changes;
}
}

View file

@ -25,9 +25,8 @@ final class PhabricatorRepositoryCommit
protected $committerIdentityPHID; protected $committerIdentityPHID;
protected $commitIdentifier; protected $commitIdentifier;
protected $epoch; protected $epoch;
protected $mailKey;
protected $authorPHID; protected $authorPHID;
protected $auditStatus = PhabricatorAuditCommitStatusConstants::NONE; protected $auditStatus = DiffusionCommitAuditStatus::NONE;
protected $summary = ''; protected $summary = '';
protected $importStatus = 0; protected $importStatus = 0;
@ -116,11 +115,10 @@ final class PhabricatorRepositoryCommit
self::CONFIG_TIMESTAMPS => false, self::CONFIG_TIMESTAMPS => false,
self::CONFIG_COLUMN_SCHEMA => array( self::CONFIG_COLUMN_SCHEMA => array(
'commitIdentifier' => 'text40', 'commitIdentifier' => 'text40',
'mailKey' => 'bytes20',
'authorPHID' => 'phid?', 'authorPHID' => 'phid?',
'authorIdentityPHID' => 'phid?', 'authorIdentityPHID' => 'phid?',
'committerIdentityPHID' => 'phid?', 'committerIdentityPHID' => 'phid?',
'auditStatus' => 'uint32', 'auditStatus' => 'text32',
'summary' => 'text255', 'summary' => 'text255',
'importStatus' => 'uint32', 'importStatus' => 'uint32',
), ),
@ -321,13 +319,6 @@ final class PhabricatorRepositoryCommit
return mpull($audits, 'getAuditorPHID'); return mpull($audits, 'getAuditorPHID');
} }
public function save() {
if (!$this->mailKey) {
$this->mailKey = Filesystem::readRandomCharacters(20);
}
return parent::save();
}
public function delete() { public function delete() {
$data = $this->loadCommitData(); $data = $this->loadCommitData();
$audits = id(new PhabricatorRepositoryAuditRequest()) $audits = id(new PhabricatorRepositoryAuditRequest())
@ -381,27 +372,24 @@ final class PhabricatorRepositoryCommit
} }
} }
$current_status = $this->getAuditStatus();
$status_verify = PhabricatorAuditCommitStatusConstants::NEEDS_VERIFICATION;
if ($any_concern) { if ($any_concern) {
if ($current_status == $status_verify) { if ($this->isAuditStatusNeedsVerification()) {
// If the change is in "Needs Verification", we keep it there as // If the change is in "Needs Verification", we keep it there as
// long as any auditors still have concerns. // long as any auditors still have concerns.
$status = $status_verify; $status = DiffusionCommitAuditStatus::NEEDS_VERIFICATION;
} else { } else {
$status = PhabricatorAuditCommitStatusConstants::CONCERN_RAISED; $status = DiffusionCommitAuditStatus::CONCERN_RAISED;
} }
} else if ($any_accept) { } else if ($any_accept) {
if ($any_need) { if ($any_need) {
$status = PhabricatorAuditCommitStatusConstants::PARTIALLY_AUDITED; $status = DiffusionCommitAuditStatus::PARTIALLY_AUDITED;
} else { } else {
$status = PhabricatorAuditCommitStatusConstants::FULLY_AUDITED; $status = DiffusionCommitAuditStatus::AUDITED;
} }
} else if ($any_need) { } else if ($any_need) {
$status = PhabricatorAuditCommitStatusConstants::NEEDS_AUDIT; $status = DiffusionCommitAuditStatus::NEEDS_AUDIT;
} else { } else {
$status = PhabricatorAuditCommitStatusConstants::NONE; $status = DiffusionCommitAuditStatus::NONE;
} }
return $this->setAuditStatus($status); return $this->setAuditStatus($status);
@ -532,7 +520,31 @@ final class PhabricatorRepositoryCommit
public function getAuditStatusObject() { public function getAuditStatusObject() {
$status = $this->getAuditStatus(); $status = $this->getAuditStatus();
return PhabricatorAuditCommitStatusConstants::newForLegacyStatus($status); return DiffusionCommitAuditStatus::newForStatus($status);
}
public function isAuditStatusNoAudit() {
return $this->getAuditStatusObject()->isNoAudit();
}
public function isAuditStatusNeedsAudit() {
return $this->getAuditStatusObject()->isNeedsAudit();
}
public function isAuditStatusConcernRaised() {
return $this->getAuditStatusObject()->isConcernRaised();
}
public function isAuditStatusNeedsVerification() {
return $this->getAuditStatusObject()->isNeedsVerification();
}
public function isAuditStatusPartiallyAudited() {
return $this->getAuditStatusObject()->isPartiallyAudited();
}
public function isAuditStatusAudited() {
return $this->getAuditStatusObject()->isAudited();
} }
/* -( PhabricatorPolicyInterface )----------------------------------------- */ /* -( PhabricatorPolicyInterface )----------------------------------------- */
@ -584,7 +596,6 @@ final class PhabricatorRepositoryCommit
'phid' => $this->getPHID(), 'phid' => $this->getPHID(),
'commitIdentifier' => $this->getCommitIdentifier(), 'commitIdentifier' => $this->getCommitIdentifier(),
'epoch' => $this->getEpoch(), 'epoch' => $this->getEpoch(),
'mailKey' => $this->getMailKey(),
'authorPHID' => $this->getAuthorPHID(), 'authorPHID' => $this->getAuthorPHID(),
'auditStatus' => $this->getAuditStatus(), 'auditStatus' => $this->getAuditStatus(),
'summary' => $this->getSummary(), 'summary' => $this->getSummary(),
@ -830,16 +841,110 @@ final class PhabricatorRepositoryCommit
->setKey('identifier') ->setKey('identifier')
->setType('string') ->setType('string')
->setDescription(pht('The commit identifier.')), ->setDescription(pht('The commit identifier.')),
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('repositoryPHID')
->setType('phid')
->setDescription(pht('The repository this commit belongs to.')),
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('author')
->setType('map<string, wild>')
->setDescription(pht('Information about the commit author.')),
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('committer')
->setType('map<string, wild>')
->setDescription(pht('Information about the committer.')),
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('isImported')
->setType('bool')
->setDescription(pht('True if the commit is fully imported.')),
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('isUnreachable')
->setType('bool')
->setDescription(
pht(
'True if the commit is not the ancestor of any tag, branch, or '.
'ref.')),
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('auditStatus')
->setType('map<string, wild>')
->setDescription(pht('Information about the current audit status.')),
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('message')
->setType('string')
->setDescription(pht('The commit message.')),
); );
} }
public function getFieldValuesForConduit() { public function getFieldValuesForConduit() {
$data = $this->getCommitData();
// NOTE: This data should be similar to the information returned about $author_identity = $this->getAuthorIdentity();
// commmits by "differential.diff.search" with the "commits" attachment. if ($author_identity) {
$author_name = $author_identity->getIdentityDisplayName();
$author_email = $author_identity->getIdentityEmailAddress();
$author_raw = $author_identity->getIdentityName();
$author_identity_phid = $author_identity->getPHID();
$author_user_phid = $author_identity->getCurrentEffectiveUserPHID();
} else {
$author_name = null;
$author_email = null;
$author_raw = null;
$author_identity_phid = null;
$author_user_phid = null;
}
$committer_identity = $this->getCommitterIdentity();
if ($committer_identity) {
$committer_name = $committer_identity->getIdentityDisplayName();
$committer_email = $committer_identity->getIdentityEmailAddress();
$committer_raw = $committer_identity->getIdentityName();
$committer_identity_phid = $committer_identity->getPHID();
$committer_user_phid = $committer_identity->getCurrentEffectiveUserPHID();
} else {
$committer_name = null;
$committer_email = null;
$committer_raw = null;
$committer_identity_phid = null;
$committer_user_phid = null;
}
$author_epoch = $data->getCommitDetail('authorEpoch');
if ($author_epoch) {
$author_epoch = (int)$author_epoch;
} else {
$author_epoch = null;
}
$audit_status = $this->getAuditStatusObject();
return array( return array(
'identifier' => $this->getCommitIdentifier(), 'identifier' => $this->getCommitIdentifier(),
'repositoryPHID' => $this->getRepository()->getPHID(),
'author' => array(
'name' => $author_name,
'email' => $author_email,
'raw' => $author_raw,
'epoch' => $author_epoch,
'identityPHID' => $author_identity_phid,
'userPHID' => $author_user_phid,
),
'committer' => array(
'name' => $committer_name,
'email' => $committer_email,
'raw' => $committer_raw,
'epoch' => (int)$this->getEpoch(),
'identityPHID' => $committer_identity_phid,
'userPHID' => $committer_user_phid,
),
'isUnreachable' => (bool)$this->isUnreachable(),
'isImported' => (bool)$this->isImported(),
'auditStatus' => array(
'value' => $audit_status->getKey(),
'name' => $audit_status->getName(),
'closed' => (bool)$audit_status->getIsClosed(),
'color.ansi' => $audit_status->getAnsiColor(),
),
'message' => $data->getCommitMessage(),
); );
} }

View file

@ -230,9 +230,20 @@ EOTEXT
$constants_rows = array(); $constants_rows = array();
foreach ($constants as $constant) { foreach ($constants as $constant) {
if ($constant->getIsDeprecated()) {
$icon = id(new PHUIIconView())
->setIcon('fa-exclamation-triangle', 'red');
} else {
$icon = null;
}
$constants_rows[] = array( $constants_rows[] = array(
$constant->getKey(), $constant->getKey(),
$constant->getValue(), array(
$icon,
' ',
$constant->getValue(),
),
); );
} }
@ -244,7 +255,7 @@ EOTEXT
)) ))
->setColumnClasses( ->setColumnClasses(
array( array(
'pre', 'mono',
'wide', 'wide',
)); ));

View file

@ -4,6 +4,7 @@ final class PhabricatorSearchCheckboxesField
extends PhabricatorSearchField { extends PhabricatorSearchField {
private $options; private $options;
private $deprecatedOptions = array();
public function setOptions(array $options) { public function setOptions(array $options) {
$this->options = $options; $this->options = $options;
@ -14,6 +15,15 @@ final class PhabricatorSearchCheckboxesField
return $this->options; return $this->options;
} }
public function setDeprecatedOptions(array $deprecated_options) {
$this->deprecatedOptions = $deprecated_options;
return $this;
}
public function getDeprecatedOptions() {
return $this->deprecatedOptions;
}
protected function getDefaultValue() { protected function getDefaultValue() {
return array(); return array();
} }
@ -23,11 +33,12 @@ final class PhabricatorSearchCheckboxesField
return array(); return array();
} }
return $value; return $this->getCanonicalValue($value);
} }
protected function getValueFromRequest(AphrontRequest $request, $key) { protected function getValueFromRequest(AphrontRequest $request, $key) {
return $this->getListFromRequest($request, $key); $value = $this->getListFromRequest($request, $key);
return $this->getCanonicalValue($value);
} }
protected function newControl() { protected function newControl() {
@ -58,7 +69,29 @@ final class PhabricatorSearchCheckboxesField
->setValue($option); ->setValue($option);
} }
foreach ($this->getDeprecatedOptions() as $key => $value) {
$list[] = id(new ConduitConstantDescription())
->setKey($key)
->setIsDeprecated(true)
->setValue(pht('Deprecated alias for "%s".', $value));
}
return $list; return $list;
} }
private function getCanonicalValue(array $values) {
// Always map the current normal options to themselves.
$normal_options = array_fuse(array_keys($this->getOptions()));
// Map deprecated values to their new values.
$deprecated_options = $this->getDeprecatedOptions();
$map = $normal_options + $deprecated_options;
foreach ($values as $key => $value) {
$values[$key] = idx($map, $value, $value);
}
return $values;
}
} }

View file

@ -850,6 +850,10 @@ abstract class PhabricatorApplicationTransactionEditor
$xaction->setIsSilentTransaction(true); $xaction->setIsSilentTransaction(true);
} }
if ($actor->hasHighSecuritySession()) {
$xaction->setIsMFATransaction(true);
}
return $xaction; return $xaction;
} }

View file

@ -83,7 +83,15 @@ final class PhabricatorApplicationTransactionResponse
$xactions[$key] = hsprintf('%s', $xaction); $xactions[$key] = hsprintf('%s', $xaction);
} }
$aural = phutil_tag(
'h3',
array(
'class' => 'aural-only',
),
pht('Comment Preview'));
$content = array( $content = array(
'header' => hsprintf('%s', $aural),
'xactions' => $xactions, 'xactions' => $xactions,
'spacer' => PHUITimelineView::renderSpacer(), 'spacer' => PHUITimelineView::renderSpacer(),
'previewContent' => hsprintf('%s', $this->getPreviewContent()), 'previewContent' => hsprintf('%s', $this->getPreviewContent()),

View file

@ -165,6 +165,14 @@ abstract class PhabricatorApplicationTransaction
return (bool)$this->getMetadataValue('core.silent', false); return (bool)$this->getMetadataValue('core.silent', false);
} }
public function setIsMFATransaction($mfa) {
return $this->setMetadataValue('core.mfa', $mfa);
}
public function getIsMFATransaction() {
return (bool)$this->getMetadataValue('core.mfa', false);
}
public function attachComment( public function attachComment(
PhabricatorApplicationTransactionComment $comment) { PhabricatorApplicationTransactionComment $comment) {
$this->comment = $comment; $this->comment = $comment;
@ -1461,6 +1469,12 @@ abstract class PhabricatorApplicationTransaction
if ($is_silent != $xaction->getIsSilentTransaction()) { if ($is_silent != $xaction->getIsSilentTransaction()) {
return false; return false;
} }
// Don't group MFA and non-MFA transactions together.
$is_mfa = $this->getIsMFATransaction();
if ($is_mfa != $xaction->getIsMFATransaction()) {
return false;
}
} }
return true; return true;

View file

@ -243,8 +243,16 @@ class PhabricatorApplicationTransactionCommentView extends AphrontView {
$comment_box = id(new PHUIObjectBoxView()) $comment_box = id(new PHUIObjectBoxView())
->setFlush(true) ->setFlush(true)
->setNoBorder(true)
->addClass('phui-comment-form-view') ->addClass('phui-comment-form-view')
->addSigil('phui-comment-form') ->addSigil('phui-comment-form')
->appendChild(
phutil_tag(
'h3',
array(
'class' => 'aural-only',
),
pht('Add Comment')))
->appendChild($image) ->appendChild($image)
->appendChild($badge_view) ->appendChild($badge_view)
->appendChild($wedge) ->appendChild($wedge)

View file

@ -424,7 +424,8 @@ class PhabricatorApplicationTransactionView extends AphrontView {
->setIcon($xaction->getIcon()) ->setIcon($xaction->getIcon())
->setColor($xaction->getColor()) ->setColor($xaction->getColor())
->setHideCommentOptions($this->getHideCommentOptions()) ->setHideCommentOptions($this->getHideCommentOptions())
->setIsSilent($xaction->getIsSilentTransaction()); ->setIsSilent($xaction->getIsSilentTransaction())
->setIsMFA($xaction->getIsMFATransaction());
list($token, $token_removed) = $xaction->getToken(); list($token, $token_removed) = $xaction->getToken();
if ($token) { if ($token) {

View file

@ -6,5 +6,78 @@ Construct a detailed written history of your civilization.
Overview Overview
======== ========
Phriction is a simple wiki. You can edit pages, and the text you write will stay Phriction is a wiki. You can edit pages, and the text you write will stay
there. Other people can see it later. there. Other people can see it later.
Phriction documents are arranged in a hierarchy, like a filesystem. This can
make it easier to keep things organized and to apply policy controls to
groups of documents.
Policies
========
Documents and policies in Phriction are hierarchical, similar to a filesystem.
For example, a document called "Zebra Information" may be located
at `/zoo/animals/zebra/`.
To view a document in Phrction, you must first be able to view all of its
ancestors. So a user can only see {nav Zoo > Animals > Zebra Information} if
they can see the pages {nav Zoo} and {nav Zoo > Animals}.
This allows sections of the wiki to be restricted by applying a restrictive
policy to the parent (or grandparent) document. For example, if you apply a
restrictive view policy to the {nav Zoo} page, it will implicitly apply to
all sub-pages, including {nav Zoo > Animals > Zebra Information}.
Versions and Drafts
===================
Document content is tracked with linear version numbers: version 1, version 2,
version 3, and so on. Each time a page is edited, a new version of the page is
created.
You can {nav View History} to review older versions of a page and see how it
has changed over time (and who has changed it).
When you visit a particular document, you are normally shown the most recent
version of that document. For example, if there are 17 versions, you'll see
version 17.
Likewise, when you edit a document using {nav Edit Document > Save and Publish},
your changes are published immediately. If there were previously 17 versions,
your new changes will become version 18 and visitors to the document will begin
seeing version 18.
If you want to edit a document without publishing the changes right away, you
can use {nav Edit Document > Save as Draft} instead. This will still create a
new version 18, but it won't change which version users see when they visit the
document: they'll still see version 17 (the last published version).
You (and other users) can continue editing the draft by using
{nav Edit Document}. (Once a document has an unpublished draft, editing will
stay in draft mode.)
Once you're satisfied with your changes, use {nav Publish Draft} to make your
changes the current visible version of the document that users see by default
when they visit it.
If you made a mistake and published something you didn't intend to, you can
navigate back to an older version of the document and use
{nav Publish Older Version} to change the current visible version of the
document to some older version.
Note that draft versions are still normal versions of the document: they are
not private, they can not be deleted, other users can see them if they can see
the document, and they will eventually become a standard part of the document
history. The only private parts of drafts are: editing a draft does not
generate a feed story; and users won't see draft content by default when
viewing a document.
Drafts may be a good fit if you are:
- working on changes over time; or
- starting with a rough change and refining it in several iterations; or
- collaborating with others on a change; or
- sharing changes before they're published to get feedback.

View file

@ -233,14 +233,15 @@ final class PHUIButtonView extends AphrontTagView {
$classes = array(); $classes = array();
} }
// See PHI823. If we aren't rendering a "<button>" tag, give the tag we // See PHI823. If we aren't rendering a "<button>" or "<input>" tag,
// are rendering a "button" role as a hint to screen readers. // give the tag we are rendering a "button" role as a hint to screen
// readers.
$role = null; $role = null;
if ($this->tag !== 'button') { if ($this->tag !== 'button' && $this->tag !== 'input') {
$role = 'button'; $role = 'button';
} }
return array( $attrs = array(
'class' => $classes, 'class' => $classes,
'href' => $this->href, 'href' => $this->href,
'name' => $this->name, 'name' => $this->name,
@ -249,9 +250,19 @@ final class PHUIButtonView extends AphrontTagView {
'meta' => $meta, 'meta' => $meta,
'role' => $role, 'role' => $role,
); );
if ($this->tag == 'input') {
$attrs['type'] = 'submit';
$attrs['value'] = $this->text;
}
return $attrs;
} }
protected function getTagContent() { protected function getTagContent() {
if ($this->tag === 'input') {
return null;
}
$icon = $this->icon; $icon = $this->icon;
$text = null; $text = null;

View file

@ -25,6 +25,7 @@ final class PHUIObjectBoxView extends AphrontTagView {
private $showHideHref; private $showHideHref;
private $showHideContent; private $showHideContent;
private $showHideOpen; private $showHideOpen;
private $noBorder;
private $propertyLists = array(); private $propertyLists = array();
@ -147,6 +148,11 @@ final class PHUIObjectBoxView extends AphrontTagView {
return $this; return $this;
} }
public function setNoBorder($no_border) {
$this->noBorder = $no_border;
return $this;
}
public function setValidationException( public function setValidationException(
PhabricatorApplicationTransactionValidationException $ex = null) { PhabricatorApplicationTransactionValidationException $ex = null) {
$this->validationException = $ex; $this->validationException = $ex;
@ -156,7 +162,9 @@ final class PHUIObjectBoxView extends AphrontTagView {
protected function getTagAttributes() { protected function getTagAttributes() {
$classes = array(); $classes = array();
$classes[] = 'phui-box'; $classes[] = 'phui-box';
$classes[] = 'phui-box-border'; if (!$this->noBorder) {
$classes[] = 'phui-box-border';
}
$classes[] = 'phui-object-box'; $classes[] = 'phui-object-box';
$classes[] = 'mlt mll mlr'; $classes[] = 'mlt mll mlr';

View file

@ -30,6 +30,7 @@ final class PHUITimelineEventView extends AphrontView {
private $badges = array(); private $badges = array();
private $pinboardItems = array(); private $pinboardItems = array();
private $isSilent; private $isSilent;
private $isMFA;
public function setAuthorPHID($author_phid) { public function setAuthorPHID($author_phid) {
$this->authorPHID = $author_phid; $this->authorPHID = $author_phid;
@ -187,6 +188,15 @@ final class PHUITimelineEventView extends AphrontView {
return $this->isSilent; return $this->isSilent;
} }
public function setIsMFA($is_mfa) {
$this->isMFA = $is_mfa;
return $this;
}
public function getIsMFA() {
return $this->isMFA;
}
public function setReallyMajorEvent($me) { public function setReallyMajorEvent($me) {
$this->reallyMajorEvent = $me; $this->reallyMajorEvent = $me;
return $this; return $this;
@ -590,6 +600,14 @@ final class PHUITimelineEventView extends AphrontView {
->setIcon('fa-bell-slash', 'red') ->setIcon('fa-bell-slash', 'red')
->setTooltip(pht('Silent Edit')); ->setTooltip(pht('Silent Edit'));
} }
// If this edit was applied while the actor was in high-security mode,
// provide a hint that it was extra authentic.
if ($this->getIsMFA()) {
$extra[] = id(new PHUIIconView())
->setIcon('fa-vcard', 'green')
->setTooltip(pht('MFA Authenticated'));
}
} }
$extra = javelin_tag( $extra = javelin_tag(

View file

@ -83,7 +83,15 @@ final class PHUITimelineView extends AphrontView {
'class' => 'phui-timeline-view', 'class' => 'phui-timeline-view',
'id' => $this->id, 'id' => $this->id,
), ),
$events); array(
phutil_tag(
'h3',
array(
'class' => 'aural-only',
),
pht('Event Timeline')),
$events,
));
} }
public function buildEvents() { public function buildEvents() {

View file

@ -4,7 +4,8 @@
button, button,
a.button { a.button,
input[type="submit"] {
font: {$basefont}; font: {$basefont};
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-webkit-user-select: none; -webkit-user-select: none;
@ -72,7 +73,8 @@ a.icon:visited {
button.button-green, button.button-green,
a.button-green.button, a.button-green.button,
a.button-green.button:visited { a.button-green.button:visited,
input[type="submit"].button-green {
background-color: {$green.button.color}; background-color: {$green.button.color};
border-color: {$green.button.color}; border-color: {$green.button.color};
background-image: {$green.button.gradient}; background-image: {$green.button.gradient};
@ -80,16 +82,17 @@ a.button-green.button:visited {
button.button-red, button.button-red,
a.button-red.button, a.button-red.button,
a.button-red.button:visited { a.button-red.button:visited,
input[type="submit"].button-red {
background-color: {$red.button.color}; background-color: {$red.button.color};
border-color: {$red.button.color}; border-color: {$red.button.color};
background-image: {$red.button.gradient}; background-image: {$red.button.gradient};
} }
button.button-grey, button.button-grey,
input[type="submit"].button-grey,
a.button-grey, a.button-grey,
a.button-grey:visited { a.button-grey:visited,
input[type="submit"].button-grey {
background-color: {$grey.button.color}; background-color: {$grey.button.color};
background-image: {$grey.button.gradient}; background-image: {$grey.button.gradient};
border: 1px solid rgba({$alphablue}, 0.3); border: 1px solid rgba({$alphablue}, 0.3);

View file

@ -241,10 +241,13 @@ body.printable {
} }
} }
.phui-document-view-pro-box {
margin-bottom: 24px;
}
.phui-document-view-pro-box .phui-timeline-view { .phui-document-view-pro-box .phui-timeline-view {
padding: 16px 0 0 0; padding: 16px 0 0 0;
background: none; background: none;
border-top: 1px solid rgba({$alphablue}, 0.20);
} }
.phui-document-view-pro-box .phui-timeline-wedge { .phui-document-view-pro-box .phui-timeline-wedge {

View file

@ -133,19 +133,12 @@
} }
.aphront-form-control-submit button, .aphront-form-control-submit button,
.aphront-form-control-submit a.button { .aphront-form-control-submit a.button,
.aphront-form-control-submit input[type="submit"] {
float: right; float: right;
margin: 4px 0 0 8px; margin: 4px 0 0 8px;
} }
.phui-form-control-multi-submit input,
.phui-form-control-multi-submit button,
.phui-form-control-multi-submit a {
float: right;
margin: 4px 0 0 8px;
width: auto;
}
.aphront-form-control-textarea textarea.aphront-textarea-very-short { .aphront-form-control-textarea textarea.aphront-textarea-very-short {
height: 44px; height: 44px;
} }

View file

@ -105,6 +105,7 @@ JX.behavior('comment-actions', function(config) {
JX.DOM.setContent( JX.DOM.setContent(
preview_root, preview_root,
[ [
JX.$H(response.header),
JX.$H(response.xactions.join('')), JX.$H(response.xactions.join('')),
JX.$H(response.previewContent) JX.$H(response.previewContent)
]); ]);