From d740374cca7a9c196c4c0b2f17ac66fcb919be55 Mon Sep 17 00:00:00 2001 From: Bob Trahan Date: Wed, 15 Jan 2014 16:48:44 -0800 Subject: [PATCH] Legalpad - add policy rule for legalpad document signatures Summary: Ref T3116. This creates a policy rule where you can require a signature on a given legalpad document. NOTE: signatures must be for the *latest* document version. Test Plan: made a task have a custom policy requiring a legalpad signature. verified non-signers were locked out. Reviewers: epriestley Reviewed By: epriestley CC: Korvin, epriestley, aran Maniphest Tasks: T3116 Differential Revision: https://secure.phabricator.com/D7977 --- .../autopatches/20140115.legalpadsigkey.sql | 5 ++ src/__phutil_library_map__.php | 2 + .../LegalpadDocumentSignController.php | 6 +- .../legalpad/query/LegalpadDocumentQuery.php | 27 ++++++++ ...PhabricatorPolicyRuleLegalpadSignature.php | 69 +++++++++++++++++++ ...torTypeaheadCommonDatasourceController.php | 16 +++++ 6 files changed, 122 insertions(+), 3 deletions(-) create mode 100644 resources/sql/autopatches/20140115.legalpadsigkey.sql create mode 100644 src/applications/policy/rule/PhabricatorPolicyRuleLegalpadSignature.php diff --git a/resources/sql/autopatches/20140115.legalpadsigkey.sql b/resources/sql/autopatches/20140115.legalpadsigkey.sql new file mode 100644 index 0000000000..c02873bebc --- /dev/null +++ b/resources/sql/autopatches/20140115.legalpadsigkey.sql @@ -0,0 +1,5 @@ +ALTER TABLE {$NAMESPACE}_legalpad.legalpad_documentsignature + DROP KEY `key_document`; + +ALTER TABLE {$NAMESPACE}_legalpad.legalpad_documentsignature + ADD KEY `key_document` (`documentPHID`,`signerPHID`, `documentVersion`); diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index df30647529..7a33735035 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1764,6 +1764,7 @@ phutil_register_library_map(array( 'PhabricatorPolicyQuery' => 'applications/policy/query/PhabricatorPolicyQuery.php', 'PhabricatorPolicyRule' => 'applications/policy/rule/PhabricatorPolicyRule.php', 'PhabricatorPolicyRuleAdministrators' => 'applications/policy/rule/PhabricatorPolicyRuleAdministrators.php', + 'PhabricatorPolicyRuleLegalpadSignature' => 'applications/policy/rule/PhabricatorPolicyRuleLegalpadSignature.php', 'PhabricatorPolicyRuleLunarPhase' => 'applications/policy/rule/PhabricatorPolicyRuleLunarPhase.php', 'PhabricatorPolicyRuleProjects' => 'applications/policy/rule/PhabricatorPolicyRuleProjects.php', 'PhabricatorPolicyRuleUsers' => 'applications/policy/rule/PhabricatorPolicyRuleUsers.php', @@ -4395,6 +4396,7 @@ phutil_register_library_map(array( 'PhabricatorPolicyPHIDTypePolicy' => 'PhabricatorPHIDType', 'PhabricatorPolicyQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorPolicyRuleAdministrators' => 'PhabricatorPolicyRule', + 'PhabricatorPolicyRuleLegalpadSignature' => 'PhabricatorPolicyRule', 'PhabricatorPolicyRuleLunarPhase' => 'PhabricatorPolicyRule', 'PhabricatorPolicyRuleProjects' => 'PhabricatorPolicyRule', 'PhabricatorPolicyRuleUsers' => 'PhabricatorPolicyRule', diff --git a/src/applications/legalpad/controller/LegalpadDocumentSignController.php b/src/applications/legalpad/controller/LegalpadDocumentSignController.php index 1d1896bfab..0c0e96b22f 100644 --- a/src/applications/legalpad/controller/LegalpadDocumentSignController.php +++ b/src/applications/legalpad/controller/LegalpadDocumentSignController.php @@ -58,10 +58,10 @@ final class LegalpadDocumentSignController extends LegalpadController { if ($signer_phid) { $signature = id(new LegalpadDocumentSignature()) ->loadOneWhere( - 'documentPHID = %s AND documentVersion = %d AND signerPHID = %s', + 'documentPHID = %s AND signerPHID = %s AND documentVersion = %d', $document->getPHID(), - $document->getVersions(), - $signer_phid); + $signer_phid, + $document->getVersions()); } if (!$signature) { diff --git a/src/applications/legalpad/query/LegalpadDocumentQuery.php b/src/applications/legalpad/query/LegalpadDocumentQuery.php index 22db1808b0..ad076ee1f3 100644 --- a/src/applications/legalpad/query/LegalpadDocumentQuery.php +++ b/src/applications/legalpad/query/LegalpadDocumentQuery.php @@ -10,6 +10,7 @@ final class LegalpadDocumentQuery private $phids; private $creatorPHIDs; private $contributorPHIDs; + private $signerPHIDs; private $dateCreatedAfter; private $dateCreatedBefore; @@ -36,6 +37,11 @@ final class LegalpadDocumentQuery return $this; } + public function withSignerPHIDs(array $phids) { + $this->signerPHIDs = $phids; + return $this; + } + public function needDocumentBodies($need_bodies) { $this->needDocumentBodies = $need_bodies; return $this; @@ -75,6 +81,27 @@ final class LegalpadDocumentQuery } protected function willFilterPage(array $documents) { + if ($this->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 = 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) { $documents = $this->loadDocumentBodies($documents); } diff --git a/src/applications/policy/rule/PhabricatorPolicyRuleLegalpadSignature.php b/src/applications/policy/rule/PhabricatorPolicyRuleLegalpadSignature.php new file mode 100644 index 0000000000..8941d53b28 --- /dev/null +++ b/src/applications/policy/rule/PhabricatorPolicyRuleLegalpadSignature.php @@ -0,0 +1,69 @@ +setViewer(PhabricatorUser::getOmnipotentUser()) + ->withPHIDs($values) + ->withSignerPHIDs(array($viewer->getPHID())) + ->execute(); + $this->signatures = mpull($documents, 'getPHID', 'getPHID'); + } + + public function applyRule(PhabricatorUser $viewer, $value) { + foreach ($value as $document_phid) { + if (!isset($this->signatures[$document_phid])) { + return false; + } + } + return true; + } + + public function getValueControlType() { + return self::CONTROL_TYPE_TOKENIZER; + } + + public function getValueControlTemplate() { + return array( + 'markup' => new AphrontTokenizerTemplateView(), + 'uri' => '/typeahead/common/legalpaddocuments/', + 'placeholder' => pht('Type a document title...'), + ); + } + + public function getRuleOrder() { + return 900; + } + + public function getValueForStorage($value) { + PhutilTypeSpec::newFromString('list')->check($value); + return array_values($value); + } + + public function getValueForDisplay(PhabricatorUser $viewer, $value) { + $handles = id(new PhabricatorHandleQuery()) + ->setViewer($viewer) + ->withPHIDs($value) + ->execute(); + + return mpull($handles, 'getFullName', 'getPHID'); + } + + public function ruleHasEffect($value) { + return (bool)$value; + } + +} diff --git a/src/applications/typeahead/controller/PhabricatorTypeaheadCommonDatasourceController.php b/src/applications/typeahead/controller/PhabricatorTypeaheadCommonDatasourceController.php index 32db073e3b..e7d9ab0f97 100644 --- a/src/applications/typeahead/controller/PhabricatorTypeaheadCommonDatasourceController.php +++ b/src/applications/typeahead/controller/PhabricatorTypeaheadCommonDatasourceController.php @@ -37,6 +37,7 @@ final class PhabricatorTypeaheadCommonDatasourceController $need_jump_objects = false; $need_build_plans = false; $need_macros = false; + $need_legalpad_documents = false; switch ($this->type) { case 'mainsearch': $need_users = true; @@ -101,6 +102,9 @@ final class PhabricatorTypeaheadCommonDatasourceController case 'macros': $need_macros = true; break; + case 'legalpaddocuments': + $need_legalpad_documents = true; + break; } $results = array(); @@ -252,6 +256,18 @@ final class PhabricatorTypeaheadCommonDatasourceController } } + if ($need_legalpad_documents) { + $documents = id(new LegalpadDocumentQuery()) + ->setViewer($viewer) + ->execute(); + $documents = mpull($documents, 'getTitle', 'getPHID'); + foreach ($documents as $phid => $title) { + $results[] = id(new PhabricatorTypeaheadResult()) + ->setPHID($phid) + ->setName($title); + } + } + if ($need_projs) { $projs = id(new PhabricatorProjectQuery()) ->setViewer($viewer)