diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 7a33735035..a6515e9733 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -842,6 +842,8 @@ phutil_register_library_map(array( 'LegalpadDocumentSearchEngine' => 'applications/legalpad/query/LegalpadDocumentSearchEngine.php', 'LegalpadDocumentSignController' => 'applications/legalpad/controller/LegalpadDocumentSignController.php', 'LegalpadDocumentSignature' => 'applications/legalpad/storage/LegalpadDocumentSignature.php', + 'LegalpadDocumentSignatureListController' => 'applications/legalpad/controller/LegalpadDocumentSignatureListController.php', + 'LegalpadDocumentSignatureQuery' => 'applications/legalpad/query/LegalpadDocumentSignatureQuery.php', 'LegalpadDocumentSignatureVerificationController' => 'applications/legalpad/controller/LegalpadDocumentSignatureVerificationController.php', 'LegalpadDocumentViewController' => 'applications/legalpad/controller/LegalpadDocumentViewController.php', 'LegalpadMockMailReceiver' => 'applications/legalpad/mail/LegalpadMockMailReceiver.php', @@ -3374,7 +3376,13 @@ phutil_register_library_map(array( 'LegalpadDocumentQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'LegalpadDocumentSearchEngine' => 'PhabricatorApplicationSearchEngine', 'LegalpadDocumentSignController' => 'LegalpadController', - 'LegalpadDocumentSignature' => 'LegalpadDAO', + 'LegalpadDocumentSignature' => + array( + 0 => 'LegalpadDAO', + 1 => 'PhabricatorPolicyInterface', + ), + 'LegalpadDocumentSignatureListController' => 'LegalpadController', + 'LegalpadDocumentSignatureQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'LegalpadDocumentSignatureVerificationController' => 'LegalpadController', 'LegalpadDocumentViewController' => 'LegalpadController', 'LegalpadMockMailReceiver' => 'PhabricatorObjectMailReceiver', diff --git a/src/applications/legalpad/application/PhabricatorApplicationLegalpad.php b/src/applications/legalpad/application/PhabricatorApplicationLegalpad.php index 663fd3c805..399fdb155b 100644 --- a/src/applications/legalpad/application/PhabricatorApplicationLegalpad.php +++ b/src/applications/legalpad/application/PhabricatorApplicationLegalpad.php @@ -49,7 +49,8 @@ final class PhabricatorApplicationLegalpad extends PhabricatorApplication { 'comment/(?P\d+)/' => 'LegalpadDocumentCommentController', 'view/(?P\d+)/' => 'LegalpadDocumentViewController', 'verify/(?P[^/]+)/' => - 'LegalpadDocumentSignatureVerificationController', + 'LegalpadDocumentSignatureVerificationController', + 'signatures/(?P\d+)/' => 'LegalpadDocumentSignatureListController', 'document/' => array( 'preview/' => 'PhabricatorMarkupPreviewController'), )); diff --git a/src/applications/legalpad/controller/LegalpadDocumentSignController.php b/src/applications/legalpad/controller/LegalpadDocumentSignController.php index 0c0e96b22f..42acab41b0 100644 --- a/src/applications/legalpad/controller/LegalpadDocumentSignController.php +++ b/src/applications/legalpad/controller/LegalpadDocumentSignController.php @@ -1,8 +1,5 @@ loadOneWhere( - 'documentPHID = %s AND signerPHID = %s AND documentVersion = %d', - $document->getPHID(), - $signer_phid, - $document->getVersions()); + $signature = id(new LegalpadDocumentSignatureQuery()) + ->setViewer($user) + ->withDocumentPHIDs(array($document->getPHID())) + ->withSignerPHIDs(array($signer_phid)) + ->withDocumentVersions(array($document->getVersions())) + ->executeOne(); } if (!$signature) { diff --git a/src/applications/legalpad/controller/LegalpadDocumentSignatureListController.php b/src/applications/legalpad/controller/LegalpadDocumentSignatureListController.php new file mode 100644 index 0000000000..84717af2da --- /dev/null +++ b/src/applications/legalpad/controller/LegalpadDocumentSignatureListController.php @@ -0,0 +1,122 @@ +documentId = $data['id']; + } + + public function processRequest() { + $request = $this->getRequest(); + $user = $request->getUser(); + + $document = id(new LegalpadDocumentQuery()) + ->setViewer($user) + ->withIDs(array($this->documentId)) + ->executeOne(); + + if (!$document) { + return new Aphront404Response(); + } + + $title = pht('Signatures for %s', $document->getMonogram()); + + $pager = id(new AphrontCursorPagerView()) + ->readFromRequest($request); + $signatures = id(new LegalpadDocumentSignatureQuery()) + ->setViewer($user) + ->withDocumentPHIDs(array($document->getPHID())) + ->executeWithCursorPager($pager); + + $crumbs = $this->buildApplicationCrumbs($this->buildSideNav()); + $crumbs->addTextCrumb( + $document->getMonogram(), + $this->getApplicationURI('view/'.$document->getID())); + + $crumbs->addTextCrumb( + pht('Signatures')); + $list = $this->renderResultsList($document, $signatures); + $list->setPager($pager); + + return $this->buildApplicationPage( + array( + $crumbs, + $list, + ), + array( + 'title' => $title, + 'device' => true, + )); + } + + private function renderResultsList( + LegalpadDocument $document, + array $signatures) { + assert_instances_of($signatures, 'LegalpadDocumentSignature'); + + $user = $this->getRequest()->getUser(); + + $list = new PHUIObjectItemListView(); + $list->setUser($user); + + foreach ($signatures as $signature) { + $created = phabricator_date($signature->getDateCreated(), $user); + + $data = $signature->getSignatureData(); + + $sig_data = phutil_tag( + 'div', + array(), + array( + phutil_tag( + 'div', + array(), + phutil_tag( + 'a', + array( + 'href' => 'mailto:'.$data['email'], + ), + $data['email'])), + phutil_tag( + 'div', + array(), + $data['address_1']), + phutil_tag( + 'div', + array(), + $data['address_2']), + phutil_tag( + 'div', + array(), + $data['phone']) + )); + + $item = id(new PHUIObjectItemView()) + ->setObject($signature) + ->setHeader($data['name']) + ->setSubhead($sig_data) + ->addIcon('none', pht('Signed %s', $created)); + + $good_sig = true; + if (!$signature->isVerified()) { + $item->addFootIcon('disable', 'Unverified Email'); + $good_sig = false; + } + if ($signature->getDocumentVersion() != $document->getVersions()) { + $item->addFootIcon('delete', 'Stale Signature'); + $good_sig = false; + } + + if ($good_sig) { + $item->setBarColor('green'); + } + + $list->addItem($item); + } + + return $list; + } + +} diff --git a/src/applications/legalpad/controller/LegalpadDocumentSignatureVerificationController.php b/src/applications/legalpad/controller/LegalpadDocumentSignatureVerificationController.php index d832a93491..19072f2caf 100644 --- a/src/applications/legalpad/controller/LegalpadDocumentSignatureVerificationController.php +++ b/src/applications/legalpad/controller/LegalpadDocumentSignatureVerificationController.php @@ -21,8 +21,18 @@ extends LegalpadController { $request = $this->getRequest(); $user = $request->getUser(); - $signature = id(new LegalpadDocumentSignature()) - ->loadOneWhere('secretKey = %s', $this->code); + // this page can be accessed by not logged in users to valid their + // signatures. use the omnipotent user for these cases. + if (!$user->isLoggedIn()) { + $viewer = PhabricatorUser::getOmnipotentUser(); + } else { + $viewer = $user; + } + + $signature = id(new LegalpadDocumentSignatureQuery()) + ->setViewer($viewer) + ->withSecretKeys(array($this->code)) + ->executeOne(); if (!$signature) { $title = pht('Unable to Verify Signature'); diff --git a/src/applications/legalpad/controller/LegalpadDocumentViewController.php b/src/applications/legalpad/controller/LegalpadDocumentViewController.php index 40550ca358..53a8792c4a 100644 --- a/src/applications/legalpad/controller/LegalpadDocumentViewController.php +++ b/src/applications/legalpad/controller/LegalpadDocumentViewController.php @@ -132,11 +132,13 @@ final class LegalpadDocumentViewController extends LegalpadController { $document, PhabricatorPolicyCapability::CAN_EDIT); + $doc_id = $document->getID(); + $actions->addAction( id(new PhabricatorActionView()) ->setIcon('edit') ->setName(pht('Edit Document')) - ->setHref($this->getApplicationURI('/edit/'.$document->getID().'/')) + ->setHref($this->getApplicationURI('/edit/'.$doc_id.'/')) ->setDisabled(!$can_edit) ->setWorkflow(!$can_edit)); @@ -146,6 +148,12 @@ final class LegalpadDocumentViewController extends LegalpadController { ->setName(pht('Sign Document')) ->setHref('/'.$document->getMonogram())); + $actions->addAction( + id(new PhabricatorActionView()) + ->setIcon('transcript') + ->setName(pht('View Signatures')) + ->setHref($this->getApplicationURI('/signatures/'.$doc_id.'/'))); + return $actions; } diff --git a/src/applications/legalpad/query/LegalpadDocumentQuery.php b/src/applications/legalpad/query/LegalpadDocumentQuery.php index 6316d70c0b..e9034c18a2 100644 --- a/src/applications/legalpad/query/LegalpadDocumentQuery.php +++ b/src/applications/legalpad/query/LegalpadDocumentQuery.php @@ -1,8 +1,5 @@ signerPHIDs) { $document_map = mpull($documents, null, 'getPHID'); - $signatures = id(new LegalpadDocumentSignature()) - ->loadAllWhere( - 'documentPHID IN (%Ls) AND signerPHID IN (%Ls)', - array_keys($document_map), - $this->signerPHIDs); + $signatures = id(new LegalpadDocumentSignatureQuery()) + ->setViewer($this->getViewer()) + ->withDocumentPHIDs(array_keys($document_map)) + ->wtihSignerPHIDs($this->signerPHIDs) + ->execute(); $signatures = mgroup($signatures, 'getDocumentPHID'); foreach ($document_map as $document_phid => $document) { $sigs = idx($signatures, $document_phid, array()); @@ -222,10 +219,10 @@ final class LegalpadDocumentQuery private function loadSignatures(array $documents) { $document_map = mpull($documents, null, 'getPHID'); - $signatures = id(new LegalpadDocumentSignature()) - ->loadAllWhere( - 'documentPHID IN (%Ls)', - array_keys($document_map)); + $signatures = id(new LegalpadDocumentSignatureQuery()) + ->setViewer($this->getViewer()) + ->withDocumentPHIDs(array_keys($document_map)) + ->execute(); $signatures = mgroup($signatures, 'getDocumentPHID'); foreach ($documents as $document) { diff --git a/src/applications/legalpad/query/LegalpadDocumentSignatureQuery.php b/src/applications/legalpad/query/LegalpadDocumentSignatureQuery.php new file mode 100644 index 0000000000..ade76679c3 --- /dev/null +++ b/src/applications/legalpad/query/LegalpadDocumentSignatureQuery.php @@ -0,0 +1,101 @@ +ids = $ids; + return $this; + } + + public function withDocumentPHIDs(array $phids) { + $this->documentPHIDs = $phids; + return $this; + } + + public function withSignerPHIDs(array $phids) { + $this->signerPHIDs = $phids; + return $this; + } + + public function withDocumentVersions(array $versions) { + $this->documentVersions = $versions; + return $this; + } + + public function withSecretKeys(array $keys) { + $this->secretKeys = $keys; + return $this; + } + + protected function loadPage() { + $table = new LegalpadDocumentSignature(); + $conn_r = $table->establishConnection('r'); + + $data = queryfx_all( + $conn_r, + 'SELECT * FROM %T %Q %Q %Q', + $table->getTableName(), + $this->buildWhereClause($conn_r), + $this->buildOrderClause($conn_r), + $this->buildLimitClause($conn_r)); + + $documents = $table->loadAllFromArray($data); + + return $documents; + } + + protected function buildWhereClause($conn_r) { + $where = array(); + + $where[] = $this->buildPagingClause($conn_r); + + if ($this->ids) { + $where[] = qsprintf( + $conn_r, + 'id IN (%Ld)', + $this->ids); + } + + if ($this->documentPHIDs) { + $where[] = qsprintf( + $conn_r, + 'documentPHID IN (%Ls)', + $this->documentPHIDs); + } + + if ($this->signerPHIDs) { + $where[] = qsprintf( + $conn_r, + 'signerPHID IN (%Ls)', + $this->signerPHIDs); + } + + if ($this->documentVersions) { + $where[] = qsprintf( + $conn_r, + 'documentVersion IN (%Ld)', + $this->documentVersions); + } + + if ($this->secretKeys) { + $where[] = qsprintf( + $conn_r, + 'secretKey IN (%Ls)', + $this->secretKeys); + } + + return $this->formatWhereClause($where); + } + + public function getQueryApplicationClass() { + return 'PhabricatorApplicationLegalpad'; + } + +} diff --git a/src/applications/legalpad/storage/LegalpadDocumentSignature.php b/src/applications/legalpad/storage/LegalpadDocumentSignature.php index 8ecd9eeee6..5c66b06d19 100644 --- a/src/applications/legalpad/storage/LegalpadDocumentSignature.php +++ b/src/applications/legalpad/storage/LegalpadDocumentSignature.php @@ -1,9 +1,8 @@ getVerified() != self::UNVERIFIED; } +/* -( PhabricatorPolicyInterface )----------------------------------------- */ + + public function getCapabilities() { + return array( + PhabricatorPolicyCapability::CAN_VIEW, + ); + } + + public function getPolicy($capability) { + switch ($capability) { + case PhabricatorPolicyCapability::CAN_VIEW: + return PhabricatorPolicies::POLICY_USER; + } + } + + public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { + return false; + } + + public function describeAutomaticCapability($capability) { + return null; + } }