mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-26 08:42:41 +01:00
Legalpad - add signature page
Summary: Fixes T3481. Sort of - this thing be very ugly. Also it assumes that you'll "always" want to sign terms. I was thinking in a future diff that should be optional as well as configurable, though it was unclear to me if either was worth pursuing... Generally very hideous as the three main elements (PHUIDocument, AphrontErrorView, and AphrontForm with an AphrontFormInset) have never really played together before. Test Plan: agreed to some test terms. noted UI displayed nicely. reloaded and noted UI told me I had signed it already. Went to different terms and filled them out wrong and got sensical errors. Reviewers: epriestley Reviewed By: epriestley CC: aran, Korvin Maniphest Tasks: T3481 Differential Revision: https://secure.phabricator.com/D6399
This commit is contained in:
parent
d467c49a66
commit
4fb3b27f1d
10 changed files with 260 additions and 9 deletions
2
resources/sql/patches/20130709.legalpadsignature.sql
Normal file
2
resources/sql/patches/20130709.legalpadsignature.sql
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_legalpad.legalpad_documentsignature
|
||||||
|
ADD signatureData LONGTEXT NOT NULL COLLATE utf8_bin AFTER signerPHID;
|
|
@ -644,6 +644,7 @@ phutil_register_library_map(array(
|
||||||
'LegalpadDocumentPreviewController' => 'applications/legalpad/controller/LegalpadDocumentPreviewController.php',
|
'LegalpadDocumentPreviewController' => 'applications/legalpad/controller/LegalpadDocumentPreviewController.php',
|
||||||
'LegalpadDocumentQuery' => 'applications/legalpad/query/LegalpadDocumentQuery.php',
|
'LegalpadDocumentQuery' => 'applications/legalpad/query/LegalpadDocumentQuery.php',
|
||||||
'LegalpadDocumentSearchEngine' => 'applications/legalpad/query/LegalpadDocumentSearchEngine.php',
|
'LegalpadDocumentSearchEngine' => 'applications/legalpad/query/LegalpadDocumentSearchEngine.php',
|
||||||
|
'LegalpadDocumentSignController' => 'applications/legalpad/controller/LegalpadDocumentSignController.php',
|
||||||
'LegalpadDocumentSignature' => 'applications/legalpad/storage/LegalpadDocumentSignature.php',
|
'LegalpadDocumentSignature' => 'applications/legalpad/storage/LegalpadDocumentSignature.php',
|
||||||
'LegalpadDocumentViewController' => 'applications/legalpad/controller/LegalpadDocumentViewController.php',
|
'LegalpadDocumentViewController' => 'applications/legalpad/controller/LegalpadDocumentViewController.php',
|
||||||
'LegalpadMockMailReceiver' => 'applications/legalpad/mail/LegalpadMockMailReceiver.php',
|
'LegalpadMockMailReceiver' => 'applications/legalpad/mail/LegalpadMockMailReceiver.php',
|
||||||
|
@ -2573,6 +2574,7 @@ phutil_register_library_map(array(
|
||||||
'LegalpadDocumentPreviewController' => 'LegalpadController',
|
'LegalpadDocumentPreviewController' => 'LegalpadController',
|
||||||
'LegalpadDocumentQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
'LegalpadDocumentQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
'LegalpadDocumentSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
'LegalpadDocumentSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||||
|
'LegalpadDocumentSignController' => 'LegalpadController',
|
||||||
'LegalpadDocumentSignature' => 'LegalpadDAO',
|
'LegalpadDocumentSignature' => 'LegalpadDAO',
|
||||||
'LegalpadDocumentViewController' => 'LegalpadController',
|
'LegalpadDocumentViewController' => 'LegalpadController',
|
||||||
'LegalpadMockMailReceiver' => 'PhabricatorObjectMailReceiver',
|
'LegalpadMockMailReceiver' => 'PhabricatorObjectMailReceiver',
|
||||||
|
|
|
@ -40,7 +40,7 @@ final class PhabricatorApplicationLegalpad extends PhabricatorApplication {
|
||||||
|
|
||||||
public function getRoutes() {
|
public function getRoutes() {
|
||||||
return array(
|
return array(
|
||||||
'/L(?P<id>\d+)/' => 'LegalpadDocumentViewController',
|
'/L(?P<id>\d+)' => 'LegalpadDocumentSignController',
|
||||||
'/legalpad/' => array(
|
'/legalpad/' => array(
|
||||||
'' => 'LegalpadDocumentListController',
|
'' => 'LegalpadDocumentListController',
|
||||||
'(query/(?P<queryKey>[^/]+)/)?' => 'LegalpadDocumentListController',
|
'(query/(?P<queryKey>[^/]+)/)?' => 'LegalpadDocumentListController',
|
||||||
|
|
|
@ -37,8 +37,8 @@ final class LegalpadDocumentListController extends LegalpadController
|
||||||
$list->setUser($user);
|
$list->setUser($user);
|
||||||
foreach ($documents as $document) {
|
foreach ($documents as $document) {
|
||||||
$last_updated = phabricator_date($document->getDateModified(), $user);
|
$last_updated = phabricator_date($document->getDateModified(), $user);
|
||||||
$updater = $this->getHandle(
|
$recent_contributors = $document->getRecentContributorPHIDs();
|
||||||
reset($document->getRecentContributorPHIDs()))->renderLink();
|
$updater = $this->getHandle(reset($recent_contributors))->renderLink();
|
||||||
|
|
||||||
$title = $document->getTitle();
|
$title = $document->getTitle();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,236 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group legalpad
|
||||||
|
*/
|
||||||
|
final class LegalpadDocumentSignController extends LegalpadController {
|
||||||
|
|
||||||
|
private $id;
|
||||||
|
|
||||||
|
public function willProcessRequest(array $data) {
|
||||||
|
$this->id = $data['id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function processRequest() {
|
||||||
|
$request = $this->getRequest();
|
||||||
|
$user = $request->getUser();
|
||||||
|
|
||||||
|
$document = id(new LegalpadDocumentQuery())
|
||||||
|
->setViewer($user)
|
||||||
|
->withIDs(array($this->id))
|
||||||
|
->needDocumentBodies(true)
|
||||||
|
->executeOne();
|
||||||
|
|
||||||
|
if (!$document) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
$signature = id(new LegalpadDocumentSignature())
|
||||||
|
->loadOneWhere(
|
||||||
|
'documentPHID = %s AND documentVersion = %d AND signerPHID = %s',
|
||||||
|
$document->getPHID(),
|
||||||
|
$document->getVersions(),
|
||||||
|
$user->getPHID());
|
||||||
|
|
||||||
|
if (!$signature) {
|
||||||
|
$has_signed = false;
|
||||||
|
$error_view = null;
|
||||||
|
$signature = id(new LegalpadDocumentSignature())
|
||||||
|
->setSignerPHID($user->getPHID())
|
||||||
|
->setDocumentPHID($document->getPHID())
|
||||||
|
->setDocumentVersion($document->getVersions());
|
||||||
|
$data = array(
|
||||||
|
'name' => $user->getRealName(),
|
||||||
|
'email' => $user->loadPrimaryEmailAddress());
|
||||||
|
$signature->setSignatureData($data);
|
||||||
|
} else {
|
||||||
|
$has_signed = true;
|
||||||
|
$error_view = id(new AphrontErrorView())
|
||||||
|
->setSeverity(AphrontErrorView::SEVERITY_NOTICE)
|
||||||
|
->setTitle(pht('You have already agreed to these terms.'));
|
||||||
|
$data = $signature->getSignatureData();
|
||||||
|
}
|
||||||
|
|
||||||
|
$e_name = true;
|
||||||
|
$e_email = true;
|
||||||
|
$e_address_1 = true;
|
||||||
|
$errors = array();
|
||||||
|
if ($request->isFormPost()) {
|
||||||
|
$name = $request->getStr('name');
|
||||||
|
$email = $request->getStr('email');
|
||||||
|
$address_1 = $request->getStr('address_1');
|
||||||
|
$address_2 = $request->getStr('address_2');
|
||||||
|
$phone = $request->getStr('phone');
|
||||||
|
$agree = $request->getExists('agree');
|
||||||
|
|
||||||
|
if (!$name) {
|
||||||
|
$e_name = pht('Required');
|
||||||
|
$errors[] = pht('Name field is required.');
|
||||||
|
}
|
||||||
|
$data['name'] = $name;
|
||||||
|
|
||||||
|
if (!$email) {
|
||||||
|
$e_email = pht('Required');
|
||||||
|
$errors[] = pht('Email field is required.');
|
||||||
|
} else {
|
||||||
|
$addr_obj = new PhutilEmailAddress($email);
|
||||||
|
$domain = $addr_obj->getDomainName();
|
||||||
|
if (!$domain) {
|
||||||
|
$e_email = pht('Invalid');
|
||||||
|
$errors[] = pht('A valid email is required.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$data['email'] = $email;
|
||||||
|
|
||||||
|
if (!$address_1) {
|
||||||
|
$e_address_1 = pht('Required');
|
||||||
|
$errors[] = pht('Address line 1 field is required.');
|
||||||
|
}
|
||||||
|
$data['address_1'] = $address_1;
|
||||||
|
$data['address_2'] = $address_2;
|
||||||
|
$data['phone'] = $phone;
|
||||||
|
$signature->setSignatureData($data);
|
||||||
|
|
||||||
|
if (!$agree) {
|
||||||
|
$errors[] = pht(
|
||||||
|
'You must check "I agree to the terms laid forth above."');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$errors) {
|
||||||
|
$signature->save();
|
||||||
|
$has_signed = true;
|
||||||
|
$error_view = id(new AphrontErrorView())
|
||||||
|
->setSeverity(AphrontErrorView::SEVERITY_NOTICE)
|
||||||
|
->setTitle(pht('Signature successful. Thank you.'));
|
||||||
|
} else {
|
||||||
|
$error_view = id(new AphrontErrorView())
|
||||||
|
->setTitle(pht('Error in submission.'))
|
||||||
|
->setErrors($errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$document_body = $document->getDocumentBody();
|
||||||
|
$engine = id(new PhabricatorMarkupEngine())
|
||||||
|
->setViewer($user);
|
||||||
|
$engine->addObject(
|
||||||
|
$document_body,
|
||||||
|
LegalpadDocumentBody::MARKUP_FIELD_TEXT);
|
||||||
|
$engine->process();
|
||||||
|
|
||||||
|
$title = $document_body->getTitle();
|
||||||
|
|
||||||
|
$header = id(new PhabricatorHeaderView())
|
||||||
|
->setHeader($title);
|
||||||
|
|
||||||
|
$content = array(
|
||||||
|
id(new PHUIDocumentView())
|
||||||
|
->setHeader($header)
|
||||||
|
->appendChild($this->buildDocument($engine, $document_body)),
|
||||||
|
$error_view,
|
||||||
|
$this->buildSignatureForm(
|
||||||
|
$document_body,
|
||||||
|
$signature,
|
||||||
|
$has_signed,
|
||||||
|
$e_name,
|
||||||
|
$e_email,
|
||||||
|
$e_address_1));
|
||||||
|
|
||||||
|
return $this->buildApplicationPage(
|
||||||
|
$content,
|
||||||
|
array(
|
||||||
|
'title' => $title,
|
||||||
|
'device' => true,
|
||||||
|
'dust' => true,
|
||||||
|
'pageObjects' => array($document->getPHID()),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildDocument(
|
||||||
|
PhabricatorMarkupEngine
|
||||||
|
$engine, LegalpadDocumentBody $body) {
|
||||||
|
|
||||||
|
require_celerity_resource('legalpad-documentbody-css');
|
||||||
|
|
||||||
|
return phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => 'legalpad-documentbody'
|
||||||
|
),
|
||||||
|
$engine->getOutput($body, LegalpadDocumentBody::MARKUP_FIELD_TEXT));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildSignatureForm(
|
||||||
|
LegalpadDocumentBody $body,
|
||||||
|
LegalpadDocumentSignature $signature,
|
||||||
|
$has_signed = false,
|
||||||
|
$e_name = true,
|
||||||
|
$e_email = true,
|
||||||
|
$e_address_1 = true) {
|
||||||
|
|
||||||
|
$user = $this->getRequest()->getUser();
|
||||||
|
if ($has_signed) {
|
||||||
|
$instructions = pht('Thank you for signing and agreeing.');
|
||||||
|
} else {
|
||||||
|
$instructions = pht('Please enter the following information.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $signature->getSignatureData();
|
||||||
|
$form = id(new AphrontFormView())
|
||||||
|
->setUser($user)
|
||||||
|
->setFlexible(true)
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormInsetView())
|
||||||
|
->setTitle(pht('Sign and Agree'))
|
||||||
|
->setDescription($instructions)
|
||||||
|
->setContent(phutil_tag('br', array()))
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormTextControl())
|
||||||
|
->setLabel(pht('Name'))
|
||||||
|
->setValue(idx($data, 'name', ''))
|
||||||
|
->setName('name')
|
||||||
|
->setError($e_name)
|
||||||
|
->setDisabled($has_signed))
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormTextControl())
|
||||||
|
->setLabel(pht('Email'))
|
||||||
|
->setValue(idx($data, 'email', ''))
|
||||||
|
->setName('email')
|
||||||
|
->setError($e_email)
|
||||||
|
->setDisabled($has_signed))
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormTextControl())
|
||||||
|
->setLabel(pht('Address line 1'))
|
||||||
|
->setValue(idx($data, 'address_1', ''))
|
||||||
|
->setName('address_1')
|
||||||
|
->setError($e_address_1)
|
||||||
|
->setDisabled($has_signed))
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormTextControl())
|
||||||
|
->setLabel(pht('Address line 2'))
|
||||||
|
->setValue(idx($data, 'address_2', ''))
|
||||||
|
->setName('address_2')
|
||||||
|
->setDisabled($has_signed))
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormTextControl())
|
||||||
|
->setLabel(pht('Phone'))
|
||||||
|
->setValue(idx($data, 'phone', ''))
|
||||||
|
->setName('phone')
|
||||||
|
->setDisabled($has_signed))
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormCheckboxControl())
|
||||||
|
->addCheckbox(
|
||||||
|
'agree',
|
||||||
|
'agree',
|
||||||
|
pht('I agree to the terms laid forth above.'),
|
||||||
|
$has_signed)
|
||||||
|
->setDisabled($has_signed))
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormSubmitControl())
|
||||||
|
->setValue(pht('Sign and Agree'))
|
||||||
|
->setDisabled($has_signed)));
|
||||||
|
|
||||||
|
return $form;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -47,9 +47,6 @@ final class LegalpadDocumentViewController extends LegalpadController {
|
||||||
|
|
||||||
$engine = id(new PhabricatorMarkupEngine())
|
$engine = id(new PhabricatorMarkupEngine())
|
||||||
->setViewer($user);
|
->setViewer($user);
|
||||||
$engine->addObject(
|
|
||||||
$document_body,
|
|
||||||
LegalpadDocumentBody::MARKUP_FIELD_TITLE);
|
|
||||||
$engine->addObject(
|
$engine->addObject(
|
||||||
$document_body,
|
$document_body,
|
||||||
LegalpadDocumentBody::MARKUP_FIELD_TEXT);
|
LegalpadDocumentBody::MARKUP_FIELD_TEXT);
|
||||||
|
|
|
@ -169,7 +169,7 @@ final class LegalpadDocumentEditor
|
||||||
|
|
||||||
$body->addTextSection(
|
$body->addTextSection(
|
||||||
pht('DOCUMENT DETAIL'),
|
pht('DOCUMENT DETAIL'),
|
||||||
PhabricatorEnv::getProductionURI('/L'.$object->getID()));
|
PhabricatorEnv::getProductionURI('/legalpad/view/'.$object->getID().'/'));
|
||||||
|
|
||||||
return $body;
|
return $body;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ final class LegalpadDocumentBody extends LegalpadDAO
|
||||||
implements
|
implements
|
||||||
PhabricatorMarkupInterface {
|
PhabricatorMarkupInterface {
|
||||||
|
|
||||||
const MARKUP_FIELD_TITLE = 'markup:title';
|
|
||||||
const MARKUP_FIELD_TEXT = 'markup:text ';
|
const MARKUP_FIELD_TEXT = 'markup:text ';
|
||||||
|
|
||||||
protected $phid;
|
protected $phid;
|
||||||
|
|
|
@ -6,7 +6,18 @@
|
||||||
final class LegalpadDocumentSignature extends LegalpadDAO {
|
final class LegalpadDocumentSignature extends LegalpadDAO {
|
||||||
|
|
||||||
protected $documentPHID;
|
protected $documentPHID;
|
||||||
protected $documentversion;
|
protected $documentVersion;
|
||||||
protected $signerPHID;
|
protected $signerPHID;
|
||||||
|
protected $signatureData = array();
|
||||||
|
|
||||||
|
public function getConfiguration() {
|
||||||
|
return array(
|
||||||
|
self::CONFIG_SERIALIZATION => array(
|
||||||
|
'signatureData' => self::SERIALIZATION_JSON,
|
||||||
|
),
|
||||||
|
) + parent::getConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1430,6 +1430,10 @@ final class PhabricatorBuiltinPatchList extends PhabricatorSQLPatchList {
|
||||||
'type' => 'php',
|
'type' => 'php',
|
||||||
'name' => $this->getPatchPath('20130703.legalpaddocdenorm.php'),
|
'name' => $this->getPatchPath('20130703.legalpaddocdenorm.php'),
|
||||||
),
|
),
|
||||||
|
'20130709.legalpadsignature.sql' => array(
|
||||||
|
'type' => 'sql',
|
||||||
|
'name' => $this->getPatchPath('20130709.legalpadsignature.sql'),
|
||||||
|
),
|
||||||
'20130709.droptimeline.sql' => array(
|
'20130709.droptimeline.sql' => array(
|
||||||
'type' => 'sql',
|
'type' => 'sql',
|
||||||
'name' => $this->getPatchPath('20130709.droptimeline.sql'),
|
'name' => $this->getPatchPath('20130709.droptimeline.sql'),
|
||||||
|
|
Loading…
Reference in a new issue