@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Legalpad V0.1

Summary:
got some basics here --

- can create document
- creates document object and document body object and cross-reference
- can update document
- creates document body object and updates reference from document object
- contributors stored correctly
- a contributor is anyone who has created or updated a legal document
- can subscribe to documents
- can flag documents
- can comment on documents
- can query for documents based on creator and create range
- uses basically modern stuff

Missing stuff --

- T3488
- T3483
- T3482
- T3481
- T3480
- T3479

Test Plan: TRUNCATED the database. From scratch made 3 legal docs. Verified versions and version were correct in document and document body database entries respectively. Left comments and verified versions and version did not update. Left updates and verified those updated versions and version. Flagged document and verified it showed up on homepage. Subscribed and verified transaction showed up.

Reviewers: epriestley

Reviewed By: epriestley

CC: chad, aran, Korvin

Maniphest Tasks: T3116

Differential Revision: https://secure.phabricator.com/D6351

+1506
+9
src/__celerity_resource_map__.php
··· 2819 2819 ), 2820 2820 'disk' => '/rsrc/externals/javelin/lib/Workflow.js', 2821 2821 ), 2822 + 'legalpad-documentbody-css' => 2823 + array( 2824 + 'uri' => '/res/034c3494/rsrc/css/application/legalpad/legalpad-documentbody.css', 2825 + 'type' => 'css', 2826 + 'requires' => 2827 + array( 2828 + ), 2829 + 'disk' => '/rsrc/css/application/legalpad/legalpad-documentbody.css', 2830 + ), 2822 2831 'lightbox-attachment-css' => 2823 2832 array( 2824 2833 'uri' => '/res/4657e15d/rsrc/css/aphront/lightbox-attachment.css',
+51
src/__phutil_library_map__.php
··· 629 629 'JavelinUIExample' => 'applications/uiexample/examples/JavelinUIExample.php', 630 630 'JavelinViewExample' => 'applications/uiexample/examples/JavelinViewExample.php', 631 631 'JavelinViewExampleServerView' => 'applications/uiexample/examples/JavelinViewExampleServerView.php', 632 + 'LegalpadConstants' => 'applications/legalpad/constants/LegalpadConstants.php', 633 + 'LegalpadController' => 'applications/legalpad/controller/LegalpadController.php', 634 + 'LegalpadDAO' => 'applications/legalpad/storage/LegalpadDAO.php', 635 + 'LegalpadDocument' => 'applications/legalpad/storage/LegalpadDocument.php', 636 + 'LegalpadDocumentBody' => 'applications/legalpad/storage/LegalpadDocumentBody.php', 637 + 'LegalpadDocumentCommentController' => 'applications/legalpad/controller/LegalpadDocumentCommentController.php', 638 + 'LegalpadDocumentEditController' => 'applications/legalpad/controller/LegalpadDocumentEditController.php', 639 + 'LegalpadDocumentEditor' => 'applications/legalpad/editor/LegalpadDocumentEditor.php', 640 + 'LegalpadDocumentListController' => 'applications/legalpad/controller/LegalpadDocumentListController.php', 641 + 'LegalpadDocumentQuery' => 'applications/legalpad/query/LegalpadDocumentQuery.php', 642 + 'LegalpadDocumentSearchEngine' => 'applications/legalpad/query/LegalpadDocumentSearchEngine.php', 643 + 'LegalpadDocumentSignature' => 'applications/legalpad/storage/LegalpadDocumentSignature.php', 644 + 'LegalpadDocumentViewController' => 'applications/legalpad/controller/LegalpadDocumentViewController.php', 645 + 'LegalpadTransaction' => 'applications/legalpad/storage/LegalpadTransaction.php', 646 + 'LegalpadTransactionComment' => 'applications/legalpad/storage/LegalpadTransactionComment.php', 647 + 'LegalpadTransactionQuery' => 'applications/legalpad/query/LegalpadTransactionQuery.php', 648 + 'LegalpadTransactionType' => 'applications/legalpad/constants/LegalpadTransactionType.php', 649 + 'LegalpadTransactionView' => 'applications/legalpad/view/LegalpadTransactionView.php', 632 650 'LiskChunkTestCase' => 'infrastructure/storage/lisk/__tests__/LiskChunkTestCase.php', 633 651 'LiskDAO' => 'infrastructure/storage/lisk/LiskDAO.php', 634 652 'LiskDAOSet' => 'infrastructure/storage/lisk/LiskDAOSet.php', ··· 761 779 'PhabricatorApplicationFlags' => 'applications/flag/application/PhabricatorApplicationFlags.php', 762 780 'PhabricatorApplicationHerald' => 'applications/herald/application/PhabricatorApplicationHerald.php', 763 781 'PhabricatorApplicationLaunchView' => 'applications/meta/view/PhabricatorApplicationLaunchView.php', 782 + 'PhabricatorApplicationLegalpad' => 'applications/legalpad/application/PhabricatorApplicationLegalpad.php', 764 783 'PhabricatorApplicationMacro' => 'applications/macro/application/PhabricatorApplicationMacro.php', 765 784 'PhabricatorApplicationMailingLists' => 'applications/mailinglists/application/PhabricatorApplicationMailingLists.php', 766 785 'PhabricatorApplicationManiphest' => 'applications/maniphest/application/PhabricatorApplicationManiphest.php', ··· 2523 2542 'JavelinUIExample' => 'PhabricatorUIExample', 2524 2543 'JavelinViewExample' => 'PhabricatorUIExample', 2525 2544 'JavelinViewExampleServerView' => 'AphrontView', 2545 + 'LegalpadController' => 'PhabricatorController', 2546 + 'LegalpadDAO' => 'PhabricatorLiskDAO', 2547 + 'LegalpadDocument' => 2548 + array( 2549 + 0 => 'LegalpadDAO', 2550 + 1 => 'PhabricatorPolicyInterface', 2551 + 2 => 'PhabricatorSubscribableInterface', 2552 + 3 => 'PhabricatorApplicationTransactionInterface', 2553 + ), 2554 + 'LegalpadDocumentBody' => 2555 + array( 2556 + 0 => 'LegalpadDAO', 2557 + 1 => 'PhabricatorMarkupInterface', 2558 + ), 2559 + 'LegalpadDocumentCommentController' => 'LegalpadController', 2560 + 'LegalpadDocumentEditController' => 'LegalpadController', 2561 + 'LegalpadDocumentEditor' => 'PhabricatorApplicationTransactionEditor', 2562 + 'LegalpadDocumentListController' => 2563 + array( 2564 + 0 => 'LegalpadController', 2565 + 1 => 'PhabricatorApplicationSearchResultsControllerInterface', 2566 + ), 2567 + 'LegalpadDocumentQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 2568 + 'LegalpadDocumentSearchEngine' => 'PhabricatorApplicationSearchEngine', 2569 + 'LegalpadDocumentSignature' => 'LegalpadDAO', 2570 + 'LegalpadDocumentViewController' => 'LegalpadController', 2571 + 'LegalpadTransaction' => 'PhabricatorApplicationTransaction', 2572 + 'LegalpadTransactionComment' => 'PhabricatorApplicationTransactionComment', 2573 + 'LegalpadTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 2574 + 'LegalpadTransactionType' => 'LegalpadConstants', 2575 + 'LegalpadTransactionView' => 'PhabricatorApplicationTransactionView', 2526 2576 'LiskChunkTestCase' => 'PhabricatorTestCase', 2527 2577 'LiskDAOTestCase' => 'PhabricatorTestCase', 2528 2578 'LiskEphemeralObjectException' => 'Exception', ··· 2656 2706 'PhabricatorApplicationFlags' => 'PhabricatorApplication', 2657 2707 'PhabricatorApplicationHerald' => 'PhabricatorApplication', 2658 2708 'PhabricatorApplicationLaunchView' => 'AphrontView', 2709 + 'PhabricatorApplicationLegalpad' => 'PhabricatorApplication', 2659 2710 'PhabricatorApplicationMacro' => 'PhabricatorApplication', 2660 2711 'PhabricatorApplicationMailingLists' => 'PhabricatorApplication', 2661 2712 'PhabricatorApplicationManiphest' => 'PhabricatorApplication',
+53
src/applications/legalpad/application/PhabricatorApplicationLegalpad.php
··· 1 + <?php 2 + 3 + /** 4 + * @group legalpad 5 + */ 6 + final class PhabricatorApplicationLegalpad extends PhabricatorApplication { 7 + 8 + public function getBaseURI() { 9 + return '/legalpad/'; 10 + } 11 + 12 + public function getShortDescription() { 13 + return pht('Legal Documents.'); 14 + } 15 + 16 + public function getIconName() { 17 + return 'legalpad'; 18 + } 19 + 20 + public function getTitleGlyph() { 21 + return "\xC2\xA9"; 22 + } 23 + 24 + public function getFlavorText() { 25 + return pht('With advanced signature technology.'); 26 + } 27 + 28 + public function getApplicationGroup() { 29 + return self::GROUP_COMMUNICATION; 30 + } 31 + 32 + public function getQuickCreateURI() { 33 + return $this->getBaseURI().'create/'; 34 + } 35 + 36 + 37 + public function isBeta() { 38 + return true; 39 + } 40 + 41 + public function getRoutes() { 42 + return array( 43 + '/legalpad/' => array( 44 + '' => 'LegalpadDocumentListController', 45 + '(query/(?P<queryKey>[^/]+)/)?' => 'LegalpadDocumentListController', 46 + 'create/' => 'LegalpadDocumentEditController', 47 + 'edit/(?P<id>\d+)/' => 'LegalpadDocumentEditController', 48 + 'comment/(?P<id>\d+)/' => 'LegalpadDocumentCommentController', 49 + 'view/(?P<id>\d+)/' => 'LegalpadDocumentViewController', 50 + )); 51 + } 52 + 53 + }
+8
src/applications/legalpad/constants/LegalpadConstants.php
··· 1 + <?php 2 + 3 + /** 4 + * @group legalpad 5 + */ 6 + abstract class LegalpadConstants { 7 + 8 + }
+11
src/applications/legalpad/constants/LegalpadTransactionType.php
··· 1 + <?php 2 + 3 + /** 4 + * @group legalpad 5 + */ 6 + final class LegalpadTransactionType extends LegalpadConstants { 7 + 8 + const TYPE_TITLE = 'title'; 9 + const TYPE_TEXT = 'text'; 10 + 11 + }
+41
src/applications/legalpad/controller/LegalpadController.php
··· 1 + <?php 2 + 3 + /** 4 + * @group legalpad 5 + */ 6 + abstract class LegalpadController extends PhabricatorController { 7 + 8 + public function buildSideNav($for_app = false) { 9 + $user = $this->getRequest()->getUser(); 10 + 11 + $nav = new AphrontSideNavFilterView(); 12 + $nav->setBaseURI(new PhutilURI($this->getApplicationURI())); 13 + 14 + if ($for_app) { 15 + $nav->addFilter('create/', pht('Create Document')); 16 + } 17 + 18 + id(new LegalpadDocumentSearchEngine()) 19 + ->setViewer($user) 20 + ->addNavigationItems($nav->getMenu()); 21 + 22 + return $nav; 23 + } 24 + 25 + public function buildApplicationCrumbs() { 26 + $crumbs = parent::buildApplicationCrumbs(); 27 + 28 + $crumbs->addAction( 29 + id(new PHUIListItemView()) 30 + ->setName(pht('Create Document')) 31 + ->setHref($this->getApplicationURI('create/')) 32 + ->setIcon('create')); 33 + 34 + return $crumbs; 35 + } 36 + 37 + public function buildApplicationMenu() { 38 + return $this->buildSideNav(true)->getMenu(); 39 + } 40 + 41 + }
+81
src/applications/legalpad/controller/LegalpadDocumentCommentController.php
··· 1 + <?php 2 + 3 + /** 4 + * @group legalpad 5 + */ 6 + final class LegalpadDocumentCommentController extends LegalpadController { 7 + 8 + private $id; 9 + 10 + public function willProcessRequest(array $data) { 11 + $this->id = $data['id']; 12 + } 13 + 14 + public function processRequest() { 15 + $request = $this->getRequest(); 16 + $user = $request->getUser(); 17 + 18 + if (!$request->isFormPost()) { 19 + return new Aphront400Response(); 20 + } 21 + 22 + $document = id(new LegalpadDocumentQuery()) 23 + ->setViewer($user) 24 + ->withIDs(array($this->id)) 25 + ->executeOne(); 26 + 27 + if (!$document) { 28 + return new Aphront404Response(); 29 + } 30 + 31 + $is_preview = $request->isPreviewRequest(); 32 + 33 + $draft = PhabricatorDraft::buildFromRequest($request); 34 + 35 + $document_uri = $this->getApplicationURI('view/'.$document->getID()); 36 + 37 + $comment = $request->getStr('comment'); 38 + 39 + $xactions = array(); 40 + 41 + if (strlen($comment)) { 42 + $xactions[] = id(new LegalpadTransaction()) 43 + ->setTransactionType(PhabricatorTransactions::TYPE_COMMENT) 44 + ->attachComment( 45 + id(new LegalpadTransactionComment()) 46 + ->setDocumentID($document->getID()) 47 + ->setLineNumber(0) 48 + ->setLineLength(0) 49 + ->setContent($comment)); 50 + } 51 + 52 + $editor = id(new LegalpadDocumentEditor()) 53 + ->setActor($user) 54 + ->setContentSourceFromRequest($request) 55 + ->setContinueOnNoEffect($request->isContinueRequest()) 56 + ->setIsPreview($is_preview); 57 + 58 + try { 59 + $xactions = $editor->applyTransactions($document, $xactions); 60 + } catch (PhabricatorApplicationTransactionNoEffectException $ex) { 61 + return id(new PhabricatorApplicationTransactionNoEffectResponse()) 62 + ->setCancelURI($document_uri) 63 + ->setException($ex); 64 + } 65 + 66 + if ($draft) { 67 + $draft->replaceOrDelete(); 68 + } 69 + 70 + if ($request->isAjax()) { 71 + return id(new PhabricatorApplicationTransactionResponse()) 72 + ->setViewer($user) 73 + ->setTransactions($xactions) 74 + ->setIsPreview($is_preview) 75 + ->setAnchorOffset($request->getStr('anchor')); 76 + } else { 77 + return id(new AphrontRedirectResponse())->setURI($document_uri); 78 + } 79 + } 80 + 81 + }
+184
src/applications/legalpad/controller/LegalpadDocumentEditController.php
··· 1 + <?php 2 + 3 + /** 4 + * @group legalpad 5 + */ 6 + final class LegalpadDocumentEditController extends LegalpadController { 7 + 8 + private $id; 9 + 10 + public function willProcessRequest(array $data) { 11 + $this->id = idx($data, 'id'); 12 + } 13 + 14 + public function processRequest() { 15 + $request = $this->getRequest(); 16 + $user = $request->getUser(); 17 + 18 + if (!$this->id) { 19 + $is_create = true; 20 + 21 + $document = id(new LegalpadDocument()) 22 + ->setVersions(0) 23 + ->setCreatorPHID($user->getPHID()) 24 + ->setViewPolicy(PhabricatorPolicies::POLICY_USER) 25 + ->setEditPolicy(PhabricatorPolicies::POLICY_USER); 26 + $body = id(new LegalpadDocumentBody()) 27 + ->setCreatorPHID($user->getPHID()); 28 + $document->attachDocumentBody($body); 29 + $document->setDocumentBodyPHID(PhabricatorPHIDConstants::PHID_VOID); 30 + $title = null; 31 + $text = null; 32 + } else { 33 + $is_create = false; 34 + 35 + $document = id(new LegalpadDocumentQuery()) 36 + ->setViewer($user) 37 + ->needDocumentBodies(true) 38 + ->requireCapabilities( 39 + array( 40 + PhabricatorPolicyCapability::CAN_VIEW, 41 + PhabricatorPolicyCapability::CAN_EDIT, 42 + )) 43 + ->withIDs(array($this->id)) 44 + ->executeOne(); 45 + if (!$document) { 46 + return new Aphront404Response(); 47 + } 48 + $title = $document->getDocumentBody()->getTitle(); 49 + $text = $document->getDocumentBody()->getText(); 50 + } 51 + 52 + $e_title = true; 53 + $e_text = true; 54 + $errors = array(); 55 + $can_view = null; 56 + $can_edit = null; 57 + if ($request->isFormPost()) { 58 + 59 + $xactions = array(); 60 + 61 + $title = $request->getStr('title'); 62 + if (!strlen($title)) { 63 + $e_title = pht('Required'); 64 + $errors[] = pht('The document title may not be blank.'); 65 + } else { 66 + $xactions[] = id(new LegalpadTransaction()) 67 + ->setTransactionType(LegalpadTransactionType::TYPE_TITLE) 68 + ->setNewValue($title); 69 + } 70 + 71 + $text = $request->getStr('text'); 72 + if (!strlen($text)) { 73 + $e_text = pht('Required'); 74 + $errors[] = pht('The document may not be blank.'); 75 + } else { 76 + $xactions[] = id(new LegalpadTransaction()) 77 + ->setTransactionType(LegalpadTransactionType::TYPE_TEXT) 78 + ->setNewValue($text); 79 + } 80 + 81 + $can_view = $request->getStr('can_view'); 82 + $xactions[] = id(new LegalpadTransaction()) 83 + ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY) 84 + ->setNewValue($can_view); 85 + $can_edit = $request->getStr('can_edit'); 86 + $xactions[] = id(new LegalpadTransaction()) 87 + ->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY) 88 + ->setNewValue($can_edit); 89 + 90 + if (!$errors) { 91 + $editor = id(new LegalpadDocumentEditor()) 92 + ->setContentSourceFromRequest($request) 93 + ->setContinueOnNoEffect(true) 94 + ->setActor($user); 95 + 96 + $xactions = $editor->applyTransactions($document, $xactions); 97 + 98 + return id(new AphrontRedirectResponse()) 99 + ->setURI($this->getApplicationURI('view/'.$document->getID())); 100 + } 101 + } 102 + 103 + $error_view = null; 104 + if ($errors) { 105 + $error_view = id(new AphrontErrorView()) 106 + ->setTitle(pht('A Fatal Omission!')) 107 + ->setErrors($errors); 108 + // set these to what was specified in the form on post 109 + $document->setViewPolicy($can_view); 110 + $document->setEditPolicy($can_edit); 111 + } 112 + 113 + $form = id(new AphrontFormView()) 114 + ->setFlexible(true) 115 + ->setUser($user) 116 + ->appendChild( 117 + id(new AphrontFormTextControl()) 118 + ->setLabel(pht('Title')) 119 + ->setError($e_title) 120 + ->setValue($title) 121 + ->setName('title')) 122 + ->appendChild( 123 + id(new PhabricatorRemarkupControl()) 124 + ->setLabel(pht('Text')) 125 + ->setError($e_text) 126 + ->setValue($text) 127 + ->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL) 128 + ->setName('text')); 129 + 130 + $policies = id(new PhabricatorPolicyQuery()) 131 + ->setViewer($user) 132 + ->setObject($document) 133 + ->execute(); 134 + 135 + $form 136 + ->appendChild( 137 + id(new AphrontFormPolicyControl()) 138 + ->setUser($user) 139 + ->setCapability(PhabricatorPolicyCapability::CAN_VIEW) 140 + ->setPolicyObject($document) 141 + ->setPolicies($policies) 142 + ->setName('can_view')) 143 + ->appendChild( 144 + id(new AphrontFormPolicyControl()) 145 + ->setUser($user) 146 + ->setCapability(PhabricatorPolicyCapability::CAN_EDIT) 147 + ->setPolicyObject($document) 148 + ->setPolicies($policies) 149 + ->setName('can_edit')); 150 + 151 + $submit = new AphrontFormSubmitControl(); 152 + if ($is_create) { 153 + $submit->setValue(pht('Create Document')); 154 + $title = pht('Create Document'); 155 + $short = pht('Create'); 156 + } else { 157 + $submit->setValue(pht('Update Document')); 158 + $submit->addCancelButton( 159 + $this->getApplicationURI('view/'.$document->getID())); 160 + $title = pht('Update Document'); 161 + $short = pht('Update'); 162 + } 163 + 164 + $form 165 + ->appendChild($submit); 166 + 167 + $crumbs = $this->buildApplicationCrumbs($this->buildSideNav()); 168 + $crumbs->addCrumb( 169 + id(new PhabricatorCrumbView())->setName($short)); 170 + 171 + return $this->buildApplicationPage( 172 + array( 173 + $crumbs, 174 + $error_view, 175 + $form, 176 + ), 177 + array( 178 + 'title' => $title, 179 + 'device' => true, 180 + 'dust' => true, 181 + )); 182 + } 183 + 184 + }
+60
src/applications/legalpad/controller/LegalpadDocumentListController.php
··· 1 + <?php 2 + 3 + /** 4 + * @group legalpad 5 + */ 6 + final class LegalpadDocumentListController extends LegalpadController 7 + implements PhabricatorApplicationSearchResultsControllerInterface { 8 + 9 + private $queryKey; 10 + 11 + public function willProcessRequest(array $data) { 12 + $this->queryKey = idx($data, 'queryKey'); 13 + } 14 + 15 + public function processRequest() { 16 + $request = $this->getRequest(); 17 + $controller = id(new PhabricatorApplicationSearchController($request)) 18 + ->setQueryKey($this->queryKey) 19 + ->setSearchEngine(new LegalpadDocumentSearchEngine()) 20 + ->setNavigation($this->buildSideNav()); 21 + 22 + return $this->delegateToController($controller); 23 + } 24 + 25 + public function renderResultsList( 26 + array $documents, 27 + PhabricatorSavedQuery $query) { 28 + assert_instances_of($documents, 'LegalpadDocument'); 29 + 30 + $user = $this->getRequest()->getUser(); 31 + 32 + $contributors = array_mergev(mpull($documents, 'getContributors')); 33 + $this->loadHandles($contributors); 34 + 35 + $list = new PhabricatorObjectItemListView(); 36 + $list->setUser($user); 37 + foreach ($documents as $document) { 38 + $document_body = $document->getDocumentBody(); 39 + $last_updated = phabricator_date($document->getDateModified(), $user); 40 + $updater = $this->getHandle( 41 + $document_body->getCreatorPHID())->renderLink(); 42 + 43 + $title = $document_body->getTitle(); 44 + 45 + $item = id(new PhabricatorObjectItemView()) 46 + ->setObjectName('L'.$document->getID()) 47 + ->setHeader($title) 48 + ->setHref($this->getApplicationURI('view/'.$document->getID())) 49 + ->setObject($document) 50 + ->addIcon('none', pht('Last updated: %s', $last_updated)) 51 + ->addByline(pht('Updated by: %s', $updater)) 52 + ->addAttribute(pht('Versions: %d', $document->getVersions())); 53 + 54 + $list->addItem($item); 55 + } 56 + 57 + return $list; 58 + } 59 + 60 + }
+241
src/applications/legalpad/controller/LegalpadDocumentViewController.php
··· 1 + <?php 2 + 3 + /** 4 + * @group legalpad 5 + */ 6 + final class LegalpadDocumentViewController extends LegalpadController { 7 + 8 + private $id; 9 + 10 + public function willProcessRequest(array $data) { 11 + $this->id = $data['id']; 12 + } 13 + 14 + public function processRequest() { 15 + $request = $this->getRequest(); 16 + $user = $request->getUser(); 17 + 18 + $document = id(new LegalpadDocumentQuery()) 19 + ->setViewer($user) 20 + ->withIDs(array($this->id)) 21 + ->needDocumentBodies(true) 22 + ->needContributors(true) 23 + ->executeOne(); 24 + 25 + if (!$document) { 26 + return new Aphront404Response(); 27 + } 28 + 29 + $xactions = id(new LegalpadTransactionQuery()) 30 + ->setViewer($user) 31 + ->withObjectPHIDs(array($document->getPHID())) 32 + ->execute(); 33 + 34 + $subscribers = PhabricatorSubscribersQuery::loadSubscribersForPHID( 35 + $document->getPHID()); 36 + 37 + $document_body = $document->getDocumentBody(); 38 + $phids = array(); 39 + $phids[] = $document_body->getCreatorPHID(); 40 + foreach ($subscribers as $subscriber) { 41 + $phids[] = $subscriber; 42 + } 43 + foreach ($document->getContributors() as $contributor) { 44 + $phids[] = $contributor; 45 + } 46 + $this->loadHandles($phids); 47 + 48 + $engine = id(new PhabricatorMarkupEngine()) 49 + ->setViewer($user); 50 + $engine->addObject( 51 + $document_body, 52 + LegalpadDocumentBody::MARKUP_FIELD_TITLE); 53 + $engine->addObject( 54 + $document_body, 55 + LegalpadDocumentBody::MARKUP_FIELD_TEXT); 56 + foreach ($xactions as $xaction) { 57 + if ($xaction->getComment()) { 58 + $engine->addObject( 59 + $xaction->getComment(), 60 + PhabricatorApplicationTransactionComment::MARKUP_FIELD_COMMENT); 61 + } 62 + } 63 + $engine->process(); 64 + 65 + $title = $document_body->getTitle(); 66 + 67 + $header = id(new PhabricatorHeaderView()) 68 + ->setHeader($title); 69 + 70 + $actions = $this->buildActionView($document); 71 + $properties = $this->buildPropertyView($document, $engine, $subscribers); 72 + 73 + $comment_form_id = celerity_generate_unique_node_id(); 74 + 75 + $xaction_view = id(new LegalpadTransactionView()) 76 + ->setUser($this->getRequest()->getUser()) 77 + ->setTransactions($xactions) 78 + ->setMarkupEngine($engine); 79 + 80 + $add_comment = $this->buildAddCommentView($document, $comment_form_id); 81 + 82 + $crumbs = $this->buildApplicationCrumbs($this->buildSideNav()); 83 + $crumbs->setActionList($actions); 84 + $crumbs->addCrumb( 85 + id(new PhabricatorCrumbView()) 86 + ->setName('L'.$document->getID()) 87 + ->setHref($this->getApplicationURI('view/'.$document->getID()))); 88 + 89 + $content = array( 90 + $crumbs, 91 + $header, 92 + $actions, 93 + $properties, 94 + $this->buildDocument($engine, $document_body), 95 + $xaction_view, 96 + $add_comment, 97 + ); 98 + 99 + return $this->buildApplicationPage( 100 + $content, 101 + array( 102 + 'title' => $title, 103 + 'device' => true, 104 + 'dust' => true, 105 + 'pageObjects' => array($document->getPHID()), 106 + )); 107 + } 108 + 109 + private function buildDocument( 110 + PhabricatorMarkupEngine 111 + $engine, LegalpadDocumentBody $body) { 112 + 113 + require_celerity_resource('legalpad-documentbody-css'); 114 + 115 + return phutil_tag( 116 + 'div', 117 + array( 118 + 'class' => 'legalpad-documentbody' 119 + ), 120 + $engine->getOutput($body, LegalpadDocumentBody::MARKUP_FIELD_TEXT)); 121 + 122 + } 123 + 124 + private function buildActionView(LegalpadDocument $document) { 125 + $user = $this->getRequest()->getUser(); 126 + 127 + $actions = id(new PhabricatorActionListView()) 128 + ->setUser($user) 129 + ->setObject($document); 130 + 131 + $can_edit = PhabricatorPolicyFilter::hasCapability( 132 + $user, 133 + $document, 134 + PhabricatorPolicyCapability::CAN_EDIT); 135 + 136 + $actions->addAction( 137 + id(new PhabricatorActionView()) 138 + ->setIcon('edit') 139 + ->setName(pht('Edit Document')) 140 + ->setHref($this->getApplicationURI('/edit/'.$document->getID().'/')) 141 + ->setDisabled(!$can_edit) 142 + ->setWorkflow(!$can_edit)); 143 + 144 + return $actions; 145 + } 146 + 147 + private function buildPropertyView( 148 + LegalpadDocument $document, 149 + PhabricatorMarkupEngine $engine, 150 + array $subscribers) { 151 + 152 + $user = $this->getRequest()->getUser(); 153 + 154 + $properties = id(new PhabricatorPropertyListView()) 155 + ->setUser($user) 156 + ->setObject($document); 157 + 158 + $properties->addProperty( 159 + pht('Last Updated'), 160 + phabricator_datetime($document->getDateModified(), $user)); 161 + 162 + $properties->addProperty( 163 + pht('Updated By'), 164 + $this->getHandle( 165 + $document->getDocumentBody()->getCreatorPHID())->renderLink()); 166 + 167 + $properties->addProperty( 168 + pht('Versions'), 169 + $document->getVersions()); 170 + 171 + $contributor_view = array(); 172 + foreach ($document->getContributors() as $contributor) { 173 + $contributor_view[] = $this->getHandle($contributor)->renderLink(); 174 + } 175 + $contributor_view = phutil_implode_html(', ', $contributor_view); 176 + $properties->addProperty( 177 + pht('Contributors'), 178 + $contributor_view); 179 + 180 + $descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions( 181 + $user, 182 + $document); 183 + 184 + $properties->addProperty( 185 + pht('Visible To'), 186 + $descriptions[PhabricatorPolicyCapability::CAN_VIEW]); 187 + 188 + if ($subscribers) { 189 + $sub_view = array(); 190 + foreach ($subscribers as $subscriber) { 191 + $sub_view[] = $this->getHandle($subscriber)->renderLink(); 192 + } 193 + $sub_view = phutil_implode_html(', ', $sub_view); 194 + } else { 195 + $sub_view = phutil_tag('em', array(), pht('None')); 196 + } 197 + 198 + $properties->addProperty( 199 + pht('Subscribers'), 200 + $sub_view); 201 + 202 + $properties->invokeWillRenderEvent(); 203 + 204 + return $properties; 205 + } 206 + 207 + private function buildAddCommentView( 208 + LegalpadDocument $document, 209 + $comment_form_id) { 210 + $user = $this->getRequest()->getUser(); 211 + 212 + $draft = PhabricatorDraft::newFromUserAndKey($user, $document->getPHID()); 213 + 214 + $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); 215 + 216 + $title = $is_serious 217 + ? pht('Add Comment') 218 + : pht('Debate Legislation'); 219 + 220 + $header = id(new PhabricatorHeaderView()) 221 + ->setHeader($title); 222 + 223 + $button_name = $is_serious 224 + ? pht('Add Comment') 225 + : pht('Commence Filibuster'); 226 + 227 + $form = id(new PhabricatorApplicationTransactionCommentView()) 228 + ->setUser($user) 229 + ->setFormID($comment_form_id) 230 + ->setDraft($draft) 231 + ->setSubmitButtonName($button_name) 232 + ->setAction($this->getApplicationURI('/comment/'.$document->getID().'/')) 233 + ->setRequestURI($this->getRequest()->getRequestURI()); 234 + 235 + return array( 236 + $header, 237 + $form, 238 + ); 239 + } 240 + 241 + }
+126
src/applications/legalpad/editor/LegalpadDocumentEditor.php
··· 1 + <?php 2 + 3 + /** 4 + * @group legalpad 5 + */ 6 + final class LegalpadDocumentEditor 7 + extends PhabricatorApplicationTransactionEditor { 8 + 9 + private $isContribution = false; 10 + 11 + private function setIsContribution($is_contribution) { 12 + $this->isContribution = $is_contribution; 13 + } 14 + private function isContribution() { 15 + return $this->isContribution; 16 + } 17 + 18 + public function getTransactionTypes() { 19 + $types = parent::getTransactionTypes(); 20 + 21 + $types[] = PhabricatorTransactions::TYPE_COMMENT; 22 + $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; 23 + $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; 24 + 25 + $types[] = LegalpadTransactionType::TYPE_TITLE; 26 + $types[] = LegalpadTransactionType::TYPE_TEXT; 27 + return $types; 28 + } 29 + 30 + protected function getCustomTransactionOldValue( 31 + PhabricatorLiskDAO $object, 32 + PhabricatorApplicationTransaction $xaction) { 33 + 34 + switch ($xaction->getTransactionType()) { 35 + case LegalpadTransactionType::TYPE_TITLE: 36 + return $object->getDocumentBody()->getTitle(); 37 + case LegalpadTransactionType::TYPE_TEXT: 38 + return $object->getDocumentBody()->getText(); 39 + } 40 + } 41 + 42 + protected function getCustomTransactionNewValue( 43 + PhabricatorLiskDAO $object, 44 + PhabricatorApplicationTransaction $xaction) { 45 + 46 + switch ($xaction->getTransactionType()) { 47 + case LegalpadTransactionType::TYPE_TITLE: 48 + case LegalpadTransactionType::TYPE_TEXT: 49 + return $xaction->getNewValue(); 50 + } 51 + } 52 + 53 + protected function applyCustomInternalTransaction( 54 + PhabricatorLiskDAO $object, 55 + PhabricatorApplicationTransaction $xaction) { 56 + 57 + switch ($xaction->getTransactionType()) { 58 + case LegalpadTransactionType::TYPE_TITLE: 59 + $body = $object->getDocumentBody(); 60 + $body->setTitle($xaction->getNewValue()); 61 + $this->setIsContribution(true); 62 + break; 63 + case LegalpadTransactionType::TYPE_TEXT: 64 + $body = $object->getDocumentBody(); 65 + $body->setText($xaction->getNewValue()); 66 + $this->setIsContribution(true); 67 + break; 68 + } 69 + } 70 + 71 + protected function applyCustomExternalTransaction( 72 + PhabricatorLiskDAO $object, 73 + PhabricatorApplicationTransaction $xaction) { 74 + return; 75 + } 76 + 77 + protected function applyFinalEffects( 78 + PhabricatorLiskDAO $object, 79 + array $xactions) { 80 + 81 + if ($this->isContribution()) { 82 + $object->setVersions($object->getVersions() + 1); 83 + $body = $object->getDocumentBody(); 84 + $body->setVersion($object->getVersions()); 85 + $body->setDocumentPHID($object->getPHID()); 86 + $body->save(); 87 + 88 + $object->setDocumentBodyPHID($body->getPHID()); 89 + $object->save(); 90 + 91 + $actor = $this->getActor(); 92 + $type = PhabricatorEdgeConfig::TYPE_CONTRIBUTED_TO_OBJECT; 93 + id(new PhabricatorEdgeEditor()) 94 + ->addEdge($actor->getPHID(), $type, $object->getPHID()) 95 + ->setActor($actor) 96 + ->save(); 97 + } 98 + } 99 + 100 + protected function mergeTransactions( 101 + PhabricatorApplicationTransaction $u, 102 + PhabricatorApplicationTransaction $v) { 103 + 104 + $type = $u->getTransactionType(); 105 + switch ($type) { 106 + case LegalpadTransactionType::TYPE_TITLE: 107 + case LegalpadTransactionType::TYPE_TEXT: 108 + return $v; 109 + } 110 + 111 + return parent::mergeTransactions($u, $v); 112 + } 113 + 114 + protected function supportsMail() { 115 + return false; 116 + } 117 + 118 + protected function supportsFeed() { 119 + return false; 120 + } 121 + 122 + protected function supportsSearch() { 123 + return false; 124 + } 125 + 126 + }
+168
src/applications/legalpad/query/LegalpadDocumentQuery.php
··· 1 + <?php 2 + 3 + /** 4 + * @group legalpad 5 + */ 6 + final class LegalpadDocumentQuery 7 + extends PhabricatorCursorPagedPolicyAwareQuery { 8 + 9 + private $ids; 10 + private $phids; 11 + private $creatorPHIDs; 12 + private $contributorPHIDs; // TODO - T3479 13 + private $dateCreatedAfter; 14 + private $dateCreatedBefore; 15 + 16 + private $needDocumentBodies; 17 + private $needContributors; 18 + 19 + public function withIDs(array $ids) { 20 + $this->ids = $ids; 21 + return $this; 22 + } 23 + 24 + public function withPHIDs(array $phids) { 25 + $this->phids = $phids; 26 + return $this; 27 + } 28 + 29 + public function withCreatorPHIDs(array $phids) { 30 + $this->creatorPHIDs = $phids; 31 + return $this; 32 + } 33 + 34 + public function withContributorPHIDs(array $phids) { 35 + $this->contributorPHIDs = $phids; 36 + return $this; 37 + } 38 + 39 + public function needDocumentBodies($need_bodies) { 40 + $this->needDocumentBodies = $need_bodies; 41 + return $this; 42 + } 43 + 44 + public function needContributors($need_contributors) { 45 + $this->needContributors = $need_contributors; 46 + return $this; 47 + } 48 + 49 + public function withDateCreatedBefore($date_created_before) { 50 + $this->dateCreatedBefore = $date_created_before; 51 + return $this; 52 + } 53 + 54 + public function withDateCreatedAfter($date_created_after) { 55 + $this->dateCreatedAfter = $date_created_after; 56 + return $this; 57 + } 58 + 59 + protected function loadPage() { 60 + $table = new LegalpadDocument(); 61 + $conn_r = $table->establishConnection('r'); 62 + 63 + $data = queryfx_all( 64 + $conn_r, 65 + 'SELECT legalpad_document.* FROM %T legalpad_document %Q %Q %Q', 66 + $table->getTableName(), 67 + $this->buildWhereClause($conn_r), 68 + $this->buildOrderClause($conn_r), 69 + $this->buildLimitClause($conn_r)); 70 + 71 + $documents = $table->loadAllFromArray($data); 72 + 73 + return $documents; 74 + } 75 + 76 + protected function willFilterPage(array $documents) { 77 + if (!$documents) { 78 + return $documents; 79 + } 80 + 81 + if ($this->needDocumentBodies) { 82 + $documents = $this->loadDocumentBodies($documents); 83 + } 84 + 85 + if ($this->needContributors) { 86 + $documents = $this->loadContributors($documents); 87 + } 88 + 89 + return $documents; 90 + } 91 + 92 + protected function buildWhereClause($conn_r) { 93 + $where = array(); 94 + 95 + $where[] = $this->buildPagingClause($conn_r); 96 + 97 + if ($this->ids) { 98 + $where[] = qsprintf( 99 + $conn_r, 100 + 'id IN (%Ld)', 101 + $this->ids); 102 + } 103 + 104 + if ($this->phids) { 105 + $where[] = qsprintf( 106 + $conn_r, 107 + 'phid IN (%Ls)', 108 + $this->phids); 109 + } 110 + 111 + if ($this->creatorPHIDs) { 112 + $where[] = qsprintf( 113 + $conn_r, 114 + 'creatorPHID IN (%Ls)', 115 + $this->creatorPHIDs); 116 + } 117 + 118 + if ($this->dateCreatedAfter) { 119 + $where[] = qsprintf( 120 + $conn_r, 121 + 'dateCreated >= %d', 122 + $this->dateCreatedAfter); 123 + } 124 + 125 + if ($this->dateCreatedBefore) { 126 + $where[] = qsprintf( 127 + $conn_r, 128 + 'dateCreated <= %d', 129 + $this->dateCreatedBefore); 130 + } 131 + 132 + return $this->formatWhereClause($where); 133 + } 134 + 135 + private function loadDocumentBodies(array $documents) { 136 + $body_phids = mpull($documents, 'getDocumentBodyPHID'); 137 + $bodies = id(new LegalpadDocumentBody())->loadAllWhere( 138 + 'phid IN (%Ls)', 139 + $body_phids); 140 + $bodies = mpull($bodies, null, 'getPHID'); 141 + 142 + foreach ($documents as $document) { 143 + $body = idx($bodies, $document->getDocumentBodyPHID()); 144 + $document->attachDocumentBody($body); 145 + } 146 + 147 + return $documents; 148 + } 149 + 150 + private function loadContributors(array $documents) { 151 + $document_map = mpull($documents, null, 'getPHID'); 152 + $edge_type = PhabricatorEdgeConfig::TYPE_OBJECT_HAS_CONTRIBUTOR; 153 + $contributor_data = id(new PhabricatorEdgeQuery()) 154 + ->withSourcePHIDs(array_keys($document_map)) 155 + ->withEdgeTypes(array($edge_type)) 156 + ->execute(); 157 + 158 + foreach ($document_map as $document_phid => $document) { 159 + $data = $contributor_data[$document_phid]; 160 + $contributors = array_keys(idx($data, $edge_type, array())); 161 + $document->attachContributors($contributors); 162 + } 163 + 164 + return $documents; 165 + } 166 + 167 + 168 + }
+93
src/applications/legalpad/query/LegalpadDocumentSearchEngine.php
··· 1 + <?php 2 + 3 + /** 4 + * @group legalpad 5 + */ 6 + final class LegalpadDocumentSearchEngine 7 + extends PhabricatorApplicationSearchEngine { 8 + 9 + public function buildSavedQueryFromRequest(AphrontRequest $request) { 10 + $saved = new PhabricatorSavedQuery(); 11 + $saved->setParameter( 12 + 'creatorPHIDs', 13 + array_values($request->getArr('creators'))); 14 + 15 + $saved->setParameter('createdStart', $request->getStr('createdStart')); 16 + $saved->setParameter('createdEnd', $request->getStr('createdEnd')); 17 + 18 + return $saved; 19 + } 20 + 21 + public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { 22 + $query = id(new LegalpadDocumentQuery()) 23 + ->needDocumentBodies(true) 24 + ->needContributors(true) 25 + ->withCreatorPHIDs($saved->getParameter('creatorPHIDs', array())); 26 + 27 + $start = $this->parseDateTime($saved->getParameter('createdStart')); 28 + $end = $this->parseDateTime($saved->getParameter('createdEnd')); 29 + 30 + if ($start) { 31 + $query->withDateCreatedAfter($start); 32 + } 33 + 34 + if ($end) { 35 + $query->withDateCreatedBefore($end); 36 + } 37 + 38 + return $query; 39 + } 40 + 41 + public function buildSearchForm( 42 + AphrontFormView $form, 43 + PhabricatorSavedQuery $saved_query) { 44 + $phids = $saved_query->getParameter('creatorPHIDs', array()); 45 + $handles = id(new PhabricatorObjectHandleData($phids)) 46 + ->setViewer($this->requireViewer()) 47 + ->loadHandles(); 48 + $creator_tokens = mpull($handles, 'getFullName', 'getPHID'); 49 + 50 + $form 51 + ->appendChild( 52 + id(new AphrontFormTokenizerControl()) 53 + ->setDatasource('/typeahead/common/users/') 54 + ->setName('creators') 55 + ->setLabel(pht('Creators')) 56 + ->setValue($creator_tokens)); 57 + 58 + $this->buildDateRange( 59 + $form, 60 + $saved_query, 61 + 'createdStart', 62 + pht('Created After'), 63 + 'createdEnd', 64 + pht('Created Before')); 65 + 66 + } 67 + 68 + protected function getURI($path) { 69 + return '/legalpad/'.$path; 70 + } 71 + 72 + public function getBuiltinQueryNames() { 73 + $names = array( 74 + 'all' => pht('All Documents'), 75 + ); 76 + 77 + return $names; 78 + } 79 + 80 + public function buildSavedQueryFromBuiltin($query_key) { 81 + 82 + $query = $this->newSavedQuery(); 83 + $query->setQueryKey($query_key); 84 + 85 + switch ($query_key) { 86 + case 'all': 87 + return $query; 88 + } 89 + 90 + return parent::buildSavedQueryFromBuiltin($query_key); 91 + } 92 + 93 + }
+13
src/applications/legalpad/query/LegalpadTransactionQuery.php
··· 1 + <?php 2 + 3 + /** 4 + * @group legalpad 5 + */ 6 + final class LegalpadTransactionQuery 7 + extends PhabricatorApplicationTransactionQuery { 8 + 9 + protected function getTemplateApplicationTransaction() { 10 + return new LegalpadTransaction(); 11 + } 12 + 13 + }
+12
src/applications/legalpad/storage/LegalpadDAO.php
··· 1 + <?php 2 + 3 + /** 4 + * @group legalpad 5 + */ 6 + abstract class LegalpadDAO extends PhabricatorLiskDAO { 7 + 8 + public function getApplicationName() { 9 + return 'legalpad'; 10 + } 11 + 12 + }
+105
src/applications/legalpad/storage/LegalpadDocument.php
··· 1 + <?php 2 + 3 + /** 4 + * @group legalpad 5 + */ 6 + final class LegalpadDocument extends LegalpadDAO 7 + implements 8 + PhabricatorPolicyInterface, 9 + PhabricatorSubscribableInterface, 10 + PhabricatorApplicationTransactionInterface { 11 + 12 + protected $phid; 13 + protected $creatorPHID; 14 + protected $versions; 15 + protected $documentBodyPHID; 16 + protected $viewPolicy; 17 + protected $editPolicy; 18 + 19 + private $documentBody; 20 + private $contributors; 21 + 22 + public function getConfiguration() { 23 + return array( 24 + self::CONFIG_AUX_PHID => true, 25 + ) + parent::getConfiguration(); 26 + } 27 + 28 + public function generatePHID() { 29 + return PhabricatorPHID::generateNewPHID( 30 + PhabricatorPHIDConstants::PHID_TYPE_LEGD); 31 + } 32 + 33 + public function getDocumentBody() { 34 + if ($this->documentBody === null) { 35 + throw new Exception( 36 + 'You must attachDocumentBody before you can getDocumentBody.'); 37 + } 38 + 39 + return $this->documentBody; 40 + } 41 + 42 + public function attachDocumentBody(LegalpadDocumentBody $body) { 43 + $this->documentBody = $body; 44 + return $this; 45 + } 46 + 47 + public function getContributors() { 48 + if ($this->contributors === null) { 49 + throw new Exception( 50 + 'You must attachContributors before you can getContributors.'); 51 + } 52 + 53 + return $this->contributors; 54 + } 55 + 56 + public function attachContributors(array $contributors) { 57 + $this->contributors = $contributors; 58 + return $this; 59 + } 60 + 61 + /* -( PhabricatorSubscribableInterface Implementation )-------------------- */ 62 + 63 + public function isAutomaticallySubscribed($phid) { 64 + return ($this->creatorPHID == $phid); 65 + } 66 + 67 + /* -( PhabricatorPolicyInterface Implementation )-------------------------- */ 68 + 69 + public function getCapabilities() { 70 + return array( 71 + PhabricatorPolicyCapability::CAN_VIEW, 72 + PhabricatorPolicyCapability::CAN_EDIT, 73 + ); 74 + } 75 + 76 + public function getPolicy($capability) { 77 + switch ($capability) { 78 + case PhabricatorPolicyCapability::CAN_VIEW: 79 + $policy = $this->viewPolicy; 80 + break; 81 + case PhabricatorPolicyCapability::CAN_EDIT: 82 + $policy = $this->editPolicy; 83 + break; 84 + default: 85 + $policy = PhabricatorPolicies::POLICY_NOONE; 86 + break; 87 + } 88 + return $policy; 89 + } 90 + 91 + public function hasAutomaticCapability($capability, PhabricatorUser $user) { 92 + return ($user->getPHID() == $this->getCreatorPHID()); 93 + } 94 + 95 + /* -( PhabricatorApplicationTransactionInterface )------------------------- */ 96 + 97 + public function getApplicationTransactionEditor() { 98 + return new LegalpadDocumentEditor(); 99 + } 100 + 101 + public function getApplicationTransactionObject() { 102 + return new LegalpadTransaction(); 103 + } 104 + 105 + }
+74
src/applications/legalpad/storage/LegalpadDocumentBody.php
··· 1 + <?php 2 + 3 + /** 4 + * @group legalpad 5 + */ 6 + final class LegalpadDocumentBody extends LegalpadDAO 7 + implements 8 + PhabricatorMarkupInterface { 9 + 10 + const MARKUP_FIELD_TITLE = 'markup:title'; 11 + const MARKUP_FIELD_TEXT = 'markup:text '; 12 + 13 + protected $phid; 14 + protected $creatorPHID; 15 + protected $documentPHID; 16 + protected $version; 17 + protected $title; 18 + protected $text; 19 + 20 + public function getConfiguration() { 21 + return array( 22 + self::CONFIG_AUX_PHID => true, 23 + ) + parent::getConfiguration(); 24 + } 25 + 26 + public function generatePHID() { 27 + return PhabricatorPHID::generateNewPHID( 28 + PhabricatorPHIDConstants::PHID_TYPE_LEGB); 29 + } 30 + 31 + /* -( PhabricatorMarkupInterface )----------------------------------------- */ 32 + 33 + 34 + public function getMarkupFieldKey($field) { 35 + $hash = PhabricatorHash::digest($this->getMarkupText($field)); 36 + return 'LEGB:'.$hash; 37 + } 38 + 39 + public function newMarkupEngine($field) { 40 + return PhabricatorMarkupEngine::newMarkupEngine(array()); 41 + } 42 + 43 + public function getMarkupText($field) { 44 + switch ($field) { 45 + case self::MARKUP_FIELD_TEXT: 46 + $text = $this->getText(); 47 + break; 48 + case self::MARKUP_FIELD_TITLE: 49 + $text = $this->getTitle(); 50 + break; 51 + default: 52 + throw new Exception('Unknown field: '.$field); 53 + break; 54 + } 55 + 56 + return $text; 57 + } 58 + 59 + public function didMarkupText($field, $output, PhutilMarkupEngine $engine) { 60 + require_celerity_resource('phabricator-remarkup-css'); 61 + return phutil_tag( 62 + 'div', 63 + array( 64 + 'class' => 'phabricator-remarkup', 65 + ), 66 + $output); 67 + } 68 + 69 + public function shouldUseMarkupCache($field) { 70 + return (bool)$this->getID(); 71 + } 72 + 73 + 74 + }
+12
src/applications/legalpad/storage/LegalpadDocumentSignature.php
··· 1 + <?php 2 + 3 + /** 4 + * @group legalpad 5 + */ 6 + final class LegalpadDocumentSignature extends LegalpadDAO { 7 + 8 + protected $documentPHID; 9 + protected $documentversion; 10 + protected $signerPHID; 11 + 12 + }
+86
src/applications/legalpad/storage/LegalpadTransaction.php
··· 1 + <?php 2 + 3 + /** 4 + * @group legalpad 5 + */ 6 + final class LegalpadTransaction extends PhabricatorApplicationTransaction { 7 + 8 + public function getApplicationName() { 9 + return 'legalpad'; 10 + } 11 + 12 + public function getApplicationTransactionType() { 13 + return PhabricatorPHIDConstants::PHID_TYPE_LEGD; 14 + } 15 + 16 + public function getApplicationTransactionCommentObject() { 17 + return new LegalpadTransactionComment(); 18 + } 19 + 20 + public function getApplicationTransactionViewObject() { 21 + return new LegalpadTransactionView(); 22 + } 23 + 24 + public function getApplicationObjectTypeName() { 25 + return pht('document'); 26 + } 27 + 28 + public function shouldHide() { 29 + $old = $this->getOldValue(); 30 + 31 + switch ($this->getTransactionType()) { 32 + case LegalpadTransactionType::TYPE_TITLE: 33 + case LegalpadTransactionType::TYPE_TEXT: 34 + return ($old === null); 35 + } 36 + 37 + return parent::shouldHide(); 38 + } 39 + 40 + public function getTitle() { 41 + $author_phid = $this->getAuthorPHID(); 42 + 43 + $old = $this->getOldValue(); 44 + $new = $this->getNewValue(); 45 + 46 + $type = $this->getTransactionType(); 47 + switch ($type) { 48 + case LegalpadTransactionType::TYPE_TITLE: 49 + return pht( 50 + '%s renamed this document from "%s" to "%s".', 51 + $this->renderHandleLink($author_phid), 52 + $old, 53 + $new); 54 + break; 55 + case LegalpadTransactionType::TYPE_TEXT: 56 + return pht( 57 + "%s updated the document's text.", 58 + $this->renderHandleLink($author_phid)); 59 + break; 60 + } 61 + 62 + return parent::getTitle(); 63 + } 64 + 65 + public function hasChangeDetails() { 66 + switch ($this->getTransactionType()) { 67 + case LegalpadTransactionType::TYPE_TITLE: 68 + case LegalpadTransactionType::TYPE_TEXT: 69 + return true; 70 + } 71 + return parent::hasChangeDetails(); 72 + } 73 + 74 + public function renderChangeDetails(PhabricatorUser $viewer) { 75 + $old = $this->getOldValue(); 76 + $new = $this->getNewValue(); 77 + 78 + $view = id(new PhabricatorApplicationTransactionTextDiffDetailView()) 79 + ->setUser($viewer) 80 + ->setOldText($old) 81 + ->setNewText($new); 82 + 83 + return $view->render(); 84 + } 85 + 86 + }
+24
src/applications/legalpad/storage/LegalpadTransactionComment.php
··· 1 + <?php 2 + 3 + /** 4 + * @group legalpad 5 + */ 6 + final class LegalpadTransactionComment 7 + extends PhabricatorApplicationTransactionComment { 8 + 9 + protected $documentID; 10 + protected $lineNumber; 11 + protected $lineLength; 12 + protected $fixedState; 13 + protected $hasReplies = 0; 14 + protected $replyToCommentPHID; 15 + 16 + public function getApplicationTransactionObject() { 17 + return new LegalpadTransaction(); 18 + } 19 + 20 + public function shouldUseMarkupCache($field) { 21 + // Only cache submitted comments. 22 + return ($this->getTransactionPHID() != null); 23 + } 24 + }
+9
src/applications/legalpad/view/LegalpadTransactionView.php
··· 1 + <?php 2 + 3 + /** 4 + * @group legalpad 5 + */ 6 + final class LegalpadTransactionView 7 + extends PhabricatorApplicationTransactionView { 8 + 9 + }
+1
src/applications/phid/PhabricatorObjectHandle.php
··· 114 114 PhabricatorPHIDConstants::PHID_TYPE_PVAR => 'Variable', 115 115 PhabricatorPHIDConstants::PHID_TYPE_PSTE => 'Paste', 116 116 PhabricatorPHIDConstants::PHID_TYPE_PROJ => 'Project', 117 + PhabricatorPHIDConstants::PHID_TYPE_LEGD => 'Legalpad Document', 117 118 ); 118 119 119 120 return idx($map, $this->getType(), $this->getType());
+2
src/applications/phid/PhabricatorPHIDConstants.php
··· 40 40 const PHID_TYPE_CHRG = 'CHRG'; 41 41 const PHID_TYPE_CART = 'CART'; 42 42 const PHID_TYPE_CDWN = 'CDWN'; 43 + const PHID_TYPE_LEGD = 'LEGD'; 44 + const PHID_TYPE_LEGB = 'LEGB'; 43 45 44 46 const PHID_TYPE_XACT = 'XACT'; 45 47 const PHID_TYPE_XCMT = 'XCMT';
+26
src/applications/phid/handle/PhabricatorObjectHandleData.php
··· 211 211 $phids); 212 212 return mpull($xusrs, null, 'getPHID'); 213 213 214 + case PhabricatorPHIDConstants::PHID_TYPE_LEGD: 215 + $legds = id(new LegalpadDocumentQuery()) 216 + ->needDocumentBody(true) 217 + ->withPHIDs($phids) 218 + ->setViewer($this->viewer) 219 + ->execute(); 220 + return mpull($legds, null, 'getPHID'); 221 + 214 222 } 215 223 216 224 return array(); ··· 718 726 $handle->setName($countdown->getTitle()); 719 727 $handle->setFullName($countdown->getTitle()); 720 728 $handle->setURI('/countdown/'.$countdown->getID().'/'); 729 + $handle->setComplete(true); 730 + } 731 + $handles[$phid] = $handle; 732 + } 733 + break; 734 + 735 + case PhabricatorPHIDConstants::PHID_TYPE_LEGD: 736 + foreach ($phids as $phid) { 737 + $handle = new PhabricatorObjectHandle(); 738 + $handle->setPHID($phid); 739 + $handle->setType($type); 740 + if (empty($objects[$phid])) { 741 + $handle->setName('Unknown Legalpad Document'); 742 + } else { 743 + $document = $objects[$phid]; 744 + $handle->setName($document->getDocumentBody()->getTitle()); 745 + $handle->setFullName($document->getDocumentBody()->getTitle()); 746 + $handle->setURI('/legalpad/view/'.$document->getID().'/'); 721 747 $handle->setComplete(true); 722 748 } 723 749 $handles[$phid] = $handle;
+7
src/infrastructure/edges/constants/PhabricatorEdgeConfig.php
··· 51 51 const TYPE_DREV_HAS_COMMIT = 31; 52 52 const TYPE_COMMIT_HAS_DREV = 32; 53 53 54 + const TYPE_OBJECT_HAS_CONTRIBUTOR = 33; 55 + const TYPE_CONTRIBUTED_TO_OBJECT = 34; 56 + 54 57 const TYPE_TEST_NO_CYCLE = 9000; 55 58 56 59 const TYPE_PHOB_HAS_ASANATASK = 80001; ··· 106 109 self::TYPE_DREV_HAS_COMMIT => self::TYPE_COMMIT_HAS_DREV, 107 110 self::TYPE_COMMIT_HAS_DREV => self::TYPE_DREV_HAS_COMMIT, 108 111 112 + self::TYPE_OBJECT_HAS_CONTRIBUTOR => self::TYPE_SUBSCRIBED_TO_OBJECT, 113 + self::TYPE_CONTRIBUTED_TO_OBJECT => self::TYPE_OBJECT_HAS_CONTRIBUTOR, 114 + 109 115 self::TYPE_PHOB_HAS_ASANATASK => self::TYPE_ASANATASK_HAS_PHOB, 110 116 self::TYPE_ASANATASK_HAS_PHOB => self::TYPE_PHOB_HAS_ASANATASK, 111 117 ··· 149 155 PhabricatorPHIDConstants::PHID_TYPE_PRCH => 'PhortunePurchase', 150 156 PhabricatorPHIDConstants::PHID_TYPE_CHRG => 'PhortuneCharge', 151 157 PhabricatorPHIDConstants::PHID_TYPE_XOBJ => 'DoorkeeperExternalObject', 158 + PhabricatorPHIDConstants::PHID_TYPE_LEGD => 'LegalpadDocument', 152 159 ); 153 160 154 161 $class = idx($class_map, $phid_type);
+9
webroot/rsrc/css/application/legalpad/legalpad-documentbody.css
··· 1 + /** 2 + * @provides legalpad-documentbody-css 3 + */ 4 + 5 + .legalpad-documentbody { 6 + position: relative; 7 + padding: 1.25em 2% 8 + } 9 +