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:
parent
af9d6f593e
commit
5242fb0572
6 changed files with 85 additions and 69 deletions
|
@ -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()));
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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.',
|
||||||
|
|
Loading…
Reference in a new issue