Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14476247
D9795.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
15 KB
Referenced Files
None
Subscribers
None
D9795.diff
View Options
diff --git a/resources/sql/autopatches/20140701.legalexemption.1.sql b/resources/sql/autopatches/20140701.legalexemption.1.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20140701.legalexemption.1.sql
@@ -0,0 +1,2 @@
+ALTER TABLE {$NAMESPACE}_legalpad.legalpad_documentsignature
+ ADD isExemption BOOL NOT NULL DEFAULT 0 AFTER verified;
diff --git a/resources/sql/autopatches/20140701.legalexemption.2.sql b/resources/sql/autopatches/20140701.legalexemption.2.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20140701.legalexemption.2.sql
@@ -0,0 +1,2 @@
+ALTER TABLE {$NAMESPACE}_legalpad.legalpad_documentsignature
+ ADD exemptionPHID VARCHAR(64) COLLATE utf8_bin AFTER isExemption;
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -874,10 +874,12 @@
'LegalpadDocumentSearchEngine' => 'applications/legalpad/query/LegalpadDocumentSearchEngine.php',
'LegalpadDocumentSignController' => 'applications/legalpad/controller/LegalpadDocumentSignController.php',
'LegalpadDocumentSignature' => 'applications/legalpad/storage/LegalpadDocumentSignature.php',
+ 'LegalpadDocumentSignatureAddController' => 'applications/legalpad/controller/LegalpadDocumentSignatureAddController.php',
'LegalpadDocumentSignatureListController' => 'applications/legalpad/controller/LegalpadDocumentSignatureListController.php',
'LegalpadDocumentSignatureQuery' => 'applications/legalpad/query/LegalpadDocumentSignatureQuery.php',
'LegalpadDocumentSignatureSearchEngine' => 'applications/legalpad/query/LegalpadDocumentSignatureSearchEngine.php',
'LegalpadDocumentSignatureVerificationController' => 'applications/legalpad/controller/LegalpadDocumentSignatureVerificationController.php',
+ 'LegalpadDocumentSignatureViewController' => 'applications/legalpad/controller/LegalpadDocumentSignatureViewController.php',
'LegalpadMockMailReceiver' => 'applications/legalpad/mail/LegalpadMockMailReceiver.php',
'LegalpadReplyHandler' => 'applications/legalpad/mail/LegalpadReplyHandler.php',
'LegalpadTransaction' => 'applications/legalpad/storage/LegalpadTransaction.php',
@@ -3639,10 +3641,12 @@
0 => 'LegalpadDAO',
1 => 'PhabricatorPolicyInterface',
),
+ 'LegalpadDocumentSignatureAddController' => 'LegalpadController',
'LegalpadDocumentSignatureListController' => 'LegalpadController',
'LegalpadDocumentSignatureQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'LegalpadDocumentSignatureSearchEngine' => 'PhabricatorApplicationSearchEngine',
'LegalpadDocumentSignatureVerificationController' => 'LegalpadController',
+ 'LegalpadDocumentSignatureViewController' => 'LegalpadController',
'LegalpadMockMailReceiver' => 'PhabricatorObjectMailReceiver',
'LegalpadReplyHandler' => 'PhabricatorMailReplyHandler',
'LegalpadTransaction' => 'PhabricatorApplicationTransaction',
diff --git a/src/applications/legalpad/application/PhabricatorApplicationLegalpad.php b/src/applications/legalpad/application/PhabricatorApplicationLegalpad.php
--- a/src/applications/legalpad/application/PhabricatorApplicationLegalpad.php
+++ b/src/applications/legalpad/application/PhabricatorApplicationLegalpad.php
@@ -54,8 +54,11 @@
'LegalpadDocumentSignatureVerificationController',
'signatures/(?:(?P<id>\d+)/)?(?:query/(?P<queryKey>[^/]+)/)?' =>
'LegalpadDocumentSignatureListController',
+ 'addsignature/(?P<id>\d+)/' => 'LegalpadDocumentSignatureAddController',
+ 'signature/(?P<id>\d+)/' => 'LegalpadDocumentSignatureViewController',
'document/' => array(
- 'preview/' => 'PhabricatorMarkupPreviewController'),
+ 'preview/' => 'PhabricatorMarkupPreviewController',
+ ),
));
}
diff --git a/src/applications/legalpad/controller/LegalpadDocumentSignController.php b/src/applications/legalpad/controller/LegalpadDocumentSignController.php
--- a/src/applications/legalpad/controller/LegalpadDocumentSignController.php
+++ b/src/applications/legalpad/controller/LegalpadDocumentSignController.php
@@ -101,14 +101,26 @@
// In this case, we know they've signed.
$signed_at = $signature->getDateCreated();
+
+ if ($signature->getIsExemption()) {
+ $exemption_phid = $signature->getExemptionPHID();
+ $handles = $this->loadViewerHandles(array($exemption_phid));
+ $exemption_handle = $handles[$exemption_phid];
+
+ $signed_text = pht(
+ 'You do not need to sign this document. '.
+ '%s added a signature exemption for you on %s.',
+ $exemption_handle->renderLink(),
+ phabricator_datetime($signed_at, $viewer));
+ } else {
+ $signed_text = pht(
+ 'You signed this document on %s.',
+ phabricator_datetime($signed_at, $viewer));
+ }
+
$signed_status = id(new AphrontErrorView())
->setSeverity(AphrontErrorView::SEVERITY_NOTICE)
- ->setErrors(
- array(
- pht(
- 'You signed this document on %s.',
- phabricator_datetime($signed_at, $viewer)),
- ));
+ ->setErrors(array($signed_text));
}
$e_name = true;
diff --git a/src/applications/legalpad/controller/LegalpadDocumentSignatureAddController.php b/src/applications/legalpad/controller/LegalpadDocumentSignatureAddController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/legalpad/controller/LegalpadDocumentSignatureAddController.php
@@ -0,0 +1,127 @@
+<?php
+
+final class LegalpadDocumentSignatureAddController extends LegalpadController {
+
+ private $id;
+
+ public function willProcessRequest(array $data) {
+ $this->id = $data['id'];
+ }
+
+ public function processRequest() {
+ $request = $this->getRequest();
+ $viewer = $request->getUser();
+
+ $document = id(new LegalpadDocumentQuery())
+ ->setViewer($viewer)
+ ->needDocumentBodies(true)
+ ->requireCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ ))
+ ->withIDs(array($this->id))
+ ->executeOne();
+ if (!$document) {
+ return new Aphront404Response();
+ }
+
+ $next_uri = $this->getApplicationURI('signatures/'.$document->getID().'/');
+
+ $e_user = true;
+ $v_users = array();
+ $v_notes = '';
+ $errors = array();
+
+ if ($request->isFormPost()) {
+ $v_notes = $request->getStr('notes');
+ $v_users = array_slice($request->getArr('users'), 0, 1);
+
+ $user_phid = head($v_users);
+ if (!$user_phid) {
+ $e_user = pht('Required');
+ $errors[] = pht('You must choose a user to exempt.');
+ } else {
+ $user = id(new PhabricatorPeopleQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($user_phid))
+ ->executeOne();
+
+ if (!$user) {
+ $e_user = pht('Invalid');
+ $errors[] = pht('That user does not exist.');
+ } else {
+ $signature = id(new LegalpadDocumentSignatureQuery())
+ ->setViewer($viewer)
+ ->withDocumentPHIDs(array($document->getPHID()))
+ ->withSignerPHIDs(array($user->getPHID()))
+ ->executeOne();
+ if ($signature) {
+ $e_user = pht('Signed');
+ $errors[] = pht('That user has already signed this document.');
+ } else {
+ $e_user = null;
+ }
+ }
+ }
+
+ if (!$errors) {
+ $name = $user->getRealName();
+ $email = $user->loadPrimaryEmailAddress();
+
+ $signature = id(new LegalpadDocumentSignature())
+ ->setDocumentPHID($document->getPHID())
+ ->setDocumentVersion($document->getVersions())
+ ->setSignerPHID($user->getPHID())
+ ->setSignerName($name)
+ ->setSignerEmail($email)
+ ->setIsExemption(1)
+ ->setExemptionPHID($viewer->getPHID())
+ ->setVerified(LegalpadDocumentSignature::VERIFIED)
+ ->setSignatureData(
+ array(
+ 'name' => $name,
+ 'email' => $email,
+ 'notes' => $v_notes,
+ ));
+
+ $signature->save();
+
+ return id(new AphrontRedirectResponse())->setURI($next_uri);
+ }
+ }
+
+ $user_handles = $this->loadViewerHandles($v_users);
+
+ $form = id(new AphrontFormView())
+ ->setUser($viewer)
+ ->appendChild(
+ id(new AphrontFormTokenizerControl())
+ ->setLabel(pht('Exempt User'))
+ ->setName('users')
+ ->setLimit(1)
+ ->setDatasource('/typeahead/common/users/')
+ ->setValue($user_handles)
+ ->setError($e_user))
+ ->appendChild(
+ id(new AphrontFormTextAreaControl())
+ ->setLabel(pht('Notes'))
+ ->setName('notes')
+ ->setValue($v_notes));
+
+ return $this->newDialog()
+ ->setTitle(pht('Add Signature Exemption'))
+ ->setWidth(AphrontDialogView::WIDTH_FORM)
+ ->setErrors($errors)
+ ->appendParagraph(
+ pht(
+ 'You can record a signature exemption if a user has signed an '.
+ 'equivalent document. Other applications will behave as through the '.
+ 'user has signed this document.'))
+ ->appendParagraph(null)
+ ->appendChild($form->buildLayoutView())
+ ->addSubmitButton(pht('Add Exemption'))
+ ->addCancelButton($next_uri);
+ }
+
+}
diff --git a/src/applications/legalpad/controller/LegalpadDocumentSignatureViewController.php b/src/applications/legalpad/controller/LegalpadDocumentSignatureViewController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/legalpad/controller/LegalpadDocumentSignatureViewController.php
@@ -0,0 +1,71 @@
+<?php
+
+final class LegalpadDocumentSignatureViewController extends LegalpadController {
+
+ private $id;
+
+ public function willProcessRequest(array $data) {
+ $this->id = $data['id'];
+ }
+
+ public function processRequest() {
+ $request = $this->getRequest();
+ $viewer = $request->getUser();
+
+ $signature = id(new LegalpadDocumentSignatureQuery())
+ ->setViewer($viewer)
+ ->withIDs(array($this->id))
+ ->executeOne();
+ if (!$signature) {
+ return new Aphront404Response();
+ }
+
+
+ // NOTE: In order to see signature details (which include the relatively
+ // internal-feeling "notes" field) you must be able to edit the document.
+ // Essentially, this power is for document managers. Notably, this prevents
+ // users from seeing notes about their own exemptions by guessing their
+ // signature ID. This is purely a policy check.
+
+ $document = id(new LegalpadDocumentQuery())
+ ->setViewer($viewer)
+ ->withIDs(array($signature->getDocument()->getID()))
+ ->requireCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ ))
+ ->executeOne();
+ if (!$document) {
+ return new Aphront404Response();
+ }
+
+
+ $document_id = $signature->getDocument()->getID();
+ $next_uri = $this->getApplicationURI('signatures/'.$document_id.'/');
+
+ $exemption_phid = $signature->getExemptionPHID();
+ $handles = $this->loadViewerHandles(array($exemption_phid));
+ $exemptor_handle = $handles[$exemption_phid];
+
+ $data = $signature->getSignatureData();
+
+ $form = id(new AphrontFormView())
+ ->setUser($viewer)
+ ->appendChild(
+ id(new AphrontFormMarkupControl())
+ ->setLabel(pht('Exemption By'))
+ ->setValue($exemptor_handle->renderLink()))
+ ->appendChild(
+ id(new AphrontFormMarkupControl())
+ ->setLabel(pht('Notes'))
+ ->setValue(idx($data, 'notes')));
+
+ return $this->newDialog()
+ ->setTitle(pht('Signature Details'))
+ ->setWidth(AphrontDialogView::WIDTH_FORM)
+ ->appendChild($form->buildLayoutView())
+ ->addCancelButton($next_uri, pht('Close'));
+ }
+
+}
diff --git a/src/applications/legalpad/query/LegalpadDocumentSignatureSearchEngine.php b/src/applications/legalpad/query/LegalpadDocumentSignatureSearchEngine.php
--- a/src/applications/legalpad/query/LegalpadDocumentSignatureSearchEngine.php
+++ b/src/applications/legalpad/query/LegalpadDocumentSignatureSearchEngine.php
@@ -178,6 +178,11 @@
'red',
pht('Unverified Email'));
+ $sig_exemption = $this->renderIcon(
+ 'fa-asterisk',
+ 'indigo',
+ pht('Exemption'));
+
id(new PHUIIconView())
->setIconFont('fa-envelope', 'red')
->addSigil('has-tooltip')
@@ -190,7 +195,18 @@
$document = $signature->getDocument();
- if (!$signature->isVerified()) {
+ if ($signature->getIsExemption()) {
+ $signature_href = $this->getApplicationURI(
+ 'signature/'.$signature->getID().'/');
+
+ $sig_icon = javelin_tag(
+ 'a',
+ array(
+ 'href' => $signature_href,
+ 'sigil' => 'workflow',
+ ),
+ $sig_exemption);
+ } else if (!$signature->isVerified()) {
$sig_icon = $sig_unverified;
} else if ($signature->getDocumentVersion() != $document->getVersions()) {
$sig_icon = $sig_old;
@@ -242,8 +258,23 @@
'right',
));
+ $header = id(new PHUIHeaderView())
+ ->setHeader(pht('Signatures'));
+
+ if ($this->document) {
+ $document_id = $this->document->getID();
+
+ $header->addActionLink(
+ id(new PHUIButtonView())
+ ->setText(pht('Add Signature Exemption'))
+ ->setTag('a')
+ ->setHref($this->getApplicationURI('addsignature/'.$document_id.'/'))
+ ->setWorkflow(true)
+ ->setIcon(id(new PHUIIconView())->setIconFont('fa-pencil')));
+ }
+
$box = id(new PHUIObjectBoxView())
- ->setHeaderText(pht('Signatures'))
+ ->setHeader($header)
->appendChild($table);
if (!$this->document) {
diff --git a/src/applications/legalpad/storage/LegalpadDocumentSignature.php b/src/applications/legalpad/storage/LegalpadDocumentSignature.php
--- a/src/applications/legalpad/storage/LegalpadDocumentSignature.php
+++ b/src/applications/legalpad/storage/LegalpadDocumentSignature.php
@@ -14,6 +14,8 @@
protected $signerEmail;
protected $signatureData = array();
protected $verified;
+ protected $isExemption = 0;
+ protected $exemptionPHID;
protected $secretKey;
private $document = self::ATTACHABLE;
diff --git a/src/docs/user/userguide/legalpad.diviner b/src/docs/user/userguide/legalpad.diviner
--- a/src/docs/user/userguide/legalpad.diviner
+++ b/src/docs/user/userguide/legalpad.diviner
@@ -61,6 +61,27 @@
Users will now only be able to take the action (for example, view or edit the
object) if they have signed the specified documents.
+
+Adding Exemptions
+=================
+
+If you have users who have signed an alternate form of a document (for example,
+you have a hard copy on file), or an equivalent document, or who are otherwise
+exempt from needing to sign a document in Legalpad, you can add a signature
+exemption for them.
+
+Other applications will treat users with a signature exemption as though they
+had signed the document, although the UI will show the signature as an exemption
+rather than a normal signature.
+
+To add an exemption, go to **Manage Document**, then **View Signatures**, then
+**Add Signature Exemption**.
+
+You can optionally add notes about why a user is exempt from signing a document.
+To review the notes later (and see who added the exemption), click the colored
+asterisk in the list view.
+
+
Roadmap
========
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Dec 29, 1:48 AM (8 h, 10 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6941477
Default Alt Text
D9795.diff (15 KB)
Attached To
Mode
D9795: Allow Legalpad document managers to add signature exemptions
Attached
Detach File
Event Timeline
Log In to Comment