1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-26 16:52:41 +01:00

Use ApplicationSearch to search for Legalpad signatures

Summary:
Ref T3116. Currently, document signatures are just in a big list that you can't search through.

  - Make it easier to check if a specific user has signed.
  - Restrict this UI to users who have edit permission on the document (roughly, you need to be a document manager to see the full signature list).

(It's currently possible to generate a Dashboard panel using this query, but it will just throw an exception. I'm going to leave it like that for now, we might reasonably expose some "view signatures across doucments" UI later so someone can quickly check if a user has signed 5 documents or something.)

Test Plan: {F171576}

Reviewers: chad

Reviewed By: chad

Subscribers: epriestley

Maniphest Tasks: T3116

Differential Revision: https://secure.phabricator.com/D9765
This commit is contained in:
epriestley 2014-06-28 16:36:37 -07:00
parent 45d61b7110
commit d8bba221b5
4 changed files with 204 additions and 90 deletions

View file

@ -873,6 +873,7 @@ phutil_register_library_map(array(
'LegalpadDocumentSignature' => 'applications/legalpad/storage/LegalpadDocumentSignature.php', 'LegalpadDocumentSignature' => 'applications/legalpad/storage/LegalpadDocumentSignature.php',
'LegalpadDocumentSignatureListController' => 'applications/legalpad/controller/LegalpadDocumentSignatureListController.php', 'LegalpadDocumentSignatureListController' => 'applications/legalpad/controller/LegalpadDocumentSignatureListController.php',
'LegalpadDocumentSignatureQuery' => 'applications/legalpad/query/LegalpadDocumentSignatureQuery.php', 'LegalpadDocumentSignatureQuery' => 'applications/legalpad/query/LegalpadDocumentSignatureQuery.php',
'LegalpadDocumentSignatureSearchEngine' => 'applications/legalpad/query/LegalpadDocumentSignatureSearchEngine.php',
'LegalpadDocumentSignatureVerificationController' => 'applications/legalpad/controller/LegalpadDocumentSignatureVerificationController.php', 'LegalpadDocumentSignatureVerificationController' => 'applications/legalpad/controller/LegalpadDocumentSignatureVerificationController.php',
'LegalpadMockMailReceiver' => 'applications/legalpad/mail/LegalpadMockMailReceiver.php', 'LegalpadMockMailReceiver' => 'applications/legalpad/mail/LegalpadMockMailReceiver.php',
'LegalpadReplyHandler' => 'applications/legalpad/mail/LegalpadReplyHandler.php', 'LegalpadReplyHandler' => 'applications/legalpad/mail/LegalpadReplyHandler.php',
@ -3633,6 +3634,7 @@ phutil_register_library_map(array(
), ),
'LegalpadDocumentSignatureListController' => 'LegalpadController', 'LegalpadDocumentSignatureListController' => 'LegalpadController',
'LegalpadDocumentSignatureQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'LegalpadDocumentSignatureQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'LegalpadDocumentSignatureSearchEngine' => 'PhabricatorApplicationSearchEngine',
'LegalpadDocumentSignatureVerificationController' => 'LegalpadController', 'LegalpadDocumentSignatureVerificationController' => 'LegalpadController',
'LegalpadMockMailReceiver' => 'PhabricatorObjectMailReceiver', 'LegalpadMockMailReceiver' => 'PhabricatorObjectMailReceiver',
'LegalpadReplyHandler' => 'PhabricatorMailReplyHandler', 'LegalpadReplyHandler' => 'PhabricatorMailReplyHandler',

View file

@ -41,15 +41,16 @@ final class PhabricatorApplicationLegalpad extends PhabricatorApplication {
'/L(?P<id>\d+)' => 'LegalpadDocumentSignController', '/L(?P<id>\d+)' => 'LegalpadDocumentSignController',
'/legalpad/' => array( '/legalpad/' => array(
'' => 'LegalpadDocumentListController', '' => 'LegalpadDocumentListController',
'(query/(?P<queryKey>[^/]+)/)?' => 'LegalpadDocumentListController', '(?:query/(?P<queryKey>[^/]+)/)?' => 'LegalpadDocumentListController',
'create/' => 'LegalpadDocumentEditController', 'create/' => 'LegalpadDocumentEditController',
'edit/(?P<id>\d+)/' => 'LegalpadDocumentEditController', 'edit/(?P<id>\d+)/' => 'LegalpadDocumentEditController',
'comment/(?P<id>\d+)/' => 'LegalpadDocumentCommentController', 'comment/(?P<id>\d+)/' => 'LegalpadDocumentCommentController',
'view/(?P<id>\d+)/' => 'LegalpadDocumentManageController', 'view/(?P<id>\d+)/' => 'LegalpadDocumentManageController',
'done/' => 'LegalpadDocumentDoneController', 'done/' => 'LegalpadDocumentDoneController',
'verify/(?P<code>[^/]+)/' => 'verify/(?P<code>[^/]+)/' =>
'LegalpadDocumentSignatureVerificationController', 'LegalpadDocumentSignatureVerificationController',
'signatures/(?P<id>\d+)/' => 'LegalpadDocumentSignatureListController', 'signatures/(?P<id>\d+)/(?:query/(?P<queryKey>[^/]+)/)?'
=> 'LegalpadDocumentSignatureListController',
'document/' => array( 'document/' => array(
'preview/' => 'PhabricatorMarkupPreviewController'), 'preview/' => 'PhabricatorMarkupPreviewController'),
)); ));

View file

@ -2,10 +2,13 @@
final class LegalpadDocumentSignatureListController extends LegalpadController { final class LegalpadDocumentSignatureListController extends LegalpadController {
private $documentId; private $documentID;
private $queryKey;
private $document;
public function willProcessRequest(array $data) { public function willProcessRequest(array $data) {
$this->documentId = $data['id']; $this->documentID = $data['id'];
$this->queryKey = idx($data, 'queryKey');
} }
public function processRequest() { public function processRequest() {
@ -14,108 +17,52 @@ final class LegalpadDocumentSignatureListController extends LegalpadController {
$document = id(new LegalpadDocumentQuery()) $document = id(new LegalpadDocumentQuery())
->setViewer($user) ->setViewer($user)
->withIDs(array($this->documentId)) ->withIDs(array($this->documentID))
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->executeOne(); ->executeOne();
if (!$document) { if (!$document) {
return new Aphront404Response(); return new Aphront404Response();
} }
$title = pht('Signatures for %s', $document->getMonogram()); $this->document = $document;
$pager = id(new AphrontCursorPagerView()) $engine = id(new LegalpadDocumentSignatureSearchEngine())
->readFromRequest($request); ->setDocument($document);
$signatures = id(new LegalpadDocumentSignatureQuery())
->setViewer($user)
->withDocumentPHIDs(array($document->getPHID()))
->executeWithCursorPager($pager);
$crumbs = $this->buildApplicationCrumbs($this->buildSideNav()); $controller = id(new PhabricatorApplicationSearchController($request))
$crumbs->addTextCrumb( ->setQueryKey($this->queryKey)
$document->getMonogram(), ->setSearchEngine($engine)
$this->getApplicationURI('view/'.$document->getID())); ->setNavigation($this->buildSideNav());
$crumbs->addTextCrumb( return $this->delegateToController($controller);
pht('Signatures'));
$list = $this->renderResultsList($document, $signatures);
$list->setPager($pager);
return $this->buildApplicationPage(
array(
$crumbs,
$list,
),
array(
'title' => $title,
));
} }
private function renderResultsList( public function buildSideNav($for_app = false) {
LegalpadDocument $document,
array $signatures) {
assert_instances_of($signatures, 'LegalpadDocumentSignature');
$user = $this->getRequest()->getUser(); $user = $this->getRequest()->getUser();
$list = new PHUIObjectItemListView(); $nav = new AphrontSideNavFilterView();
$list->setUser($user); $nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
foreach ($signatures as $signature) { id(new LegalpadDocumentSignatureSearchEngine())
$created = phabricator_date($signature->getDateCreated(), $user); ->setViewer($user)
->setDocument($this->document)
->addNavigationItems($nav->getMenu());
$data = $signature->getSignatureData(); return $nav;
}
$sig_data = phutil_tag( public function buildApplicationCrumbs() {
'div', $crumbs = parent::buildApplicationCrumbs();
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()) $crumbs->addTextCrumb(
->setObject($signature) $this->document->getMonogram(),
->setHeader($data['name']) '/'.$this->document->getMonogram());
->setSubhead($sig_data)
->addIcon('none', pht('Signed %s', $created));
$good_sig = true; return $crumbs;
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;
} }
} }

View file

@ -0,0 +1,164 @@
<?php
final class LegalpadDocumentSignatureSearchEngine
extends PhabricatorApplicationSearchEngine {
private $document;
public function getResultTypeDescription() {
return pht('Legalpad Signatures');
}
public function getApplicationClassName() {
return 'PhabricatorApplicationLegalpad';
}
public function setDocument(LegalpadDocument $document) {
$this->document = $document;
return $this;
}
public function buildSavedQueryFromRequest(AphrontRequest $request) {
$saved = new PhabricatorSavedQuery();
$saved->setParameter(
'signerPHIDs',
$this->readUsersFromRequest($request, 'signers'));
return $saved;
}
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
$query = id(new LegalpadDocumentSignatureQuery());
$signer_phids = $saved->getParameter('signerPHIDs', array());
if ($signer_phids) {
$query->withSignerPHIDs($signer_phids);
}
if ($this->document) {
$query->withDocumentPHIDs(array($this->document->getPHID()));
}
return $query;
}
public function buildSearchForm(
AphrontFormView $form,
PhabricatorSavedQuery $saved_query) {
$signer_phids = $saved_query->getParameter('signerPHIDs', array());
$phids = array_merge($signer_phids);
$handles = id(new PhabricatorHandleQuery())
->setViewer($this->requireViewer())
->withPHIDs($phids)
->execute();
$form
->appendChild(
id(new AphrontFormTokenizerControl())
->setDatasource('/typeahead/common/users/')
->setName('signers')
->setLabel(pht('Signers'))
->setValue(array_select_keys($handles, $signer_phids)));
}
protected function getURI($path) {
if ($this->document) {
return '/legalpad/signatures/'.$this->document->getID().'/'.$path;
} else {
throw new Exception(
pht(
'Searching for signatures outside of a document context is not '.
'currently supported.'));
}
}
public function getBuiltinQueryNames() {
$names = array(
'all' => pht('All Signatures'),
);
return $names;
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
switch ($query_key) {
case 'all':
return $query;
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
protected function getRequiredHandlePHIDsForResultList(
array $documents,
PhabricatorSavedQuery $query) {
return mpull($documents, 'getSignerPHID');
}
protected function renderResultList(
array $signatures,
PhabricatorSavedQuery $query,
array $handles) {
assert_instances_of($signatures, 'LegalpadDocumentSignature');
$viewer = $this->requireViewer();
$list = new PHUIObjectItemListView();
$list->setUser($viewer);
foreach ($signatures as $signature) {
$created = phabricator_date($signature->getDateCreated(), $viewer);
$data = $signature->getSignatureData();
$sig_data = phutil_tag(
'div',
array(),
array(
phutil_tag(
'div',
array(),
phutil_tag(
'a',
array(
'href' => 'mailto:'.$data['email'],
),
$data['email'])),
));
$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;
}
$document = $signature->getDocument();
if ($signature->getDocumentVersion() != $document->getVersions()) {
$item->addFootIcon('delete', 'Stale Signature');
$good_sig = false;
}
if ($good_sig) {
$item->setBarColor('green');
}
$list->addItem($item);
}
return $list;
}
}