From b32a00dbace4f23d6d7a945c9a70d08be8e216e4 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Wed, 10 May 2017 15:11:39 -0700 Subject: [PATCH] Update Legalpad for EditEngine Summary: Updates Legalpad to use EditEngine, paving the way for //transaction comments//. Spooky. Test Plan: - New Document - Require signing, Corp - see fail - Require signing, Noone - see fail - Require signing, Ind - get asked to sign - Edit Document Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D17862 --- src/__phutil_library_map__.php | 2 + .../PhabricatorLegalpadApplication.php | 7 +- .../controller/LegalpadController.php | 2 +- .../LegalpadDocumentEditController.php | 272 +----------------- .../LegalpadDocumentListController.php | 2 +- .../editor/LegalpadDocumentEditEngine.php | 169 +++++++++++ .../editor/LegalpadDocumentEditor.php | 39 +++ .../legalpad/storage/LegalpadDocument.php | 4 + ...padDocumentRequireSignatureTransaction.php | 18 +- 9 files changed, 239 insertions(+), 276 deletions(-) create mode 100644 src/applications/legalpad/editor/LegalpadDocumentEditEngine.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index acfc7b2ff1..78994a0ce4 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1408,6 +1408,7 @@ phutil_register_library_map(array( 'LegalpadDocumentDatasource' => 'applications/legalpad/typeahead/LegalpadDocumentDatasource.php', 'LegalpadDocumentDoneController' => 'applications/legalpad/controller/LegalpadDocumentDoneController.php', 'LegalpadDocumentEditController' => 'applications/legalpad/controller/LegalpadDocumentEditController.php', + 'LegalpadDocumentEditEngine' => 'applications/legalpad/editor/LegalpadDocumentEditEngine.php', 'LegalpadDocumentEditor' => 'applications/legalpad/editor/LegalpadDocumentEditor.php', 'LegalpadDocumentListController' => 'applications/legalpad/controller/LegalpadDocumentListController.php', 'LegalpadDocumentManageController' => 'applications/legalpad/controller/LegalpadDocumentManageController.php', @@ -6434,6 +6435,7 @@ phutil_register_library_map(array( 'LegalpadDocumentDatasource' => 'PhabricatorTypeaheadDatasource', 'LegalpadDocumentDoneController' => 'LegalpadController', 'LegalpadDocumentEditController' => 'LegalpadController', + 'LegalpadDocumentEditEngine' => 'PhabricatorEditEngine', 'LegalpadDocumentEditor' => 'PhabricatorApplicationTransactionEditor', 'LegalpadDocumentListController' => 'LegalpadController', 'LegalpadDocumentManageController' => 'LegalpadController', diff --git a/src/applications/legalpad/application/PhabricatorLegalpadApplication.php b/src/applications/legalpad/application/PhabricatorLegalpadApplication.php index 709fd7cc07..ecdb3f337b 100644 --- a/src/applications/legalpad/application/PhabricatorLegalpadApplication.php +++ b/src/applications/legalpad/application/PhabricatorLegalpadApplication.php @@ -53,9 +53,10 @@ final class PhabricatorLegalpadApplication extends PhabricatorApplication { '/L(?P\d+)' => 'LegalpadDocumentSignController', '/legalpad/' => array( '' => 'LegalpadDocumentListController', - '(?:query/(?P[^/]+)/)?' => 'LegalpadDocumentListController', - 'create/' => 'LegalpadDocumentEditController', - 'edit/(?P\d+)/' => 'LegalpadDocumentEditController', + '(?:query/(?P[^/]+)/)?' + => 'LegalpadDocumentListController', + $this->getEditRoutePattern('edit/') + => 'LegalpadDocumentEditController', 'comment/(?P\d+)/' => 'LegalpadDocumentCommentController', 'view/(?P\d+)/' => 'LegalpadDocumentManageController', 'done/' => 'LegalpadDocumentDoneController', diff --git a/src/applications/legalpad/controller/LegalpadController.php b/src/applications/legalpad/controller/LegalpadController.php index fbfb7038f4..006f1329d5 100644 --- a/src/applications/legalpad/controller/LegalpadController.php +++ b/src/applications/legalpad/controller/LegalpadController.php @@ -9,7 +9,7 @@ abstract class LegalpadController extends PhabricatorController { $nav->setBaseURI(new PhutilURI($this->getApplicationURI())); if ($for_app) { - $nav->addFilter('create/', pht('Create Document')); + $nav->addFilter('edit/', pht('Create Document')); } id(new LegalpadDocumentSearchEngine()) diff --git a/src/applications/legalpad/controller/LegalpadDocumentEditController.php b/src/applications/legalpad/controller/LegalpadDocumentEditController.php index 9b1d2ead22..be46a55dab 100644 --- a/src/applications/legalpad/controller/LegalpadDocumentEditController.php +++ b/src/applications/legalpad/controller/LegalpadDocumentEditController.php @@ -3,275 +3,9 @@ final class LegalpadDocumentEditController extends LegalpadController { public function handleRequest(AphrontRequest $request) { - $viewer = $request->getViewer(); - $id = $request->getURIData('id'); - - if (!$id) { - $is_create = true; - - $this->requireApplicationCapability( - LegalpadCreateDocumentsCapability::CAPABILITY); - - $document = LegalpadDocument::initializeNewDocument($viewer); - $body = id(new LegalpadDocumentBody()) - ->setCreatorPHID($viewer->getPHID()); - $document->attachDocumentBody($body); - $document->setDocumentBodyPHID(PhabricatorPHIDConstants::PHID_VOID); - } else { - $is_create = false; - - $document = id(new LegalpadDocumentQuery()) - ->setViewer($viewer) - ->needDocumentBodies(true) - ->requireCapabilities( - array( - PhabricatorPolicyCapability::CAN_VIEW, - PhabricatorPolicyCapability::CAN_EDIT, - )) - ->withIDs(array($id)) - ->executeOne(); - if (!$document) { - return new Aphront404Response(); - } - } - - $e_title = true; - $e_text = true; - - $title = $document->getDocumentBody()->getTitle(); - $text = $document->getDocumentBody()->getText(); - $v_signature_type = $document->getSignatureType(); - $v_preamble = $document->getPreamble(); - $v_require_signature = $document->getRequireSignature(); - - $errors = array(); - $can_view = null; - $can_edit = null; - if ($request->isFormPost()) { - - $xactions = array(); - - $title = $request->getStr('title'); - if (!strlen($title)) { - $e_title = pht('Required'); - $errors[] = pht('The document title may not be blank.'); - } else { - $xactions[] = id(new LegalpadTransaction()) - ->setTransactionType( - LegalpadDocumentTitleTransaction::TRANSACTIONTYPE) - ->setNewValue($title); - } - - $text = $request->getStr('text'); - if (!strlen($text)) { - $e_text = pht('Required'); - $errors[] = pht('The document may not be blank.'); - } else { - $xactions[] = id(new LegalpadTransaction()) - ->setTransactionType( - LegalpadDocumentTextTransaction::TRANSACTIONTYPE) - ->setNewValue($text); - } - - $can_view = $request->getStr('can_view'); - $xactions[] = id(new LegalpadTransaction()) - ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY) - ->setNewValue($can_view); - $can_edit = $request->getStr('can_edit'); - $xactions[] = id(new LegalpadTransaction()) - ->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY) - ->setNewValue($can_edit); - - if ($is_create) { - $v_signature_type = $request->getStr('signatureType'); - $xactions[] = id(new LegalpadTransaction()) - ->setTransactionType( - LegalpadDocumentSignatureTypeTransaction::TRANSACTIONTYPE) - ->setNewValue($v_signature_type); - } - - $v_preamble = $request->getStr('preamble'); - $xactions[] = id(new LegalpadTransaction()) - ->setTransactionType( - LegalpadDocumentPreambleTransaction::TRANSACTIONTYPE) - ->setNewValue($v_preamble); - - $v_require_signature = $request->getBool('requireSignature', 0); - if ($v_require_signature) { - if (!$viewer->getIsAdmin()) { - $errors[] = pht('Only admins may require signature.'); - } - $individual = LegalpadDocument::SIGNATURE_TYPE_INDIVIDUAL; - if ($v_signature_type != $individual) { - $errors[] = pht( - 'Only documents with signature type "individual" may require '. - 'signing to use Phabricator.'); - } - } - if ($viewer->getIsAdmin()) { - $xactions[] = id(new LegalpadTransaction()) - ->setTransactionType( - LegalpadDocumentRequireSignatureTransaction::TRANSACTIONTYPE) - ->setNewValue($v_require_signature); - } - - if (!$errors) { - $editor = id(new LegalpadDocumentEditor()) - ->setContentSourceFromRequest($request) - ->setContinueOnNoEffect(true) - ->setActor($viewer); - - $xactions = $editor->applyTransactions($document, $xactions); - - return id(new AphrontRedirectResponse()) - ->setURI($this->getApplicationURI('view/'.$document->getID())); - } - } - - if ($errors) { - // set these to what was specified in the form on post - $document->setViewPolicy($can_view); - $document->setEditPolicy($can_edit); - } - - $form = id(new AphrontFormView()) - ->setUser($viewer) - ->appendChild( - id(new AphrontFormTextControl()) - ->setID('document-title') - ->setLabel(pht('Title')) - ->setError($e_title) - ->setValue($title) - ->setName('title')); - - if ($is_create) { - $form->appendChild( - id(new AphrontFormSelectControl()) - ->setLabel(pht('Who Should Sign?')) - ->setName(pht('signatureType')) - ->setValue($v_signature_type) - ->setOptions(LegalpadDocument::getSignatureTypeMap())); - $show_require = true; - $caption = pht('Applies only to documents individuals sign.'); - } else { - $form->appendChild( - id(new AphrontFormMarkupControl()) - ->setLabel(pht('Who Should Sign?')) - ->setValue($document->getSignatureTypeName())); - $individual = LegalpadDocument::SIGNATURE_TYPE_INDIVIDUAL; - $show_require = $document->getSignatureType() == $individual; - $caption = null; - } - - if ($show_require) { - $form - ->appendChild( - id(new AphrontFormCheckboxControl()) - ->setDisabled(!$viewer->getIsAdmin()) - ->setLabel(pht('Require Signature')) - ->addCheckbox( - 'requireSignature', - 'requireSignature', - pht('Should signing this document be required to use Phabricator?'), - $v_require_signature) - ->setCaption($caption)); - } - - $form - ->appendChild( - id(new PhabricatorRemarkupControl()) - ->setUser($viewer) - ->setID('preamble') - ->setLabel(pht('Preamble')) - ->setValue($v_preamble) - ->setName('preamble') - ->setCaption( - pht('Optional help text for users signing this document.'))) - ->appendChild( - id(new PhabricatorRemarkupControl()) - ->setUser($viewer) - ->setID('document-text') - ->setLabel(pht('Document Body')) - ->setError($e_text) - ->setValue($text) - ->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL) - ->setName('text')); - - $policies = id(new PhabricatorPolicyQuery()) - ->setViewer($viewer) - ->setObject($document) - ->execute(); - - $form - ->appendChild( - id(new AphrontFormPolicyControl()) - ->setUser($viewer) - ->setCapability(PhabricatorPolicyCapability::CAN_VIEW) - ->setPolicyObject($document) - ->setPolicies($policies) - ->setName('can_view')) - ->appendChild( - id(new AphrontFormPolicyControl()) - ->setUser($viewer) - ->setCapability(PhabricatorPolicyCapability::CAN_EDIT) - ->setPolicyObject($document) - ->setPolicies($policies) - ->setName('can_edit')); - - $crumbs = $this->buildApplicationCrumbs(); - $submit = new AphrontFormSubmitControl(); - if ($is_create) { - $submit->setValue(pht('Create Document')); - $submit->addCancelButton($this->getApplicationURI()); - $title = pht('Create Document'); - $short = pht('Create'); - $header_icon = 'fa-plus-square'; - } else { - $submit->setValue(pht('Save Document')); - $submit->addCancelButton( - $this->getApplicationURI('view/'.$document->getID())); - $title = pht('Edit Document: %s', $document->getTitle()); - $short = pht('Edit'); - $header_icon = 'fa-pencil'; - - $crumbs->addTextCrumb( - $document->getMonogram(), - $this->getApplicationURI('view/'.$document->getID())); - } - - $form->appendChild($submit); - - $form_box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Document')) - ->setFormErrors($errors) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->setForm($form); - - $crumbs->addTextCrumb($short); - $crumbs->setBorder(true); - - $preview = id(new PHUIRemarkupPreviewPanel()) - ->setHeader($document->getTitle()) - ->setPreviewURI($this->getApplicationURI('document/preview/')) - ->setControlID('document-text') - ->setPreviewType(PHUIRemarkupPreviewPanel::DOCUMENT); - - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setHeaderIcon($header_icon); - - $view = id(new PHUITwoColumnView()) - ->setHeader($header) - ->setFooter(array( - $form_box, - $preview, - )); - - return $this->newPage() - ->setTitle($title) - ->setCrumbs($crumbs) - ->appendChild($view); - + return id(new LegalpadDocumentEditEngine()) + ->setController($this) + ->buildResponse(); } } diff --git a/src/applications/legalpad/controller/LegalpadDocumentListController.php b/src/applications/legalpad/controller/LegalpadDocumentListController.php index cbd92f87a9..852f71970d 100644 --- a/src/applications/legalpad/controller/LegalpadDocumentListController.php +++ b/src/applications/legalpad/controller/LegalpadDocumentListController.php @@ -26,7 +26,7 @@ final class LegalpadDocumentListController extends LegalpadController { $crumbs->addAction( id(new PHUIListItemView()) ->setName(pht('Create Document')) - ->setHref($this->getApplicationURI('create/')) + ->setHref($this->getApplicationURI('edit/')) ->setIcon('fa-plus-square') ->setDisabled(!$can_create) ->setWorkflow(!$can_create)); diff --git a/src/applications/legalpad/editor/LegalpadDocumentEditEngine.php b/src/applications/legalpad/editor/LegalpadDocumentEditEngine.php new file mode 100644 index 0000000000..66660c9ec2 --- /dev/null +++ b/src/applications/legalpad/editor/LegalpadDocumentEditEngine.php @@ -0,0 +1,169 @@ +getViewer(); + + $document = LegalpadDocument::initializeNewDocument($viewer); + $body = id(new LegalpadDocumentBody()) + ->setCreatorPHID($viewer->getPHID()); + $document->attachDocumentBody($body); + $document->setDocumentBodyPHID(PhabricatorPHIDConstants::PHID_VOID); + + return $document; + } + + protected function newObjectQuery() { + return id(new LegalpadDocumentQuery()) + ->needDocumentBodies(true); + } + + protected function getObjectCreateTitleText($object) { + return pht('Create New Document'); + } + + protected function getObjectEditTitleText($object) { + $body = $object->getDocumentBody(); + $title = $body->getTitle(); + return pht('Edit Document: %s', $title); + } + + protected function getObjectEditShortText($object) { + $body = $object->getDocumentBody(); + return $body->getTitle(); + } + + protected function getObjectCreateShortText() { + return pht('Create Document'); + } + + protected function getObjectName() { + return pht('Document'); + } + + protected function getObjectCreateCancelURI($object) { + return $this->getApplication()->getApplicationURI('/'); + } + + protected function getEditorURI() { + return $this->getApplication()->getApplicationURI('edit/'); + } + + protected function getObjectViewURI($object) { + $id = $object->getID(); + return $this->getApplication()->getApplicationURI('view/'.$id.'/'); + } + + + protected function getCreateNewObjectPolicy() { + return $this->getApplication()->getPolicy( + LegalpadCreateDocumentsCapability::CAPABILITY); + } + + protected function buildCustomEditFields($object) { + $viewer = $this->getViewer(); + + $body = $object->getDocumentBody(); + $document_body = $body->getText(); + + $is_create = $this->getIsCreate(); + $is_admin = $viewer->getIsAdmin(); + + $fields = array(); + $fields[] = + id(new PhabricatorTextEditField()) + ->setKey('title') + ->setLabel(pht('Title')) + ->setDescription(pht('Document Title.')) + ->setConduitTypeDescription(pht('New document title.')) + ->setValue($object->getTitle()) + ->setIsRequired(true) + ->setTransactionType( + LegalpadDocumentTitleTransaction::TRANSACTIONTYPE); + + if ($is_create) { + $fields[] = + id(new PhabricatorSelectEditField()) + ->setKey('signatureType') + ->setLabel(pht('Who Should Sign?')) + ->setDescription(pht('Type of signature required')) + ->setConduitTypeDescription(pht('New document signature type.')) + ->setValue($object->getSignatureType()) + ->setOptions(LegalpadDocument::getSignatureTypeMap()) + ->setTransactionType( + LegalpadDocumentSignatureTypeTransaction::TRANSACTIONTYPE); + $show_require = true; + } else { + $fields[] = id(new PhabricatorStaticEditField()) + ->setLabel(pht('Who Should Sign?')) + ->setValue($object->getSignatureTypeName()); + $individual = LegalpadDocument::SIGNATURE_TYPE_INDIVIDUAL; + $show_require = $object->getSignatureType() == $individual; + } + + if ($show_require && $is_admin) { + $fields[] = + id(new PhabricatorBoolEditField()) + ->setKey('requireSignature') + ->setOptions( + pht('No Signature Required'), + pht('Signature Required to use Phabricator')) + ->setAsCheckbox(true) + ->setTransactionType( + LegalpadDocumentRequireSignatureTransaction::TRANSACTIONTYPE) + ->setDescription(pht('Marks this document as required signing.')) + ->setConduitDescription( + pht('Marks this document as required signing.')) + ->setValue($object->getRequireSignature()); + } + + $fields[] = + id(new PhabricatorRemarkupEditField()) + ->setKey('preamble') + ->setLabel(pht('Preamble')) + ->setDescription(pht('The preamble of the document.')) + ->setConduitTypeDescription(pht('New document preamble.')) + ->setValue($object->getPreamble()) + ->setTransactionType( + LegalpadDocumentPreambleTransaction::TRANSACTIONTYPE); + + $fields[] = + id(new PhabricatorRemarkupEditField()) + ->setKey('text') + ->setLabel(pht('Document Body')) + ->setDescription(pht('The body of text of the document.')) + ->setConduitTypeDescription(pht('New document body.')) + ->setValue($document_body) + ->setIsRequired(true) + ->setTransactionType( + LegalpadDocumentTextTransaction::TRANSACTIONTYPE); + + return $fields; + + } + +} diff --git a/src/applications/legalpad/editor/LegalpadDocumentEditor.php b/src/applications/legalpad/editor/LegalpadDocumentEditor.php index 14430b2c33..7882635285 100644 --- a/src/applications/legalpad/editor/LegalpadDocumentEditor.php +++ b/src/applications/legalpad/editor/LegalpadDocumentEditor.php @@ -21,6 +21,14 @@ final class LegalpadDocumentEditor return $types; } + public function getCreateObjectTitle($author, $object) { + return pht('%s created this document.', $author); + } + + public function getCreateObjectTitleForFeed($author, $object) { + return pht('%s created %s.', $author, $object); + } + protected function applyFinalEffects( PhabricatorLiskDAO $object, array $xactions) { @@ -64,6 +72,37 @@ final class LegalpadDocumentEditor return $xactions; } + protected function validateAllTransactions(PhabricatorLiskDAO $object, + array $xactions) { + $errors = array(); + + $is_required = (bool)$object->getRequireSignature(); + $document_type = $object->getSignatureType(); + $individual = LegalpadDocument::SIGNATURE_TYPE_INDIVIDUAL; + + foreach ($xactions as $xaction) { + switch ($xaction->getTransactionType()) { + case LegalpadDocumentRequireSignatureTransaction::TRANSACTIONTYPE: + $is_required = (bool)$xaction->getNewValue(); + break; + case LegalpadDocumentSignatureTypeTransaction::TRANSACTIONTYPE: + $document_type = $xaction->getNewValue(); + break; + } + } + + if ($is_required && ($document_type != $individual)) { + $errors[] = new PhabricatorApplicationTransactionValidationError( + LegalpadDocumentRequireSignatureTransaction::TRANSACTIONTYPE, + pht('Invalid'), + pht('Only documents with signature type "individual" may '. + 'require signing to use Phabricator.'), + null); + } + + return $errors; + } + /* -( Sending Mail )------------------------------------------------------- */ diff --git a/src/applications/legalpad/storage/LegalpadDocument.php b/src/applications/legalpad/storage/LegalpadDocument.php index fcecac991f..55d1ef9fa9 100644 --- a/src/applications/legalpad/storage/LegalpadDocument.php +++ b/src/applications/legalpad/storage/LegalpadDocument.php @@ -120,6 +120,10 @@ final class LegalpadDocument extends LegalpadDAO return 'L'.$this->getID(); } + public function getViewURI() { + return '/'.$this->getMonogram(); + } + public function getUserSignature($phid) { return $this->assertAttachedKey($this->userSignatures, $phid); } diff --git a/src/applications/legalpad/xaction/LegalpadDocumentRequireSignatureTransaction.php b/src/applications/legalpad/xaction/LegalpadDocumentRequireSignatureTransaction.php index 2122ff10fa..3819f38a70 100644 --- a/src/applications/legalpad/xaction/LegalpadDocumentRequireSignatureTransaction.php +++ b/src/applications/legalpad/xaction/LegalpadDocumentRequireSignatureTransaction.php @@ -10,11 +10,11 @@ final class LegalpadDocumentRequireSignatureTransaction } public function applyInternalEffects($object, $value) { - $object->setRequireSignature($value); + $object->setRequireSignature((int)$value); } public function applyExternalEffects($object, $value) { - if (strlen($value)) { + if ($value) { $session = new PhabricatorAuthSession(); queryfx( $session->establishConnection('w'), @@ -25,6 +25,7 @@ final class LegalpadDocumentRequireSignatureTransaction public function getTitle() { $new = $this->getNewValue(); + if ($new) { return pht( '%s set the document to require signatures.', @@ -51,6 +52,19 @@ final class LegalpadDocumentRequireSignatureTransaction } } + public function validateTransactions($object, array $xactions) { + $errors = array(); + + $is_admin = $this->getActor()->getIsAdmin(); + + if (!$is_admin) { + $errors[] = $this->newInvalidError( + pht('Only admins may require signature.')); + } + + return $errors; + } + public function getIcon() { return 'fa-pencil-square'; }