2013-07-10 20:46:39 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
final class LegalpadDocumentSignController extends LegalpadController {
|
|
|
|
|
2014-07-09 17:01:34 +02:00
|
|
|
public function shouldAllowPublic() {
|
2014-08-08 18:53:49 +02:00
|
|
|
return true;
|
2014-01-15 02:17:18 +01:00
|
|
|
}
|
|
|
|
|
2015-03-02 16:39:16 +01:00
|
|
|
public function shouldAllowLegallyNonCompliantUsers() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-02-13 00:22:56 +01:00
|
|
|
public function handleRequest(AphrontRequest $request) {
|
2014-06-26 03:38:07 +02:00
|
|
|
$viewer = $request->getUser();
|
2013-07-10 20:46:39 +02:00
|
|
|
|
|
|
|
$document = id(new LegalpadDocumentQuery())
|
2014-06-26 03:38:07 +02:00
|
|
|
->setViewer($viewer)
|
2015-02-13 00:22:56 +01:00
|
|
|
->withIDs(array($request->getURIData('id')))
|
2013-07-10 20:46:39 +02:00
|
|
|
->needDocumentBodies(true)
|
|
|
|
->executeOne();
|
|
|
|
if (!$document) {
|
|
|
|
return new Aphront404Response();
|
|
|
|
}
|
|
|
|
|
2015-04-24 23:26:00 +02:00
|
|
|
$information = $this->readSignerInformation(
|
2014-07-04 17:04:28 +02:00
|
|
|
$document,
|
|
|
|
$request);
|
2015-04-24 23:26:00 +02:00
|
|
|
if ($information instanceof AphrontResponse) {
|
|
|
|
return $information;
|
|
|
|
}
|
|
|
|
list($signer_phid, $signature_data) = $information;
|
2014-07-04 17:04:28 +02:00
|
|
|
|
|
|
|
$signature = null;
|
|
|
|
|
|
|
|
$type_individual = LegalpadDocument::SIGNATURE_TYPE_INDIVIDUAL;
|
|
|
|
$is_individual = ($document->getSignatureType() == $type_individual);
|
2015-02-17 20:45:20 +01:00
|
|
|
switch ($document->getSignatureType()) {
|
|
|
|
case LegalpadDocument::SIGNATURE_TYPE_NONE:
|
|
|
|
// nothing to sign means this should be true
|
|
|
|
$has_signed = true;
|
|
|
|
// this is a status UI element
|
|
|
|
$signed_status = null;
|
|
|
|
break;
|
|
|
|
case LegalpadDocument::SIGNATURE_TYPE_INDIVIDUAL:
|
|
|
|
if ($signer_phid) {
|
|
|
|
// TODO: This is odd and should probably be adjusted after
|
|
|
|
// grey/external accounts work better, but use the omnipotent
|
|
|
|
// viewer to check for a signature so we can pick up
|
|
|
|
// anonymous/grey signatures.
|
|
|
|
|
|
|
|
$signature = id(new LegalpadDocumentSignatureQuery())
|
|
|
|
->setViewer(PhabricatorUser::getOmnipotentUser())
|
|
|
|
->withDocumentPHIDs(array($document->getPHID()))
|
|
|
|
->withSignerPHIDs(array($signer_phid))
|
|
|
|
->executeOne();
|
|
|
|
|
|
|
|
if ($signature && !$viewer->isLoggedIn()) {
|
2014-07-04 17:04:28 +02:00
|
|
|
return $this->newDialog()
|
|
|
|
->setTitle(pht('Already Signed'))
|
|
|
|
->appendParagraph(pht('You have already signed this document!'))
|
|
|
|
->addCancelButton('/'.$document->getMonogram(), pht('Okay'));
|
2015-02-17 20:45:20 +01:00
|
|
|
}
|
2014-06-26 16:16:42 +02:00
|
|
|
}
|
2014-01-15 02:17:18 +01:00
|
|
|
|
2015-02-17 20:45:20 +01:00
|
|
|
$signed_status = null;
|
|
|
|
if (!$signature) {
|
|
|
|
$has_signed = false;
|
|
|
|
$signature = id(new LegalpadDocumentSignature())
|
|
|
|
->setSignerPHID($signer_phid)
|
|
|
|
->setDocumentPHID($document->getPHID())
|
|
|
|
->setDocumentVersion($document->getVersions());
|
|
|
|
|
|
|
|
// If the user is logged in, show a notice that they haven't signed.
|
|
|
|
// If they aren't logged in, we can't be as sure, so don't show
|
|
|
|
// anything.
|
|
|
|
if ($viewer->isLoggedIn()) {
|
2015-03-01 23:45:56 +01:00
|
|
|
$signed_status = id(new PHUIInfoView())
|
|
|
|
->setSeverity(PHUIInfoView::SEVERITY_WARNING)
|
2015-02-17 20:45:20 +01:00
|
|
|
->setErrors(
|
|
|
|
array(
|
|
|
|
pht('You have not signed this document yet.'),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$has_signed = true;
|
|
|
|
$signature_data = $signature->getSignatureData();
|
|
|
|
|
|
|
|
// 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));
|
|
|
|
}
|
2014-07-04 17:04:28 +02:00
|
|
|
|
2015-03-01 23:45:56 +01:00
|
|
|
$signed_status = id(new PHUIInfoView())
|
|
|
|
->setSeverity(PHUIInfoView::SEVERITY_NOTICE)
|
2015-02-17 20:45:20 +01:00
|
|
|
->setErrors(array($signed_text));
|
2014-07-04 17:04:28 +02:00
|
|
|
}
|
|
|
|
|
2015-02-17 20:45:20 +01:00
|
|
|
$field_errors = array(
|
|
|
|
'name' => true,
|
|
|
|
'email' => true,
|
|
|
|
'agree' => true,
|
|
|
|
);
|
|
|
|
$signature->setSignatureData($signature_data);
|
|
|
|
break;
|
2013-07-10 20:46:39 +02:00
|
|
|
|
2015-02-17 20:45:20 +01:00
|
|
|
case LegalpadDocument::SIGNATURE_TYPE_CORPORATION:
|
|
|
|
$signature = id(new LegalpadDocumentSignature())
|
|
|
|
->setDocumentPHID($document->getPHID())
|
|
|
|
->setDocumentVersion($document->getVersions());
|
2014-06-26 16:16:42 +02:00
|
|
|
|
2015-02-17 20:45:20 +01:00
|
|
|
if ($viewer->isLoggedIn()) {
|
|
|
|
$has_signed = false;
|
2014-07-04 17:04:28 +02:00
|
|
|
|
2015-02-17 20:45:20 +01:00
|
|
|
$signed_status = null;
|
|
|
|
} else {
|
|
|
|
// This just hides the form.
|
|
|
|
$has_signed = true;
|
2014-07-04 17:04:28 +02:00
|
|
|
|
2015-02-17 20:45:20 +01:00
|
|
|
$login_text = pht(
|
|
|
|
'This document requires a corporate signatory. You must log in to '.
|
|
|
|
'accept this document on behalf of a company you represent.');
|
2015-03-01 23:45:56 +01:00
|
|
|
$signed_status = id(new PHUIInfoView())
|
|
|
|
->setSeverity(PHUIInfoView::SEVERITY_WARNING)
|
2015-02-17 20:45:20 +01:00
|
|
|
->setErrors(array($login_text));
|
|
|
|
}
|
2014-07-02 13:59:35 +02:00
|
|
|
|
2015-02-17 20:45:20 +01:00
|
|
|
$field_errors = array(
|
|
|
|
'name' => true,
|
|
|
|
'address' => true,
|
|
|
|
'contact.name' => true,
|
|
|
|
'email' => true,
|
|
|
|
);
|
|
|
|
$signature->setSignatureData($signature_data);
|
|
|
|
break;
|
2013-07-10 20:46:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
$errors = array();
|
2014-06-29 15:16:48 +02:00
|
|
|
if ($request->isFormOrHisecPost() && !$has_signed) {
|
|
|
|
|
|
|
|
// Require two-factor auth to sign legal documents.
|
2014-06-29 16:51:03 +02:00
|
|
|
if ($viewer->isLoggedIn()) {
|
|
|
|
$engine = new PhabricatorAuthSessionEngine();
|
|
|
|
$engine->requireHighSecuritySession(
|
|
|
|
$viewer,
|
|
|
|
$request,
|
|
|
|
'/'.$document->getMonogram());
|
|
|
|
}
|
2014-06-29 15:16:48 +02:00
|
|
|
|
2014-07-04 17:04:28 +02:00
|
|
|
list($form_data, $errors, $field_errors) = $this->readSignatureForm(
|
|
|
|
$document,
|
|
|
|
$request);
|
2014-06-26 16:16:42 +02:00
|
|
|
|
2014-07-04 17:04:28 +02:00
|
|
|
$signature_data = $form_data + $signature_data;
|
2013-07-10 20:46:39 +02:00
|
|
|
|
2014-07-04 17:04:28 +02:00
|
|
|
$signature->setSignatureData($signature_data);
|
|
|
|
$signature->setSignatureType($document->getSignatureType());
|
2014-06-29 16:51:03 +02:00
|
|
|
$signature->setSignerName((string)idx($signature_data, 'name'));
|
|
|
|
$signature->setSignerEmail((string)idx($signature_data, 'email'));
|
2013-07-10 20:46:39 +02:00
|
|
|
|
2014-07-04 17:04:28 +02:00
|
|
|
$agree = $request->getExists('agree');
|
2013-07-10 20:46:39 +02:00
|
|
|
if (!$agree) {
|
|
|
|
$errors[] = pht(
|
|
|
|
'You must check "I agree to the terms laid forth above."');
|
2014-07-04 17:04:28 +02:00
|
|
|
$field_errors['agree'] = pht('Required');
|
2013-07-10 20:46:39 +02:00
|
|
|
}
|
|
|
|
|
2014-07-04 17:04:28 +02:00
|
|
|
if ($viewer->isLoggedIn() && $is_individual) {
|
2014-06-26 16:16:42 +02:00
|
|
|
$verified = LegalpadDocumentSignature::VERIFIED;
|
|
|
|
} else {
|
|
|
|
$verified = LegalpadDocumentSignature::UNVERIFIED;
|
2014-01-15 02:17:18 +01:00
|
|
|
}
|
|
|
|
$signature->setVerified($verified);
|
|
|
|
|
2013-07-10 20:46:39 +02:00
|
|
|
if (!$errors) {
|
|
|
|
$signature->save();
|
2014-06-26 16:16:42 +02:00
|
|
|
|
2015-02-18 22:19:07 +01:00
|
|
|
// If the viewer is logged in, signing for themselves, send them to
|
|
|
|
// the document page, which will show that they have signed the
|
|
|
|
// document. Unless of course they were required to sign the
|
|
|
|
// document to use Phabricator; in that case try really hard to
|
|
|
|
// re-direct them to where they wanted to go.
|
|
|
|
//
|
|
|
|
// Otherwise, send them to a completion page.
|
2014-07-04 17:04:28 +02:00
|
|
|
if ($viewer->isLoggedIn() && $is_individual) {
|
2014-06-26 16:16:42 +02:00
|
|
|
$next_uri = '/'.$document->getMonogram();
|
2015-02-18 22:19:07 +01:00
|
|
|
if ($document->getRequireSignature()) {
|
|
|
|
$request_uri = $request->getRequestURI();
|
|
|
|
$next_uri = (string) $request_uri;
|
|
|
|
}
|
2014-01-15 02:17:18 +01:00
|
|
|
} else {
|
2014-07-04 17:04:28 +02:00
|
|
|
$this->sendVerifySignatureEmail(
|
|
|
|
$document,
|
|
|
|
$signature);
|
|
|
|
|
2014-06-26 16:16:42 +02:00
|
|
|
$next_uri = $this->getApplicationURI('done/');
|
2014-01-15 02:17:18 +01:00
|
|
|
}
|
2014-06-26 16:16:42 +02:00
|
|
|
|
|
|
|
return id(new AphrontRedirectResponse())->setURI($next_uri);
|
2013-07-10 20:46:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$document_body = $document->getDocumentBody();
|
|
|
|
$engine = id(new PhabricatorMarkupEngine())
|
2014-06-26 03:38:07 +02:00
|
|
|
->setViewer($viewer);
|
2013-07-10 20:46:39 +02:00
|
|
|
$engine->addObject(
|
|
|
|
$document_body,
|
|
|
|
LegalpadDocumentBody::MARKUP_FIELD_TEXT);
|
|
|
|
$engine->process();
|
|
|
|
|
2014-06-26 16:16:42 +02:00
|
|
|
$document_markup = $engine->getOutput(
|
|
|
|
$document_body,
|
|
|
|
LegalpadDocumentBody::MARKUP_FIELD_TEXT);
|
|
|
|
|
2013-07-10 20:46:39 +02:00
|
|
|
$title = $document_body->getTitle();
|
|
|
|
|
2014-06-26 03:38:07 +02:00
|
|
|
$manage_uri = $this->getApplicationURI('view/'.$document->getID().'/');
|
|
|
|
|
|
|
|
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
|
|
|
$viewer,
|
|
|
|
$document,
|
|
|
|
PhabricatorPolicyCapability::CAN_EDIT);
|
|
|
|
|
2013-09-17 18:12:37 +02:00
|
|
|
$header = id(new PHUIHeaderView())
|
2014-06-26 03:38:07 +02:00
|
|
|
->setHeader($title)
|
Add setEpoch for PHUIHeaderView, use in all Documents
Summary: Sets a consistent last update time in the header of PHUIDocuments, Legalpad, Diviner, Phriction. I'm not set on the exact language, just that there is consistency, feel free to suggest changes.
Test Plan:
Test Legalpad, Diviner, Phriction.
{F368270}
Reviewers: btrahan, epriestley
Reviewed By: epriestley
Subscribers: Korvin, epriestley
Differential Revision: https://secure.phabricator.com/D12384
2015-04-13 03:08:09 +02:00
|
|
|
->setUser($viewer)
|
|
|
|
->setPolicyObject($document)
|
|
|
|
->setEpoch($document->getDateModified())
|
2014-06-26 03:38:07 +02:00
|
|
|
->addActionLink(
|
|
|
|
id(new PHUIButtonView())
|
|
|
|
->setTag('a')
|
|
|
|
->setIcon(
|
|
|
|
id(new PHUIIconView())
|
|
|
|
->setIconFont('fa-pencil'))
|
|
|
|
->setText(pht('Manage Document'))
|
|
|
|
->setHref($manage_uri)
|
|
|
|
->setDisabled(!$can_edit)
|
|
|
|
->setWorkflow(!$can_edit));
|
2013-07-10 20:46:39 +02:00
|
|
|
|
2014-07-04 18:41:27 +02:00
|
|
|
$preamble = null;
|
|
|
|
if (strlen($document->getPreamble())) {
|
|
|
|
$preamble_text = PhabricatorMarkupEngine::renderOneObject(
|
|
|
|
id(new PhabricatorMarkupOneOff())->setContent(
|
|
|
|
$document->getPreamble()),
|
|
|
|
'default',
|
|
|
|
$viewer);
|
|
|
|
|
|
|
|
$preamble = id(new PHUIPropertyListView())
|
|
|
|
->addSectionHeader(pht('Preamble'))
|
|
|
|
->addTextContent($preamble_text);
|
|
|
|
}
|
|
|
|
|
2014-06-26 16:16:42 +02:00
|
|
|
$content = id(new PHUIDocumentView())
|
|
|
|
->addClass('legalpad')
|
|
|
|
->setHeader($header)
|
2014-06-27 16:20:14 +02:00
|
|
|
->setFontKit(PHUIDocumentView::FONT_SOURCE_SANS)
|
2014-06-26 16:16:42 +02:00
|
|
|
->appendChild(
|
|
|
|
array(
|
|
|
|
$signed_status,
|
2014-07-04 18:41:27 +02:00
|
|
|
$preamble,
|
2014-06-26 16:16:42 +02:00
|
|
|
$document_markup,
|
|
|
|
));
|
|
|
|
|
|
|
|
if (!$has_signed) {
|
|
|
|
$error_view = null;
|
|
|
|
if ($errors) {
|
2015-03-01 23:45:56 +01:00
|
|
|
$error_view = id(new PHUIInfoView())
|
2014-06-26 16:16:42 +02:00
|
|
|
->setErrors($errors);
|
|
|
|
}
|
|
|
|
|
|
|
|
$signature_form = $this->buildSignatureForm(
|
2014-07-04 17:04:28 +02:00
|
|
|
$document,
|
2014-06-26 16:16:42 +02:00
|
|
|
$signature,
|
2014-07-04 17:04:28 +02:00
|
|
|
$field_errors);
|
2014-06-26 16:16:42 +02:00
|
|
|
|
2015-02-17 20:45:20 +01:00
|
|
|
switch ($document->getSignatureType()) {
|
|
|
|
case LegalpadDocument::SIGNATURE_TYPE_NONE:
|
|
|
|
$subheader = null;
|
|
|
|
break;
|
|
|
|
case LegalpadDocument::SIGNATURE_TYPE_INDIVIDUAL:
|
|
|
|
case LegalpadDocument::SIGNATURE_TYPE_CORPORATION:
|
|
|
|
$subheader = id(new PHUIHeaderView())
|
|
|
|
->setHeader(pht('Agree and Sign Document'))
|
|
|
|
->setBleedHeader(true);
|
|
|
|
break;
|
|
|
|
}
|
2014-06-27 16:20:14 +02:00
|
|
|
|
2014-06-26 16:16:42 +02:00
|
|
|
$content->appendChild(
|
|
|
|
array(
|
2014-06-27 16:20:14 +02:00
|
|
|
$subheader,
|
2014-06-26 16:16:42 +02:00
|
|
|
$error_view,
|
|
|
|
$signature_form,
|
|
|
|
));
|
|
|
|
}
|
2013-07-10 20:46:39 +02:00
|
|
|
|
2014-06-26 03:38:07 +02:00
|
|
|
$crumbs = $this->buildApplicationCrumbs();
|
2015-01-28 18:33:49 +01:00
|
|
|
$crumbs->setBorder(true);
|
2014-06-26 03:38:07 +02:00
|
|
|
$crumbs->addTextCrumb($document->getMonogram());
|
|
|
|
|
2013-07-10 20:46:39 +02:00
|
|
|
return $this->buildApplicationPage(
|
2014-06-26 03:38:07 +02:00
|
|
|
array(
|
|
|
|
$crumbs,
|
|
|
|
$content,
|
|
|
|
),
|
2013-07-10 20:46:39 +02:00
|
|
|
array(
|
|
|
|
'title' => $title,
|
|
|
|
'pageObjects' => array($document->getPHID()),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2014-07-04 17:04:28 +02:00
|
|
|
private function readSignerInformation(
|
|
|
|
LegalpadDocument $document,
|
|
|
|
AphrontRequest $request) {
|
|
|
|
|
|
|
|
$viewer = $request->getUser();
|
|
|
|
$signer_phid = null;
|
|
|
|
$signature_data = array();
|
|
|
|
|
|
|
|
switch ($document->getSignatureType()) {
|
2015-02-17 20:45:20 +01:00
|
|
|
case LegalpadDocument::SIGNATURE_TYPE_NONE:
|
|
|
|
break;
|
2014-07-04 17:04:28 +02:00
|
|
|
case LegalpadDocument::SIGNATURE_TYPE_INDIVIDUAL:
|
|
|
|
if ($viewer->isLoggedIn()) {
|
|
|
|
$signer_phid = $viewer->getPHID();
|
|
|
|
$signature_data = array(
|
|
|
|
'name' => $viewer->getRealName(),
|
|
|
|
'email' => $viewer->loadPrimaryEmailAddress(),
|
|
|
|
);
|
|
|
|
} else if ($request->isFormPost()) {
|
|
|
|
$email = new PhutilEmailAddress($request->getStr('email'));
|
|
|
|
if (strlen($email->getDomainName())) {
|
|
|
|
$email_obj = id(new PhabricatorUserEmail())
|
|
|
|
->loadOneWhere('address = %s', $email->getAddress());
|
|
|
|
if ($email_obj) {
|
|
|
|
return $this->signInResponse();
|
|
|
|
}
|
|
|
|
$external_account = id(new PhabricatorExternalAccountQuery())
|
|
|
|
->setViewer($viewer)
|
|
|
|
->withAccountTypes(array('email'))
|
|
|
|
->withAccountDomains(array($email->getDomainName()))
|
|
|
|
->withAccountIDs(array($email->getAddress()))
|
|
|
|
->loadOneOrCreate();
|
|
|
|
if ($external_account->getUserPHID()) {
|
|
|
|
return $this->signInResponse();
|
|
|
|
}
|
|
|
|
$signer_phid = $external_account->getPHID();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LegalpadDocument::SIGNATURE_TYPE_CORPORATION:
|
|
|
|
$signer_phid = $viewer->getPHID();
|
|
|
|
if ($signer_phid) {
|
|
|
|
$signature_data = array(
|
|
|
|
'contact.name' => $viewer->getRealName(),
|
|
|
|
'email' => $viewer->loadPrimaryEmailAddress(),
|
|
|
|
'actorPHID' => $viewer->getPHID(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return array($signer_phid, $signature_data);
|
|
|
|
}
|
|
|
|
|
2013-07-10 20:46:39 +02:00
|
|
|
private function buildSignatureForm(
|
2014-07-04 17:04:28 +02:00
|
|
|
LegalpadDocument $document,
|
2013-07-10 20:46:39 +02:00
|
|
|
LegalpadDocumentSignature $signature,
|
2014-07-04 17:04:28 +02:00
|
|
|
array $errors) {
|
2013-07-10 20:46:39 +02:00
|
|
|
|
2014-06-26 03:38:07 +02:00
|
|
|
$viewer = $this->getRequest()->getUser();
|
2013-07-10 20:46:39 +02:00
|
|
|
$data = $signature->getSignatureData();
|
2014-06-26 16:16:42 +02:00
|
|
|
|
2013-07-10 20:46:39 +02:00
|
|
|
$form = id(new AphrontFormView())
|
2014-07-04 17:04:28 +02:00
|
|
|
->setUser($viewer);
|
|
|
|
|
|
|
|
$signature_type = $document->getSignatureType();
|
|
|
|
switch ($signature_type) {
|
2015-02-17 20:45:20 +01:00
|
|
|
case LegalpadDocument::SIGNATURE_TYPE_NONE:
|
|
|
|
// bail out of here quick
|
|
|
|
return;
|
2014-07-04 17:04:28 +02:00
|
|
|
case LegalpadDocument::SIGNATURE_TYPE_INDIVIDUAL:
|
|
|
|
$this->buildIndividualSignatureForm(
|
|
|
|
$form,
|
|
|
|
$document,
|
|
|
|
$signature,
|
|
|
|
$errors);
|
|
|
|
break;
|
|
|
|
case LegalpadDocument::SIGNATURE_TYPE_CORPORATION:
|
|
|
|
$this->buildCorporateSignatureForm(
|
|
|
|
$form,
|
|
|
|
$document,
|
|
|
|
$signature,
|
|
|
|
$errors);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw new Exception(
|
|
|
|
pht(
|
|
|
|
'This document has an unknown signature type ("%s").',
|
|
|
|
$signature_type));
|
|
|
|
}
|
|
|
|
|
|
|
|
$form
|
|
|
|
->appendChild(
|
|
|
|
id(new AphrontFormCheckboxControl())
|
|
|
|
->setError(idx($errors, 'agree', null))
|
|
|
|
->addCheckbox(
|
|
|
|
'agree',
|
|
|
|
'agree',
|
|
|
|
pht('I agree to the terms laid forth above.'),
|
2015-02-18 22:19:07 +01:00
|
|
|
false));
|
|
|
|
if ($document->getRequireSignature()) {
|
|
|
|
$cancel_uri = '/logout/';
|
|
|
|
$cancel_text = pht('Log Out');
|
|
|
|
} else {
|
|
|
|
$cancel_uri = $this->getApplicationURI();
|
|
|
|
$cancel_text = pht('Cancel');
|
|
|
|
}
|
|
|
|
$form
|
2014-07-04 17:04:28 +02:00
|
|
|
->appendChild(
|
|
|
|
id(new AphrontFormSubmitControl())
|
|
|
|
->setValue(pht('Sign Document'))
|
2015-02-18 22:19:07 +01:00
|
|
|
->addCancelButton($cancel_uri, $cancel_text));
|
2014-07-04 17:04:28 +02:00
|
|
|
|
|
|
|
return $form;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildIndividualSignatureForm(
|
|
|
|
AphrontFormView $form,
|
|
|
|
LegalpadDocument $document,
|
|
|
|
LegalpadDocumentSignature $signature,
|
|
|
|
array $errors) {
|
|
|
|
|
|
|
|
$data = $signature->getSignatureData();
|
|
|
|
|
|
|
|
$form
|
2013-07-10 20:46:39 +02:00
|
|
|
->appendChild(
|
2013-10-30 23:50:46 +01:00
|
|
|
id(new AphrontFormTextControl())
|
|
|
|
->setLabel(pht('Name'))
|
|
|
|
->setValue(idx($data, 'name', ''))
|
|
|
|
->setName('name')
|
2014-07-04 17:04:28 +02:00
|
|
|
->setError(idx($errors, 'name', null)));
|
2014-06-26 16:16:42 +02:00
|
|
|
|
2014-07-04 17:04:28 +02:00
|
|
|
$viewer = $this->getRequest()->getUser();
|
2014-06-26 16:16:42 +02:00
|
|
|
if (!$viewer->isLoggedIn()) {
|
|
|
|
$form->appendChild(
|
2013-10-30 23:50:46 +01:00
|
|
|
id(new AphrontFormTextControl())
|
2014-06-26 16:16:42 +02:00
|
|
|
->setLabel(pht('Email'))
|
|
|
|
->setValue(idx($data, 'email', ''))
|
|
|
|
->setName('email')
|
2014-07-04 17:04:28 +02:00
|
|
|
->setError(idx($errors, 'email', null)));
|
2014-06-26 16:16:42 +02:00
|
|
|
}
|
|
|
|
|
2014-07-04 17:04:28 +02:00
|
|
|
return $form;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildCorporateSignatureForm(
|
|
|
|
AphrontFormView $form,
|
|
|
|
LegalpadDocument $document,
|
|
|
|
LegalpadDocumentSignature $signature,
|
|
|
|
array $errors) {
|
|
|
|
|
|
|
|
$data = $signature->getSignatureData();
|
|
|
|
|
2014-06-26 16:16:42 +02:00
|
|
|
$form
|
2013-10-30 23:50:46 +01:00
|
|
|
->appendChild(
|
2014-07-04 17:04:28 +02:00
|
|
|
id(new AphrontFormTextControl())
|
|
|
|
->setLabel(pht('Company Name'))
|
|
|
|
->setValue(idx($data, 'name', ''))
|
|
|
|
->setName('name')
|
|
|
|
->setError(idx($errors, 'name', null)))
|
2013-10-30 23:50:46 +01:00
|
|
|
->appendChild(
|
2014-07-04 17:04:28 +02:00
|
|
|
id(new AphrontFormTextAreaControl())
|
|
|
|
->setLabel(pht('Company Address'))
|
|
|
|
->setValue(idx($data, 'address', ''))
|
|
|
|
->setName('address')
|
|
|
|
->setError(idx($errors, 'address', null)))
|
|
|
|
->appendChild(
|
|
|
|
id(new AphrontFormTextControl())
|
|
|
|
->setLabel(pht('Contact Name'))
|
|
|
|
->setValue(idx($data, 'contact.name', ''))
|
|
|
|
->setName('contact.name')
|
|
|
|
->setError(idx($errors, 'contact.name', null)))
|
|
|
|
->appendChild(
|
|
|
|
id(new AphrontFormTextControl())
|
|
|
|
->setLabel(pht('Contact Email'))
|
|
|
|
->setValue(idx($data, 'email', ''))
|
|
|
|
->setName('email')
|
|
|
|
->setError(idx($errors, 'email', null)));
|
2014-06-26 03:38:07 +02:00
|
|
|
|
2014-06-26 07:02:40 +02:00
|
|
|
return $form;
|
2014-01-15 02:17:18 +01:00
|
|
|
}
|
|
|
|
|
2014-07-04 17:04:28 +02:00
|
|
|
private function readSignatureForm(
|
|
|
|
LegalpadDocument $document,
|
|
|
|
AphrontRequest $request) {
|
|
|
|
|
|
|
|
$signature_type = $document->getSignatureType();
|
|
|
|
switch ($signature_type) {
|
|
|
|
case LegalpadDocument::SIGNATURE_TYPE_INDIVIDUAL:
|
|
|
|
$result = $this->readIndividualSignatureForm(
|
|
|
|
$document,
|
|
|
|
$request);
|
|
|
|
break;
|
|
|
|
case LegalpadDocument::SIGNATURE_TYPE_CORPORATION:
|
|
|
|
$result = $this->readCorporateSignatureForm(
|
|
|
|
$document,
|
|
|
|
$request);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw new Exception(
|
|
|
|
pht(
|
|
|
|
'This document has an unknown signature type ("%s").',
|
|
|
|
$signature_type));
|
|
|
|
}
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function readIndividualSignatureForm(
|
|
|
|
LegalpadDocument $document,
|
|
|
|
AphrontRequest $request) {
|
|
|
|
|
|
|
|
$signature_data = array();
|
|
|
|
$errors = array();
|
|
|
|
$field_errors = array();
|
|
|
|
|
|
|
|
|
|
|
|
$name = $request->getStr('name');
|
|
|
|
|
|
|
|
if (!strlen($name)) {
|
|
|
|
$field_errors['name'] = pht('Required');
|
|
|
|
$errors[] = pht('Name field is required.');
|
|
|
|
} else {
|
|
|
|
$field_errors['name'] = null;
|
|
|
|
}
|
|
|
|
$signature_data['name'] = $name;
|
|
|
|
|
|
|
|
$viewer = $request->getUser();
|
|
|
|
if ($viewer->isLoggedIn()) {
|
|
|
|
$email = $viewer->loadPrimaryEmailAddress();
|
|
|
|
} else {
|
|
|
|
$email = $request->getStr('email');
|
|
|
|
|
|
|
|
$addr_obj = null;
|
|
|
|
if (!strlen($email)) {
|
|
|
|
$field_errors['email'] = pht('Required');
|
|
|
|
$errors[] = pht('Email field is required.');
|
|
|
|
} else {
|
|
|
|
$addr_obj = new PhutilEmailAddress($email);
|
|
|
|
$domain = $addr_obj->getDomainName();
|
|
|
|
if (!$domain) {
|
|
|
|
$field_errors['email'] = pht('Invalid');
|
|
|
|
$errors[] = pht('A valid email is required.');
|
|
|
|
} else {
|
|
|
|
$field_errors['email'] = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$signature_data['email'] = $email;
|
|
|
|
|
|
|
|
return array($signature_data, $errors, $field_errors);
|
|
|
|
}
|
|
|
|
|
|
|
|
private function readCorporateSignatureForm(
|
|
|
|
LegalpadDocument $document,
|
|
|
|
AphrontRequest $request) {
|
|
|
|
|
|
|
|
$viewer = $request->getUser();
|
|
|
|
if (!$viewer->isLoggedIn()) {
|
|
|
|
throw new Exception(
|
|
|
|
pht(
|
|
|
|
'You can not sign a document on behalf of a corporation unless '.
|
|
|
|
'you are logged in.'));
|
|
|
|
}
|
|
|
|
|
|
|
|
$signature_data = array();
|
|
|
|
$errors = array();
|
|
|
|
$field_errors = array();
|
|
|
|
|
|
|
|
$name = $request->getStr('name');
|
|
|
|
|
|
|
|
if (!strlen($name)) {
|
|
|
|
$field_errors['name'] = pht('Required');
|
|
|
|
$errors[] = pht('Company name is required.');
|
|
|
|
} else {
|
|
|
|
$field_errors['name'] = null;
|
|
|
|
}
|
|
|
|
$signature_data['name'] = $name;
|
|
|
|
|
|
|
|
$address = $request->getStr('address');
|
|
|
|
if (!strlen($address)) {
|
|
|
|
$field_errors['address'] = pht('Required');
|
|
|
|
$errors[] = pht('Company address is required.');
|
|
|
|
} else {
|
|
|
|
$field_errors['address'] = null;
|
|
|
|
}
|
|
|
|
$signature_data['address'] = $address;
|
|
|
|
|
|
|
|
$contact_name = $request->getStr('contact.name');
|
|
|
|
if (!strlen($contact_name)) {
|
|
|
|
$field_errors['contact.name'] = pht('Required');
|
|
|
|
$errors[] = pht('Contact name is required.');
|
|
|
|
} else {
|
|
|
|
$field_errors['contact.name'] = null;
|
|
|
|
}
|
|
|
|
$signature_data['contact.name'] = $contact_name;
|
|
|
|
|
|
|
|
$email = $request->getStr('email');
|
|
|
|
$addr_obj = null;
|
|
|
|
if (!strlen($email)) {
|
|
|
|
$field_errors['email'] = pht('Required');
|
|
|
|
$errors[] = pht('Contact email is required.');
|
|
|
|
} else {
|
|
|
|
$addr_obj = new PhutilEmailAddress($email);
|
|
|
|
$domain = $addr_obj->getDomainName();
|
|
|
|
if (!$domain) {
|
|
|
|
$field_errors['email'] = pht('Invalid');
|
|
|
|
$errors[] = pht('A valid email is required.');
|
|
|
|
} else {
|
|
|
|
$field_errors['email'] = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$signature_data['email'] = $email;
|
|
|
|
|
|
|
|
return array($signature_data, $errors, $field_errors);
|
|
|
|
}
|
|
|
|
|
2014-01-15 02:17:18 +01:00
|
|
|
private function sendVerifySignatureEmail(
|
|
|
|
LegalpadDocument $doc,
|
|
|
|
LegalpadDocumentSignature $signature) {
|
|
|
|
|
|
|
|
$signature_data = $signature->getSignatureData();
|
|
|
|
$email = new PhutilEmailAddress($signature_data['email']);
|
2014-07-04 17:04:28 +02:00
|
|
|
$doc_name = $doc->getTitle();
|
|
|
|
$doc_link = PhabricatorEnv::getProductionURI('/'.$doc->getMonogram());
|
2014-01-15 02:17:18 +01:00
|
|
|
$path = $this->getApplicationURI(sprintf(
|
|
|
|
'/verify/%s/',
|
|
|
|
$signature->getSecretKey()));
|
|
|
|
$link = PhabricatorEnv::getProductionURI($path);
|
|
|
|
|
2014-07-04 17:04:28 +02:00
|
|
|
$name = idx($signature_data, 'name');
|
|
|
|
|
2014-01-15 02:17:18 +01:00
|
|
|
$body = <<<EOBODY
|
2014-07-04 17:04:28 +02:00
|
|
|
{$name}:
|
2014-01-15 02:17:18 +01:00
|
|
|
|
2014-07-04 17:04:28 +02:00
|
|
|
This email address was used to sign a Legalpad document in Phabricator:
|
|
|
|
|
|
|
|
{$doc_name}
|
|
|
|
|
|
|
|
Please verify you own this email address and accept the agreement by clicking
|
|
|
|
this link:
|
2014-01-15 02:17:18 +01:00
|
|
|
|
|
|
|
{$link}
|
|
|
|
|
2014-07-04 17:04:28 +02:00
|
|
|
Your signature is not valid until you complete this verification step.
|
|
|
|
|
|
|
|
You can review the document here:
|
|
|
|
|
|
|
|
{$doc_link}
|
|
|
|
|
2014-01-15 02:17:18 +01:00
|
|
|
EOBODY;
|
|
|
|
|
|
|
|
id(new PhabricatorMetaMTAMail())
|
|
|
|
->addRawTos(array($email->getAddress()))
|
|
|
|
->setSubject(pht('[Legalpad] Signature Verification'))
|
2014-08-12 21:28:29 +02:00
|
|
|
->setForceDelivery(true)
|
2014-01-15 02:17:18 +01:00
|
|
|
->setBody($body)
|
|
|
|
->setRelatedPHID($signature->getDocumentPHID())
|
|
|
|
->saveAndSend();
|
|
|
|
}
|
|
|
|
|
|
|
|
private function signInResponse() {
|
|
|
|
return id(new Aphront403Response())
|
|
|
|
->setForbiddenText(pht(
|
|
|
|
'The email address specified is associated with an account. '.
|
|
|
|
'Please login to that account and sign this document again.'));
|
2013-07-10 20:46:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|