1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-23 14:00:56 +01:00

Add a "documents I've signed" view to Legalpad

Summary:
Ref T3116. Allow documents to be queried for ones the viewer has signed, and make this the default view.

This also relaxes the versioning stuff a little bit, and stops invalidating signatures on older versions of documents. While I think we should do that eventually, it should be more explicit and have better coordination in the UI. For now, we'll track and show older signatures, but not invalidate them.

I imagine eventually differentiating between "minor edits" (typo / link fixes, for example) and major edits which actually require re-signature.

Test Plan: {F171650}

Reviewers: chad

Reviewed By: chad

Subscribers: epriestley

Maniphest Tasks: T3116

Differential Revision: https://secure.phabricator.com/D9769
This commit is contained in:
epriestley 2014-06-28 16:37:15 -07:00
parent af9d6f593e
commit 5242fb0572
6 changed files with 85 additions and 69 deletions

View file

@ -31,7 +31,6 @@ final class LegalpadDocumentEditController extends LegalpadController {
$document = id(new LegalpadDocumentQuery()) $document = id(new LegalpadDocumentQuery())
->setViewer($user) ->setViewer($user)
->needDocumentBodies(true) ->needDocumentBodies(true)
->needSignatures(true)
->requireCapabilities( ->requireCapabilities(
array( array(
PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_VIEW,
@ -154,14 +153,7 @@ final class LegalpadDocumentEditController extends LegalpadController {
$this->getApplicationURI('view/'.$document->getID())); $this->getApplicationURI('view/'.$document->getID()));
$title = pht('Update Document'); $title = pht('Update Document');
$short = pht('Update'); $short = pht('Update');
$signatures = $document->getSignatures();
if ($signatures) {
$form->appendInstructions(pht(
'Warning: there are %d signature(s) already for this document. '.
'Updating the title or text will invalidate these signatures and '.
'users will need to sign again. Proceed carefully.',
count($signatures)));
}
$crumbs->addTextCrumb( $crumbs->addTextCrumb(
$document->getMonogram(), $document->getMonogram(),
$this->getApplicationURI('view/'.$document->getID())); $this->getApplicationURI('view/'.$document->getID()));

View file

@ -77,10 +77,11 @@ final class LegalpadDocumentQuery
$data = queryfx_all( $data = queryfx_all(
$conn_r, $conn_r,
'SELECT d.* FROM %T d %Q %Q %Q %Q', 'SELECT d.* FROM %T d %Q %Q %Q %Q %Q',
$table->getTableName(), $table->getTableName(),
$this->buildJoinClause($conn_r), $this->buildJoinClause($conn_r),
$this->buildWhereClause($conn_r), $this->buildWhereClause($conn_r),
$this->buildGroupClause($conn_r),
$this->buildOrderClause($conn_r), $this->buildOrderClause($conn_r),
$this->buildLimitClause($conn_r)); $this->buildLimitClause($conn_r));
@ -90,28 +91,6 @@ final class LegalpadDocumentQuery
} }
protected function willFilterPage(array $documents) { protected function willFilterPage(array $documents) {
if ($this->signerPHIDs) {
$document_map = mpull($documents, null, 'getPHID');
$signatures = id(new LegalpadDocumentSignatureQuery())
->setViewer($this->getViewer())
->withDocumentPHIDs(array_keys($document_map))
->withSignerPHIDs($this->signerPHIDs)
->execute();
$signatures = mgroup($signatures, 'getDocumentPHID');
foreach ($document_map as $document_phid => $document) {
$sigs = idx($signatures, $document_phid, array());
foreach ($sigs as $index => $sig) {
if ($sig->getDocumentVersion() != $document->getVersions()) {
unset($sigs[$index]);
}
}
$signer_phids = mpull($sigs, 'getSignerPHID');
if (array_diff($this->signerPHIDs, $signer_phids)) {
unset($documents[$document->getID()]);
}
}
}
if ($this->needDocumentBodies) { if ($this->needDocumentBodies) {
$documents = $this->loadDocumentBodies($documents); $documents = $this->loadDocumentBodies($documents);
} }
@ -126,7 +105,6 @@ final class LegalpadDocumentQuery
if ($this->needViewerSignatures) { if ($this->needViewerSignatures) {
if ($documents) { if ($documents) {
if ($this->getViewer()->getPHID()) { if ($this->getViewer()->getPHID()) {
$signatures = id(new LegalpadDocumentSignatureQuery()) $signatures = id(new LegalpadDocumentSignatureQuery())
->setViewer($this->getViewer()) ->setViewer($this->getViewer())
@ -153,63 +131,81 @@ final class LegalpadDocumentQuery
private function buildJoinClause($conn_r) { private function buildJoinClause($conn_r) {
$joins = array(); $joins = array();
if ($this->contributorPHIDs) { if ($this->contributorPHIDs !== null) {
$joins[] = qsprintf( $joins[] = qsprintf(
$conn_r, $conn_r,
'JOIN edge e ON e.src = d.phid'); 'JOIN edge contributor ON contributor.src = d.phid
AND contributor.type = %d',
PhabricatorEdgeConfig::TYPE_OBJECT_HAS_CONTRIBUTOR);
}
if ($this->signerPHIDs !== null) {
$joins[] = qsprintf(
$conn_r,
'JOIN %T signer ON signer.documentPHID = d.phid
AND signer.signerPHID IN (%Ls)',
id(new LegalpadDocumentSignature())->getTableName(),
$this->signerPHIDs);
} }
return implode(' ', $joins); return implode(' ', $joins);
} }
private function buildGroupClause(AphrontDatabaseConnection $conn_r) {
if ($this->contributorPHIDs || $this->signerPHIDs) {
return 'GROUP BY d.id';
} else {
return '';
}
}
protected function buildWhereClause($conn_r) { protected function buildWhereClause($conn_r) {
$where = array(); $where = array();
$where[] = $this->buildPagingClause($conn_r); if ($this->ids !== null) {
if ($this->ids) {
$where[] = qsprintf( $where[] = qsprintf(
$conn_r, $conn_r,
'd.id IN (%Ld)', 'd.id IN (%Ld)',
$this->ids); $this->ids);
} }
if ($this->phids) { if ($this->phids !== null) {
$where[] = qsprintf( $where[] = qsprintf(
$conn_r, $conn_r,
'd.phid IN (%Ls)', 'd.phid IN (%Ls)',
$this->phids); $this->phids);
} }
if ($this->creatorPHIDs) { if ($this->creatorPHIDs !== null) {
$where[] = qsprintf( $where[] = qsprintf(
$conn_r, $conn_r,
'd.creatorPHID IN (%Ls)', 'd.creatorPHID IN (%Ls)',
$this->creatorPHIDs); $this->creatorPHIDs);
} }
if ($this->dateCreatedAfter) { if ($this->dateCreatedAfter !== null) {
$where[] = qsprintf( $where[] = qsprintf(
$conn_r, $conn_r,
'd.dateCreated >= %d', 'd.dateCreated >= %d',
$this->dateCreatedAfter); $this->dateCreatedAfter);
} }
if ($this->dateCreatedBefore) { if ($this->dateCreatedBefore !== null) {
$where[] = qsprintf( $where[] = qsprintf(
$conn_r, $conn_r,
'd.dateCreated <= %d', 'd.dateCreated <= %d',
$this->dateCreatedBefore); $this->dateCreatedBefore);
} }
if ($this->contributorPHIDs) { if ($this->contributorPHIDs !== null) {
$where[] = qsprintf( $where[] = qsprintf(
$conn_r, $conn_r,
'e.type = %s AND e.dst IN (%Ls)', 'contributor.dst IN (%Ls)',
PhabricatorEdgeConfig::TYPE_OBJECT_HAS_CONTRIBUTOR,
$this->contributorPHIDs); $this->contributorPHIDs);
} }
$where[] = $this->buildPagingClause($conn_r);
return $this->formatWhereClause($where); return $this->formatWhereClause($where);
} }
@ -256,11 +252,6 @@ final class LegalpadDocumentQuery
foreach ($documents as $document) { foreach ($documents as $document) {
$sigs = idx($signatures, $document->getPHID(), array()); $sigs = idx($signatures, $document->getPHID(), array());
foreach ($sigs as $index => $sig) {
if ($sig->getDocumentVersion() != $document->getVersions()) {
unset($sigs[$index]);
}
}
$document->attachSignatures($sigs); $document->attachSignatures($sigs);
} }

View file

@ -21,6 +21,10 @@ final class LegalpadDocumentSearchEngine
'contributorPHIDs', 'contributorPHIDs',
$this->readUsersFromRequest($request, 'contributors')); $this->readUsersFromRequest($request, 'contributors'));
$saved->setParameter(
'withViewerSignature',
$request->getBool('withViewerSignature'));
$saved->setParameter('createdStart', $request->getStr('createdStart')); $saved->setParameter('createdStart', $request->getStr('createdStart'));
$saved->setParameter('createdEnd', $request->getStr('createdEnd')); $saved->setParameter('createdEnd', $request->getStr('createdEnd'));
@ -29,9 +33,24 @@ final class LegalpadDocumentSearchEngine
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
$query = id(new LegalpadDocumentQuery()) $query = id(new LegalpadDocumentQuery())
->needViewerSignatures(true) ->needViewerSignatures(true);
->withCreatorPHIDs($saved->getParameter('creatorPHIDs', array()))
->withContributorPHIDs($saved->getParameter('contributorPHIDs', array())); $creator_phids = $saved->getParameter('creatorPHIDs', array());
if ($creator_phids) {
$query->withCreatorPHIDs($creator_phids);
}
$contributor_phids = $saved->getParameter('contributorPHIDs', array());
if ($contributor_phids) {
$query->withContributorPHIDs($contributor_phids);
}
if ($saved->getParameter('withViewerSignature')) {
$viewer_phid = $this->requireViewer()->getPHID();
if ($viewer_phid) {
$query->withSignerPHIDs(array($viewer_phid));
}
}
$start = $this->parseDateTime($saved->getParameter('createdStart')); $start = $this->parseDateTime($saved->getParameter('createdStart'));
$end = $this->parseDateTime($saved->getParameter('createdEnd')); $end = $this->parseDateTime($saved->getParameter('createdEnd'));
@ -60,7 +79,20 @@ final class LegalpadDocumentSearchEngine
->withPHIDs($phids) ->withPHIDs($phids)
->execute(); ->execute();
$viewer_signature = $saved_query->getParameter('withViewerSignature');
if (!$this->requireViewer()->getPHID()) {
$viewer_signature = false;
}
$form $form
->appendChild(
id(new AphrontFormCheckboxControl())
->addCheckbox(
'withViewerSignature',
1,
pht('Show only documents I have signed.'),
$viewer_signature)
->setDisabled(!$this->requireViewer()->getPHID()))
->appendChild( ->appendChild(
id(new AphrontFormTokenizerControl()) id(new AphrontFormTokenizerControl())
->setDatasource('/typeahead/common/users/') ->setDatasource('/typeahead/common/users/')
@ -89,9 +121,13 @@ final class LegalpadDocumentSearchEngine
} }
public function getBuiltinQueryNames() { public function getBuiltinQueryNames() {
$names = array( $names = array();
'all' => pht('All Documents'),
); if ($this->requireViewer()->isLoggedIn()) {
$names['signed'] = pht('Signed Documents');
}
$names['all'] = pht('All Documents');
return $names; return $names;
} }
@ -102,6 +138,9 @@ final class LegalpadDocumentSearchEngine
$query->setQueryKey($query_key); $query->setQueryKey($query_key);
switch ($query_key) { switch ($query_key) {
case 'signed':
return $query
->setParameter('withViewerSignature', true);
case 'all': case 'all':
return $query; return $query;
} }

View file

@ -14,12 +14,14 @@ final class PhabricatorPolicyDataTestCase extends PhabricatorTestCase {
$proj_a = id(new PhabricatorProject()) $proj_a = id(new PhabricatorProject())
->setName('A') ->setName('A')
->setAuthorPHID($author->getPHID()) ->setAuthorPHID($author->getPHID())
->setIcon('fa-briefcase') ->setIcon(PhabricatorProject::DEFAULT_ICON)
->setColor(PhabricatorProject::DEFAULT_COLOR)
->save(); ->save();
$proj_b = id(new PhabricatorProject()) $proj_b = id(new PhabricatorProject())
->setName('B') ->setName('B')
->setAuthorPHID($author->getPHID()) ->setAuthorPHID($author->getPHID())
->setIcon('fa-briefcase') ->setIcon(PhabricatorProject::DEFAULT_ICON)
->setColor(PhabricatorProject::DEFAULT_COLOR)
->save(); ->save();
$proj_a->setViewPolicy($proj_b->getPHID())->save(); $proj_a->setViewPolicy($proj_b->getPHID())->save();

View file

@ -15,6 +15,9 @@ final class PhabricatorPolicyRuleLegalpadSignature
return; return;
} }
// TODO: This accepts signature of any version of the document, even an
// older version.
$documents = id(new LegalpadDocumentQuery()) $documents = id(new LegalpadDocumentQuery())
->setViewer(PhabricatorUser::getOmnipotentUser()) ->setViewer(PhabricatorUser::getOmnipotentUser())
->withPHIDs($values) ->withPHIDs($values)

View file

@ -890,17 +890,6 @@ abstract class PhabricatorBaseEnglishTranslation
'%d Users Need Approval', '%d Users Need Approval',
), ),
'Warning: there are %d signature(s) already for this document. '.
'Updating the title or text will invalidate these signatures and users '.
'will need to sign again. Proceed carefully.' => array(
'Warning: there is %d signature already for this document. '.
'Updating the title or text will invalidate this signature and the '.
'user will need to sign again. Proceed carefully.',
'Warning: there are %d signatures already for this document. '.
'Updating the title or text will invalidate these signatures and '.
'users will need to sign again. Proceed carefully.',
),
'%s older changes(s) are hidden.' => array( '%s older changes(s) are hidden.' => array(
'%d older change is hidden.', '%d older change is hidden.',
'%d older changes are hidden.', '%d older changes are hidden.',