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

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
This commit is contained in:
Chad Little 2017-05-10 15:11:39 -07:00
parent bc4edc946b
commit b32a00dbac
9 changed files with 239 additions and 276 deletions

View file

@ -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',

View file

@ -53,9 +53,10 @@ final class PhabricatorLegalpadApplication extends PhabricatorApplication {
'/L(?P<id>\d+)' => 'LegalpadDocumentSignController',
'/legalpad/' => array(
'' => 'LegalpadDocumentListController',
'(?:query/(?P<queryKey>[^/]+)/)?' => 'LegalpadDocumentListController',
'create/' => 'LegalpadDocumentEditController',
'edit/(?P<id>\d+)/' => 'LegalpadDocumentEditController',
'(?:query/(?P<queryKey>[^/]+)/)?'
=> 'LegalpadDocumentListController',
$this->getEditRoutePattern('edit/')
=> 'LegalpadDocumentEditController',
'comment/(?P<id>\d+)/' => 'LegalpadDocumentCommentController',
'view/(?P<id>\d+)/' => 'LegalpadDocumentManageController',
'done/' => 'LegalpadDocumentDoneController',

View file

@ -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())

View file

@ -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();
}
}

View file

@ -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));

View file

@ -0,0 +1,169 @@
<?php
final class LegalpadDocumentEditEngine
extends PhabricatorEditEngine {
const ENGINECONST = 'legalpad.document';
public function getEngineName() {
return pht('Legalpad');
}
public function getEngineApplicationClass() {
return 'PhabricatorLegalpadApplication';
}
public function getSummaryHeader() {
return pht('Configure Legalpad Forms');
}
public function getSummaryText() {
return pht('Configure creation and editing documents in Legalpad.');
}
public function isEngineConfigurable() {
return false;
}
protected function newEditableObject() {
$viewer = $this->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;
}
}

View file

@ -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 )------------------------------------------------------- */

View file

@ -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);
}

View file

@ -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';
}