From 9ebb5f8cda56a5ff057500265a5afc5a3e4f0a3b Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 3 Apr 2017 08:35:29 -0700 Subject: [PATCH 01/28] Don't downgrade accepts on update (fix "sticky accept") Summary: Fixes T12496. Sticky accept was accidentally impacted by the "void" changes in D17566. Instead, don't always downgrade all accepts/rejects: on update, we only want to downgrade accepts. Test Plan: - With sticky accept off, updated an accepted revision: new state is "needs review". - With sticky accept on, updated an accepted revision: new state is "accepted" (sticky accept working correctly). - Did "reject" + "request review" to make sure that still works, worked fine. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12496 Differential Revision: https://secure.phabricator.com/D17605 --- .../editor/DifferentialTransactionEditor.php | 14 ++++++++++++-- .../DifferentialRevisionVoidTransaction.php | 6 +++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/applications/differential/editor/DifferentialTransactionEditor.php b/src/applications/differential/editor/DifferentialTransactionEditor.php index bf7faa2700..f24bc7abda 100644 --- a/src/applications/differential/editor/DifferentialTransactionEditor.php +++ b/src/applications/differential/editor/DifferentialTransactionEditor.php @@ -339,12 +339,22 @@ final class DifferentialTransactionEditor } } - if ($downgrade_accepts || $downgrade_rejects) { + $downgrade = array(); + if ($downgrade_accepts) { + $downgrade[] = DifferentialReviewerStatus::STATUS_ACCEPTED; + } + + if ($downgrade_accepts) { + $downgrade[] = DifferentialReviewerStatus::STATUS_REJECTED; + } + + if ($downgrade) { $void_type = DifferentialRevisionVoidTransaction::TRANSACTIONTYPE; + $results[] = id(new DifferentialTransaction()) ->setTransactionType($void_type) ->setIgnoreOnNoEffect(true) - ->setNewValue(true); + ->setNewValue($downgrade); } $is_commandeer = false; diff --git a/src/applications/differential/xaction/DifferentialRevisionVoidTransaction.php b/src/applications/differential/xaction/DifferentialRevisionVoidTransaction.php index ae684d94fe..5073a9c464 100644 --- a/src/applications/differential/xaction/DifferentialRevisionVoidTransaction.php +++ b/src/applications/differential/xaction/DifferentialRevisionVoidTransaction.php @@ -28,7 +28,7 @@ final class DifferentialRevisionVoidTransaction AND reviewerStatus IN (%Ls)', $table_name, $object->getPHID(), - $this->getVoidableStatuses()); + $value); return ipull($rows, 'reviewerPHID'); } @@ -47,11 +47,11 @@ final class DifferentialRevisionVoidTransaction 'UPDATE %T SET voidedPHID = %s WHERE revisionPHID = %s AND voidedPHID IS NULL - AND reviewerStatus IN (%Ls)', + AND reviewerPHID IN (%Ls)', $table_name, $this->getActingAsPHID(), $object->getPHID(), - $this->getVoidableStatuses()); + $value); } public function shouldHide() { From 5e447112184e48a57509a57efeea7c5c067fa754 Mon Sep 17 00:00:00 2001 From: epriestley Date: Tue, 4 Apr 2017 05:53:39 -0700 Subject: [PATCH 02/28] Provide a missing feed transaction string for space creation Summary: Fixes T12502. This transaction probably should not be getting picked for feed rendering, but it currently does get selected in some cases. This should probably be revisited eventually (e.g., when Maniphest moves to ModularTransactions) but just fix the brokenness for now. Test Plan: - Created a task in a space. - Viewed feed. - Saw the story render with readable text. {F4555747} Reviewers: chad Reviewed By: chad Maniphest Tasks: T12502 Differential Revision: https://secure.phabricator.com/D17609 --- .../PhabricatorApplicationTransaction.php | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/applications/transactions/storage/PhabricatorApplicationTransaction.php b/src/applications/transactions/storage/PhabricatorApplicationTransaction.php index 5e36e942ce..bf3c616df9 100644 --- a/src/applications/transactions/storage/PhabricatorApplicationTransaction.php +++ b/src/applications/transactions/storage/PhabricatorApplicationTransaction.php @@ -1149,12 +1149,20 @@ abstract class PhabricatorApplicationTransaction $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); case PhabricatorTransactions::TYPE_SPACE: - return pht( - '%s shifted %s from the %s space to the %s space.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid), - $this->renderHandleLink($old), - $this->renderHandleLink($new)); + if ($this->getIsCreateTransaction()) { + return pht( + '%s created %s in the %s space.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($object_phid), + $this->renderHandleLink($new)); + } else { + return pht( + '%s shifted %s from the %s space to the %s space.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($object_phid), + $this->renderHandleLink($old), + $this->renderHandleLink($new)); + } case PhabricatorTransactions::TYPE_EDGE: $new = ipull($new, 'dst'); $old = ipull($old, 'dst'); From 8500f78e451c61079ba9ca4e4f27a087e7ab1403 Mon Sep 17 00:00:00 2001 From: epriestley Date: Tue, 4 Apr 2017 07:43:20 -0700 Subject: [PATCH 03/28] Move Files to ModularTransactions Summary: Ref T11357. A lot of file creation doesn't go through transactions, so we only actually have one real transaction type: editing a file name. Test Plan: Created and edited files. {F4559287} Reviewers: chad Reviewed By: chad Maniphest Tasks: T11357 Differential Revision: https://secure.phabricator.com/D17610 --- src/__phutil_library_map__.php | 6 +- .../PhabricatorBadgesBadgeNameTransaction.php | 2 +- .../PhabricatorFileEditController.php | 4 +- .../files/editor/PhabricatorFileEditor.php | 67 ------------------ .../storage/PhabricatorFileTransaction.php | 69 +------------------ .../__tests__/PhabricatorFileTestCase.php | 2 +- .../PhabricatorFileNameTransaction.php | 55 +++++++++++++++ .../PhabricatorFileTransactionType.php | 4 ++ 8 files changed, 71 insertions(+), 138 deletions(-) create mode 100644 src/applications/files/xaction/PhabricatorFileNameTransaction.php create mode 100644 src/applications/files/xaction/PhabricatorFileTransactionType.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 9ccc495e7a..14d84a9ae7 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2765,6 +2765,7 @@ phutil_register_library_map(array( 'PhabricatorFileLightboxController' => 'applications/files/controller/PhabricatorFileLightboxController.php', 'PhabricatorFileLinkView' => 'view/layout/PhabricatorFileLinkView.php', 'PhabricatorFileListController' => 'applications/files/controller/PhabricatorFileListController.php', + 'PhabricatorFileNameTransaction' => 'applications/files/xaction/PhabricatorFileNameTransaction.php', 'PhabricatorFileQuery' => 'applications/files/query/PhabricatorFileQuery.php', 'PhabricatorFileROT13StorageFormat' => 'applications/files/format/PhabricatorFileROT13StorageFormat.php', 'PhabricatorFileRawStorageFormat' => 'applications/files/format/PhabricatorFileRawStorageFormat.php', @@ -2783,6 +2784,7 @@ phutil_register_library_map(array( 'PhabricatorFileTransaction' => 'applications/files/storage/PhabricatorFileTransaction.php', 'PhabricatorFileTransactionComment' => 'applications/files/storage/PhabricatorFileTransactionComment.php', 'PhabricatorFileTransactionQuery' => 'applications/files/query/PhabricatorFileTransactionQuery.php', + 'PhabricatorFileTransactionType' => 'applications/files/xaction/PhabricatorFileTransactionType.php', 'PhabricatorFileTransform' => 'applications/files/transform/PhabricatorFileTransform.php', 'PhabricatorFileTransformController' => 'applications/files/controller/PhabricatorFileTransformController.php', 'PhabricatorFileTransformListController' => 'applications/files/controller/PhabricatorFileTransformListController.php', @@ -7890,6 +7892,7 @@ phutil_register_library_map(array( 'PhabricatorFileLightboxController' => 'PhabricatorFileController', 'PhabricatorFileLinkView' => 'AphrontTagView', 'PhabricatorFileListController' => 'PhabricatorFileController', + 'PhabricatorFileNameTransaction' => 'PhabricatorFileTransactionType', 'PhabricatorFileQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorFileROT13StorageFormat' => 'PhabricatorFileStorageFormat', 'PhabricatorFileRawStorageFormat' => 'PhabricatorFileStorageFormat', @@ -7905,9 +7908,10 @@ phutil_register_library_map(array( 'PhabricatorFileTestCase' => 'PhabricatorTestCase', 'PhabricatorFileTestDataGenerator' => 'PhabricatorTestDataGenerator', 'PhabricatorFileThumbnailTransform' => 'PhabricatorFileImageTransform', - 'PhabricatorFileTransaction' => 'PhabricatorApplicationTransaction', + 'PhabricatorFileTransaction' => 'PhabricatorModularTransaction', 'PhabricatorFileTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PhabricatorFileTransactionQuery' => 'PhabricatorApplicationTransactionQuery', + 'PhabricatorFileTransactionType' => 'PhabricatorModularTransactionType', 'PhabricatorFileTransform' => 'Phobject', 'PhabricatorFileTransformController' => 'PhabricatorFileController', 'PhabricatorFileTransformListController' => 'PhabricatorFileController', diff --git a/src/applications/badges/xaction/PhabricatorBadgesBadgeNameTransaction.php b/src/applications/badges/xaction/PhabricatorBadgesBadgeNameTransaction.php index 1df7d89a70..3a609fedb2 100644 --- a/src/applications/badges/xaction/PhabricatorBadgesBadgeNameTransaction.php +++ b/src/applications/badges/xaction/PhabricatorBadgesBadgeNameTransaction.php @@ -43,7 +43,7 @@ final class PhabricatorBadgesBadgeNameTransaction $new_value = $xaction->getNewValue(); $new_length = strlen($new_value); if ($new_length > $max_length) { - $errors[] = $this->newRequiredError( + $errors[] = $this->newInvalidError( pht('The name can be no longer than %s characters.', new PhutilNumber($max_length))); } diff --git a/src/applications/files/controller/PhabricatorFileEditController.php b/src/applications/files/controller/PhabricatorFileEditController.php index e1b34afd73..a1e7a16d80 100644 --- a/src/applications/files/controller/PhabricatorFileEditController.php +++ b/src/applications/files/controller/PhabricatorFileEditController.php @@ -31,7 +31,7 @@ final class PhabricatorFileEditController extends PhabricatorFileController { $file_name = $request->getStr('name'); $errors = array(); - $type_name = PhabricatorFileTransaction::TYPE_NAME; + $type_name = PhabricatorFileNameTransaction::TRANSACTIONTYPE; $xactions = array(); @@ -40,7 +40,7 @@ final class PhabricatorFileEditController extends PhabricatorFileController { ->setNewValue($can_view); $xactions[] = id(new PhabricatorFileTransaction()) - ->setTransactionType(PhabricatorFileTransaction::TYPE_NAME) + ->setTransactionType($type_name) ->setNewValue($file_name); $editor = id(new PhabricatorFileEditor()) diff --git a/src/applications/files/editor/PhabricatorFileEditor.php b/src/applications/files/editor/PhabricatorFileEditor.php index 9cd81a4c1e..28b781fb37 100644 --- a/src/applications/files/editor/PhabricatorFileEditor.php +++ b/src/applications/files/editor/PhabricatorFileEditor.php @@ -17,46 +17,9 @@ final class PhabricatorFileEditor $types[] = PhabricatorTransactions::TYPE_COMMENT; $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; - $types[] = PhabricatorFileTransaction::TYPE_NAME; - return $types; } - protected function getCustomTransactionOldValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhabricatorFileTransaction::TYPE_NAME: - return $object->getName(); - } - } - - protected function getCustomTransactionNewValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhabricatorFileTransaction::TYPE_NAME: - return $xaction->getNewValue(); - } - } - - protected function applyCustomInternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhabricatorFileTransaction::TYPE_NAME: - $object->setName($xaction->getNewValue()); - break; - } - } - - protected function applyCustomExternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) {} - protected function shouldSendMail( PhabricatorLiskDAO $object, array $xactions) { @@ -111,34 +74,4 @@ final class PhabricatorFileEditor return false; } - protected function validateTransaction( - PhabricatorLiskDAO $object, - $type, - array $xactions) { - - $errors = parent::validateTransaction($object, $type, $xactions); - - switch ($type) { - case PhabricatorFileTransaction::TYPE_NAME: - $missing = $this->validateIsEmptyTextField( - $object->getName(), - $xactions); - - if ($missing) { - $error = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Required'), - pht('File name is required.'), - nonempty(last($xactions), null)); - - $error->setIsMissingFieldError(true); - $errors[] = $error; - } - break; - } - - return $errors; - } - - } diff --git a/src/applications/files/storage/PhabricatorFileTransaction.php b/src/applications/files/storage/PhabricatorFileTransaction.php index 663dde28c7..3c72be6fd7 100644 --- a/src/applications/files/storage/PhabricatorFileTransaction.php +++ b/src/applications/files/storage/PhabricatorFileTransaction.php @@ -1,9 +1,7 @@ getAuthorPHID(); - - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_NAME: - return pht( - '%s updated the name for this file from "%s" to "%s".', - $this->renderHandleLink($author_phid), - $old, - $new); - break; - } - - return parent::getTitle(); + public function getBaseTransactionClass() { + return 'PhabricatorFileTransactionType'; } - public function getTitleForFeed() { - $author_phid = $this->getAuthorPHID(); - $object_phid = $this->getObjectPHID(); - - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - $type = $this->getTransactionType(); - switch ($type) { - case self::TYPE_NAME: - return pht( - '%s updated the name of %s from "%s" to "%s".', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid), - $old, - $new); - break; - } - - return parent::getTitleForFeed(); - } - - public function getIcon() { - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_NAME: - return 'fa-pencil'; - } - - return parent::getIcon(); - } - - - public function getColor() { - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_NAME: - return PhabricatorTransactions::COLOR_BLUE; - } - - return parent::getColor(); - } } diff --git a/src/applications/files/storage/__tests__/PhabricatorFileTestCase.php b/src/applications/files/storage/__tests__/PhabricatorFileTestCase.php index 8aa22c6578..f9090c9c83 100644 --- a/src/applications/files/storage/__tests__/PhabricatorFileTestCase.php +++ b/src/applications/files/storage/__tests__/PhabricatorFileTestCase.php @@ -32,7 +32,7 @@ final class PhabricatorFileTestCase extends PhabricatorTestCase { // First, change the name: this should not scramble the secret. $xactions = array(); $xactions[] = id(new PhabricatorFileTransaction()) - ->setTransactionType(PhabricatorFileTransaction::TYPE_NAME) + ->setTransactionType(PhabricatorFileNameTransaction::TRANSACTIONTYPE) ->setNewValue('test.dat2'); $engine = id(new PhabricatorFileEditor()) diff --git a/src/applications/files/xaction/PhabricatorFileNameTransaction.php b/src/applications/files/xaction/PhabricatorFileNameTransaction.php new file mode 100644 index 0000000000..7eb9396b66 --- /dev/null +++ b/src/applications/files/xaction/PhabricatorFileNameTransaction.php @@ -0,0 +1,55 @@ +getName(); + } + + public function applyInternalEffects($object, $value) { + $object->setName($value); + } + + public function getTitle() { + return pht( + '%s updated the name for this file from "%s" to "%s".', + $this->renderAuthor(), + $this->renderOldValue(), + $this->renderNewValue()); + } + + public function getTitleForFeed() { + return pht( + '%s updated the name of %s from "%s" to "%s".', + $this->renderAuthor(), + $this->renderObject(), + $this->renderOldValue(), + $this->renderNewValue()); + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + if ($this->isEmptyTextTransaction($object->getName(), $xactions)) { + $errors[] = $this->newRequiredError(pht('Files must have a name.')); + } + + $max_length = $object->getColumnMaximumByteLength('name'); + foreach ($xactions as $xaction) { + $new_value = $xaction->getNewValue(); + $new_length = strlen($new_value); + if ($new_length > $max_length) { + $errors[] = $this->newInvalidError( + pht( + 'File names must not be longer than %s character(s).', + new PhutilNumber($max_length))); + } + } + + return $errors; + } + +} diff --git a/src/applications/files/xaction/PhabricatorFileTransactionType.php b/src/applications/files/xaction/PhabricatorFileTransactionType.php new file mode 100644 index 0000000000..cc708ac541 --- /dev/null +++ b/src/applications/files/xaction/PhabricatorFileTransactionType.php @@ -0,0 +1,4 @@ + Date: Tue, 4 Apr 2017 08:02:37 -0700 Subject: [PATCH 04/28] Move Files editing and commenting to EditEngine Summary: Ref T11357. This moves editing and commenting (but not creation) to EditEngine. Since only the name is really editable, this is pretty straightforward. Test Plan: Renamed files; commented on files. Reviewers: chad Reviewed By: chad Maniphest Tasks: T11357 Differential Revision: https://secure.phabricator.com/D17611 --- src/__phutil_library_map__.php | 4 +- .../PhabricatorFilesApplication.php | 3 +- .../PhabricatorFileCommentController.php | 62 ---------- .../PhabricatorFileEditController.php | 112 +----------------- .../PhabricatorFileInfoController.php | 21 ++-- .../editor/PhabricatorFileEditEngine.php | 79 ++++++++++++ .../files/storage/PhabricatorFile.php | 3 + 7 files changed, 98 insertions(+), 186 deletions(-) delete mode 100644 src/applications/files/controller/PhabricatorFileCommentController.php create mode 100644 src/applications/files/editor/PhabricatorFileEditEngine.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 14d84a9ae7..99f9810052 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2743,7 +2743,6 @@ phutil_register_library_map(array( 'PhabricatorFileChunk' => 'applications/files/storage/PhabricatorFileChunk.php', 'PhabricatorFileChunkIterator' => 'applications/files/engine/PhabricatorFileChunkIterator.php', 'PhabricatorFileChunkQuery' => 'applications/files/query/PhabricatorFileChunkQuery.php', - 'PhabricatorFileCommentController' => 'applications/files/controller/PhabricatorFileCommentController.php', 'PhabricatorFileComposeController' => 'applications/files/controller/PhabricatorFileComposeController.php', 'PhabricatorFileController' => 'applications/files/controller/PhabricatorFileController.php', 'PhabricatorFileDAO' => 'applications/files/storage/PhabricatorFileDAO.php', @@ -2751,6 +2750,7 @@ phutil_register_library_map(array( 'PhabricatorFileDeleteController' => 'applications/files/controller/PhabricatorFileDeleteController.php', 'PhabricatorFileDropUploadController' => 'applications/files/controller/PhabricatorFileDropUploadController.php', 'PhabricatorFileEditController' => 'applications/files/controller/PhabricatorFileEditController.php', + 'PhabricatorFileEditEngine' => 'applications/files/editor/PhabricatorFileEditEngine.php', 'PhabricatorFileEditField' => 'applications/transactions/editfield/PhabricatorFileEditField.php', 'PhabricatorFileEditor' => 'applications/files/editor/PhabricatorFileEditor.php', 'PhabricatorFileExternalRequest' => 'applications/files/storage/PhabricatorFileExternalRequest.php', @@ -7860,7 +7860,6 @@ phutil_register_library_map(array( 'Iterator', ), 'PhabricatorFileChunkQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', - 'PhabricatorFileCommentController' => 'PhabricatorFileController', 'PhabricatorFileComposeController' => 'PhabricatorFileController', 'PhabricatorFileController' => 'PhabricatorController', 'PhabricatorFileDAO' => 'PhabricatorLiskDAO', @@ -7868,6 +7867,7 @@ phutil_register_library_map(array( 'PhabricatorFileDeleteController' => 'PhabricatorFileController', 'PhabricatorFileDropUploadController' => 'PhabricatorFileController', 'PhabricatorFileEditController' => 'PhabricatorFileController', + 'PhabricatorFileEditEngine' => 'PhabricatorEditEngine', 'PhabricatorFileEditField' => 'PhabricatorEditField', 'PhabricatorFileEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorFileExternalRequest' => array( diff --git a/src/applications/files/application/PhabricatorFilesApplication.php b/src/applications/files/application/PhabricatorFilesApplication.php index 5733439fcf..1010818c19 100644 --- a/src/applications/files/application/PhabricatorFilesApplication.php +++ b/src/applications/files/application/PhabricatorFilesApplication.php @@ -78,7 +78,8 @@ final class PhabricatorFilesApplication extends PhabricatorApplication { 'comment/(?P[1-9]\d*)/' => 'PhabricatorFileCommentController', 'thread/(?P[^/]+)/' => 'PhabricatorFileLightboxController', 'delete/(?P[1-9]\d*)/' => 'PhabricatorFileDeleteController', - 'edit/(?P[1-9]\d*)/' => 'PhabricatorFileEditController', + $this->getEditRoutePattern('edit/') + => 'PhabricatorFileEditController', 'info/(?P[^/]+)/' => 'PhabricatorFileInfoController', 'imageproxy/' => 'PhabricatorFileImageProxyController', 'transforms/(?P[1-9]\d*)/' => diff --git a/src/applications/files/controller/PhabricatorFileCommentController.php b/src/applications/files/controller/PhabricatorFileCommentController.php deleted file mode 100644 index 11833ea8d8..0000000000 --- a/src/applications/files/controller/PhabricatorFileCommentController.php +++ /dev/null @@ -1,62 +0,0 @@ -getViewer(); - $id = $request->getURIData('id'); - - if (!$request->isFormPost()) { - return new Aphront400Response(); - } - - $file = id(new PhabricatorFileQuery()) - ->setViewer($viewer) - ->withIDs(array($id)) - ->executeOne(); - if (!$file) { - return new Aphront404Response(); - } - - $is_preview = $request->isPreviewRequest(); - $draft = PhabricatorDraft::buildFromRequest($request); - - $view_uri = $file->getInfoURI(); - - $xactions = array(); - $xactions[] = id(new PhabricatorFileTransaction()) - ->setTransactionType(PhabricatorTransactions::TYPE_COMMENT) - ->attachComment( - id(new PhabricatorFileTransactionComment()) - ->setContent($request->getStr('comment'))); - - $editor = id(new PhabricatorFileEditor()) - ->setActor($viewer) - ->setContinueOnNoEffect($request->isContinueRequest()) - ->setContentSourceFromRequest($request) - ->setIsPreview($is_preview); - - try { - $xactions = $editor->applyTransactions($file, $xactions); - } catch (PhabricatorApplicationTransactionNoEffectException $ex) { - return id(new PhabricatorApplicationTransactionNoEffectResponse()) - ->setCancelURI($view_uri) - ->setException($ex); - } - - if ($draft) { - $draft->replaceOrDelete(); - } - - if ($request->isAjax() && $is_preview) { - return id(new PhabricatorApplicationTransactionResponse()) - ->setViewer($viewer) - ->setTransactions($xactions) - ->setIsPreview($is_preview); - } else { - return id(new AphrontRedirectResponse()) - ->setURI($view_uri); - } - } - -} diff --git a/src/applications/files/controller/PhabricatorFileEditController.php b/src/applications/files/controller/PhabricatorFileEditController.php index a1e7a16d80..ea07d72722 100644 --- a/src/applications/files/controller/PhabricatorFileEditController.php +++ b/src/applications/files/controller/PhabricatorFileEditController.php @@ -1,114 +1,12 @@ getViewer(); - $id = $request->getURIData('id'); - - $file = id(new PhabricatorFileQuery()) - ->setViewer($viewer) - ->withIDs(array($id)) - ->requireCapabilities( - array( - PhabricatorPolicyCapability::CAN_VIEW, - PhabricatorPolicyCapability::CAN_EDIT, - )) - ->executeOne(); - if (!$file) { - return new Aphront404Response(); - } - - $title = pht('Edit File: %s', $file->getName()); - $file_name = $file->getName(); - $header_icon = 'fa-pencil'; - $view_uri = '/'.$file->getMonogram(); - $error_name = true; - $validation_exception = null; - - if ($request->isFormPost()) { - $can_view = $request->getStr('canView'); - $file_name = $request->getStr('name'); - $errors = array(); - - $type_name = PhabricatorFileNameTransaction::TRANSACTIONTYPE; - - $xactions = array(); - - $xactions[] = id(new PhabricatorFileTransaction()) - ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY) - ->setNewValue($can_view); - - $xactions[] = id(new PhabricatorFileTransaction()) - ->setTransactionType($type_name) - ->setNewValue($file_name); - - $editor = id(new PhabricatorFileEditor()) - ->setActor($viewer) - ->setContentSourceFromRequest($request) - ->setContinueOnNoEffect(true); - - try { - $editor->applyTransactions($file, $xactions); - return id(new AphrontRedirectResponse())->setURI($view_uri); - } catch (PhabricatorApplicationTransactionValidationException $ex) { - $validation_exception = $ex; - $error_name = $ex->getShortMessage($type_name); - - $file->setViewPolicy($can_view); - } - } - - - $policies = id(new PhabricatorPolicyQuery()) - ->setViewer($viewer) - ->setObject($file) - ->execute(); - - $form = id(new AphrontFormView()) - ->setUser($viewer) - ->appendChild( - id(new AphrontFormTextControl()) - ->setName('name') - ->setValue($file_name) - ->setLabel(pht('Name')) - ->setError($error_name)) - ->appendChild( - id(new AphrontFormPolicyControl()) - ->setUser($viewer) - ->setCapability(PhabricatorPolicyCapability::CAN_VIEW) - ->setPolicyObject($file) - ->setPolicies($policies) - ->setName('canView')) - ->appendChild( - id(new AphrontFormSubmitControl()) - ->addCancelButton($view_uri) - ->setValue(pht('Save Changes'))); - - $crumbs = $this->buildApplicationCrumbs() - ->addTextCrumb($file->getMonogram(), $view_uri) - ->addTextCrumb(pht('Edit')) - ->setBorder(true); - - $box = id(new PHUIObjectBoxView()) - ->setHeaderText($title) - ->setValidationException($validation_exception) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->appendChild($form); - - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setHeaderIcon($header_icon); - - $view = id(new PHUITwoColumnView()) - ->setHeader($header) - ->setFooter($box); - - return $this->newPage() - ->setTitle($title) - ->setCrumbs($crumbs) - ->appendChild($view); - + return id(new PhabricatorFileEditEngine()) + ->setController($this) + ->buildResponse(); } } diff --git a/src/applications/files/controller/PhabricatorFileInfoController.php b/src/applications/files/controller/PhabricatorFileInfoController.php index 4ca3bbb72e..8e92423fbc 100644 --- a/src/applications/files/controller/PhabricatorFileInfoController.php +++ b/src/applications/files/controller/PhabricatorFileInfoController.php @@ -94,25 +94,18 @@ final class PhabricatorFileInfoController extends PhabricatorFileController { $file, new PhabricatorFileTransactionQuery()); - $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); + $comment_view = id(new PhabricatorFileEditEngine()) + ->setViewer($viewer) + ->buildEditEngineCommentView($file); - $add_comment_header = $is_serious - ? pht('Add Comment') - : pht('Question File Integrity'); + $monogram = $file->getMonogram(); - $draft = PhabricatorDraft::newFromUserAndKey($viewer, $file->getPHID()); - - $add_comment_form = id(new PhabricatorApplicationTransactionCommentView()) - ->setUser($viewer) - ->setObjectPHID($file->getPHID()) - ->setDraft($draft) - ->setHeaderText($add_comment_header) - ->setAction($this->getApplicationURI('/comment/'.$file->getID().'/')) - ->setSubmitButtonName(pht('Add Comment')); + $timeline->setQuoteRef($monogram); + $comment_view->setTransactionTimeline($timeline); return array( $timeline, - $add_comment_form, + $comment_view, ); } diff --git a/src/applications/files/editor/PhabricatorFileEditEngine.php b/src/applications/files/editor/PhabricatorFileEditEngine.php new file mode 100644 index 0000000000..04c4753bd5 --- /dev/null +++ b/src/applications/files/editor/PhabricatorFileEditEngine.php @@ -0,0 +1,79 @@ +getName()); + } + + protected function getObjectEditShortText($object) { + return $object->getMonogram(); + } + + protected function getObjectCreateShortText() { + return pht('Create File'); + } + + protected function getObjectName() { + return pht('File'); + } + + protected function getObjectViewURI($object) { + return $object->getURI(); + } + + protected function buildCustomEditFields($object) { + return array( + id(new PhabricatorTextEditField()) + ->setKey('name') + ->setLabel(pht('Name')) + ->setTransactionType(PhabricatorFileNameTransaction::TRANSACTIONTYPE) + ->setDescription(pht('The name of the file.')) + ->setConduitDescription(pht('Rename the file.')) + ->setConduitTypeDescription(pht('New file name.')) + ->setValue($object->getName()), + ); + } + +} diff --git a/src/applications/files/storage/PhabricatorFile.php b/src/applications/files/storage/PhabricatorFile.php index d301abceca..da7ad3f729 100644 --- a/src/applications/files/storage/PhabricatorFile.php +++ b/src/applications/files/storage/PhabricatorFile.php @@ -774,6 +774,9 @@ final class PhabricatorFile extends PhabricatorFileDAO return $format->newReadIterator($raw_iterator); } + public function getURI() { + return $this->getInfoURI(); + } public function getViewURI() { if (!$this->getPHID()) { From 2369fa38e1879134571f02b93961b98e19236bd9 Mon Sep 17 00:00:00 2001 From: epriestley Date: Tue, 4 Apr 2017 08:48:05 -0700 Subject: [PATCH 05/28] Provide a modern ("v3") API for querying files ("file.search") Summary: Ref T11357. Implements a modern `file.search` for files, and freezes `file.info`. Test Plan: Ran `file.search` from the Conduit console. Reviewers: chad Reviewed By: chad Maniphest Tasks: T11357 Differential Revision: https://secure.phabricator.com/D17612 --- src/__phutil_library_map__.php | 3 ++ .../conduit/FileInfoConduitAPIMethod.php | 10 ++++++ .../PhabricatorFileSearchConduitAPIMethod.php | 18 ++++++++++ .../files/storage/PhabricatorFile.php | 36 ++++++++++++++++++- 4 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 src/applications/files/conduit/PhabricatorFileSearchConduitAPIMethod.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 99f9810052..f082c2fe22 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2770,6 +2770,7 @@ phutil_register_library_map(array( 'PhabricatorFileROT13StorageFormat' => 'applications/files/format/PhabricatorFileROT13StorageFormat.php', 'PhabricatorFileRawStorageFormat' => 'applications/files/format/PhabricatorFileRawStorageFormat.php', 'PhabricatorFileSchemaSpec' => 'applications/files/storage/PhabricatorFileSchemaSpec.php', + 'PhabricatorFileSearchConduitAPIMethod' => 'applications/files/conduit/PhabricatorFileSearchConduitAPIMethod.php', 'PhabricatorFileSearchEngine' => 'applications/files/query/PhabricatorFileSearchEngine.php', 'PhabricatorFileStorageBlob' => 'applications/files/storage/PhabricatorFileStorageBlob.php', 'PhabricatorFileStorageConfigurationException' => 'applications/files/exception/PhabricatorFileStorageConfigurationException.php', @@ -7847,6 +7848,7 @@ phutil_register_library_map(array( 'PhabricatorFlaggableInterface', 'PhabricatorPolicyInterface', 'PhabricatorDestructibleInterface', + 'PhabricatorConduitResultInterface', ), 'PhabricatorFileAES256StorageFormat' => 'PhabricatorFileStorageFormat', 'PhabricatorFileBundleLoader' => 'Phobject', @@ -7897,6 +7899,7 @@ phutil_register_library_map(array( 'PhabricatorFileROT13StorageFormat' => 'PhabricatorFileStorageFormat', 'PhabricatorFileRawStorageFormat' => 'PhabricatorFileStorageFormat', 'PhabricatorFileSchemaSpec' => 'PhabricatorConfigSchemaSpec', + 'PhabricatorFileSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'PhabricatorFileSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorFileStorageBlob' => 'PhabricatorFileDAO', 'PhabricatorFileStorageConfigurationException' => 'Exception', diff --git a/src/applications/files/conduit/FileInfoConduitAPIMethod.php b/src/applications/files/conduit/FileInfoConduitAPIMethod.php index 5f1bb6e936..f1c8f5941a 100644 --- a/src/applications/files/conduit/FileInfoConduitAPIMethod.php +++ b/src/applications/files/conduit/FileInfoConduitAPIMethod.php @@ -10,6 +10,16 @@ final class FileInfoConduitAPIMethod extends FileConduitAPIMethod { return pht('Get information about a file.'); } + public function getMethodStatus() { + return self::METHOD_STATUS_FROZEN; + } + + public function getMethodStatusDescription() { + return pht( + 'This method is frozen and will eventually be deprecated. New code '. + 'should use "file.search" instead.'); + } + protected function defineParamTypes() { return array( 'phid' => 'optional phid', diff --git a/src/applications/files/conduit/PhabricatorFileSearchConduitAPIMethod.php b/src/applications/files/conduit/PhabricatorFileSearchConduitAPIMethod.php new file mode 100644 index 0000000000..0b6920d559 --- /dev/null +++ b/src/applications/files/conduit/PhabricatorFileSearchConduitAPIMethod.php @@ -0,0 +1,18 @@ +saveTransaction(); } + +/* -( PhabricatorConduitResultInterface )---------------------------------- */ + + + public function getFieldSpecificationsForConduit() { + return array( + id(new PhabricatorConduitSearchFieldSpecification()) + ->setKey('name') + ->setType('string') + ->setDescription(pht('The name of the file.')), + id(new PhabricatorConduitSearchFieldSpecification()) + ->setKey('dataURI') + ->setType('string') + ->setDescription(pht('Download URI for the file data.')), + id(new PhabricatorConduitSearchFieldSpecification()) + ->setKey('size') + ->setType('int') + ->setDescription(pht('File size, in bytes.')), + ); + } + + public function getFieldValuesForConduit() { + return array( + 'name' => $this->getName(), + 'dataURI' => $this->getCDNURI(), + 'size' => (int)$this->getByteSize(), + ); + } + + public function getConduitSearchAttachments() { + return array(); + } + } From 2896da384cb7366fbcf41f8488ecea281393dfba Mon Sep 17 00:00:00 2001 From: epriestley Date: Tue, 4 Apr 2017 09:06:00 -0700 Subject: [PATCH 06/28] Only require POST to fetch file data if the viewer is logged in Summary: Ref T11357. In D17611, I added `file.search`, which includes a `"dataURI"`. Partly, this is building toward resolving T8348. However, in some cases you can't GET this URI because of a security measure: - You have not configured `security.alternate-file-domain`. - The file isn't web-viewable. - (The request isn't an LFS request.) The goal of this security mechanism is just to protect against session hijacking, so it's also safe to disable it if the viewer didn't present any credentials (since that means there's nothing to hijack). Add that exception, and reorganize the code a little bit. Test Plan: - From the browser (with a session), tried to GET a binary data file. Got redirected. - Got a download with POST. - From the CLI (without a session), tried to GET a binary data file. Go a download. Reviewers: chad Reviewed By: chad Maniphest Tasks: T11357 Differential Revision: https://secure.phabricator.com/D17613 --- .../PhabricatorFileDataController.php | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/applications/files/controller/PhabricatorFileDataController.php b/src/applications/files/controller/PhabricatorFileDataController.php index 5c2fc7bbda..43b5aa419f 100644 --- a/src/applications/files/controller/PhabricatorFileDataController.php +++ b/src/applications/files/controller/PhabricatorFileDataController.php @@ -84,18 +84,28 @@ final class PhabricatorFileDataController extends PhabricatorFileController { if ($is_viewable && !$force_download) { $response->setMimeType($file->getViewableMimeType()); } else { - if (!$request->isHTTPPost() && !$is_alternate_domain && !$is_lfs) { - // NOTE: Require POST to download files from the primary domain. We'd - // rather go full-bore and do a real CSRF check, but can't currently - // authenticate users on the file domain. This should blunt any - // attacks based on iframes, script tags, applet tags, etc., at least. - // Send the user to the "info" page if they're using some other method. + $is_public = !$viewer->isLoggedIn(); + $is_post = $request->isHTTPPost(); + // NOTE: Require POST to download files from the primary domain if the + // request includes credentials. The "Download File" links we generate + // in the web UI are forms which use POST to satisfy this requirement. + + // The intent is to make attacks based on tags like "