· 6 years ago · Oct 15, 2019, 08:36 PM
1<?php
2namespace Simcify;
3
4require_once 'TCPDF/tcpdf.php';
5require_once 'TCPDF/tcpdi.php';
6use TCPDF;
7use TCPDI;
8use Simcify\Str;
9use Simcify\File;
10use Simcify\Auth;
11use Simcify\Database;
12use \CloudConvert\Api;
13
14class PDF extends TCPDI {
15 var $_tplIdx;
16 var $numPages;
17
18 function Header() {}
19
20 function Footer() {}
21
22}
23
24class Signer {
25
26 /**
27 * Upload file
28 *
29 * @param array $data
30 * @return true
31 */
32 public static function upload($data) {
33 $user = Auth::user();
34 // get usage data
35 if ($user->role == "user") {
36 $fileUsage = Database::table("files")->where("uploaded_by" , $user->id)->count("id", "files")[0]->files;
37 $diskUsage = Database::table("files")->where("uploaded_by" , $user->id)->sum("id", "size")[0]->size / 1000;
38 // check file usage limits
39 if ($fileUsage > env("PERSONAL_FILE_LIMIT")) {
40 return responder("error", "Limit Exceeded!", "You have exceeded your limit of ".env("PERSONAL_FILE_LIMIT")." files.");
41 }
42 // check disk usage limits
43 if ($diskUsage > env("PERSONAL_DISK_LIMIT")) {
44 return responder("error", "Limit Exceeded!", "You have exceeded your limit of ".env("PERSONAL_DISK_LIMIT")." MBs.");
45 }
46 }else{
47 $fileUsage = Database::table("files")->where("company" , $user->company)->count("id", "files")[0]->files;
48 $diskUsage = Database::table("files")->where("company" , $user->company)->sum("id", "size")[0]->size / 1000;
49 // check file usage limits
50 if ($fileUsage > env("BUSINESS_FILE_LIMIT")) {
51 return responder("error", "Limit Exceeded!", "You have exceeded your limit of ".env("BUSINESS_FILE_LIMIT")." files.");
52 }
53 // check disk usage limits
54 if ($diskUsage > env("BUSINESS_DISK_LIMIT")) {
55 return responder("error", "Limit Exceeded!", "You have exceeded your limit of ".env("BUSINESS_DISK_LIMIT")." MBs.");
56 }
57 }
58 if ($user->company == 0) {
59 $files = Database::table("files")->where("name", $data["name"])->where("folder", $data["folder"])->first();
60 }else{
61 $files = Database::table("files")->where("name", $data["name"])->where("folder", $data["folder"])->where("company", $user->company)->first();
62 }
63 if (!empty($files) && $data["source"] == "form") {
64 return responder("error", "Already Exists!", "File name '".$data["name"]."' already exists.");
65 }
66 if(env("ALLOW_NON_PDF") == "Enabled"){
67 $allowedExtensions = "pdf, doc, docx, ppt, pptx, xls, xlsx";
68 }else{
69 $allowedExtensions = "pdf";
70 }
71 if ($data['source'] == "googledrive") {
72 $upload = array(
73 "status" => "success",
74 "info" => array(
75 "name" => $data['file'],
76 "size" => $data['size'],
77 "extension" => "pdf"
78 )
79 );
80 }else{
81 $upload = File::upload(
82 $data['file'],
83 "files",
84 array(
85 "source" => $data['source'],
86 "allowedExtensions" => $allowedExtensions
87 )
88 );
89 }
90
91 if ($upload['status'] == "success") {
92 self::keepcopy($upload['info']['name']);
93 $data["filename"] = $upload['info']['name'];
94 $data["size"] = $upload['info']['size'];
95 $data["extension"] = $upload['info']['extension'];
96 $activity = $data['activity'];
97 unset($data['file'], $data['source'], $data['activity']);
98 Database::table("files")->insert($data);
99 $documentId = Database::table("files")->insertId();
100 $document = Database::table("files")->where("id", $documentId)->get("document_key");
101 Database::table("history")->insert(array("company" => $data['company'], "file" => $document[0]->document_key, "activity" => $activity, "type" => "default"));
102 return responder("success", "Upload Complete", "File successfully uploaded.");
103 }else{
104 return responder("error", "Oops!", $upload['message']);
105 }
106 }
107
108 /**
109 * Duplicate file
110 *
111 * @param int $data
112 * @return true
113 */
114 public static function duplicate($file, $duplicateName = '') {
115 $document = Database::table("files")->where("id", $file)->first();
116 $user = Auth::user();
117 $fileName = Str::random(32).".".$document->extension;
118 copy(config("app.storage")."files/".$document->filename, config("app.storage")."files/".$fileName);
119 self::keepcopy($fileName);
120 if(empty($duplicateName)){ $duplicateName = $document->name." (Copy)"; }
121 $activity = 'File Duplicated from '.escape($document->name).' by <span class="text-primary">'.escape($user->fname.' '.$user->lname).'</span>.';
122 $data = array(
123 "company" => $user->company,
124 "uploaded_by" => $user->id,
125 "name" => $duplicateName,
126 "folder" => $document->folder,
127 "filename" => $fileName,
128 "extension" => $document->extension,
129 "size" => $document->size,
130 "status" => $document->status,
131 "is_template" => $document->is_template,
132 "document_key" => Str::random(32)
133 );
134 Database::table("files")->insert($data);
135 $documentId = Database::table("files")->insertId();
136 $document = Database::table("files")->where("id", $documentId)->get("document_key");
137 Database::table("history")->insert(array("company" => $data['company'], "file" => $document[0]->document_key, "activity" => $activity, "type" => "default"));
138 return $documentId;
139 }
140
141 /**
142 * Copy file
143 *
144 * @param string $filename
145 * @return true
146 */
147 public static function keepcopy($filename) {
148 copy(config("app.storage")."files/".$filename, config("app.storage")."copies/".$filename);
149 return true;
150 }
151
152 /**
153 * Copy file
154 *
155 * @param string $filename
156 * @return true
157 */
158 public static function renamecopy($fileName, $newName) {
159 rename(config("app.storage")."copies/".$fileName, config("app.storage")."copies/".$newName);
160 return true;
161 }
162
163 /**
164 * Delete a folder
165 *
166 * @param string|int $folderId
167 * @return true
168 */
169 public static function deletefolder($folderId) {
170 $foldersToDelete = $filesToDelete = array();
171 $user = Auth::user();
172 $thisFolder = Database::table("folders")->where("id", $folderId)->first();
173 if ($user->company != $thisFolder->company) {
174 return false;
175 }
176 $folders = Database::table("folders")
177 ->where("folder", $folderId)
178 ->get();
179 foreach ($folders as $folder) {
180 $foldersToDelete[] = $folder->id;
181 $folderFiles = Database::table("files")->where("folder", $folder->id)->get();
182 foreach ($folderFiles as $file) {
183 self::deletefile($file->filename, true);
184 }
185 self::deletefolder($folder->id);
186 }
187 $folderFiles = Database::table("files")->where("folder", $folderId)->get();
188 foreach ($folderFiles as $file) {
189 self::deletefile($file->filename, true);
190 }
191 Database::table("folders")->where("id", $folderId)->delete();
192 return true;
193 }
194
195 /**
196 * Delete a file
197 *
198 * @param int $fileId
199 * @return true
200 */
201 public static function deletefile($fileId, $actualFile = false) {
202 if (!$actualFile) {
203 $user = Auth::user();
204 $thisFile = Database::table("files")->where("id", $fileId)->first();
205 if ($user->company != $thisFile->company) {
206 return false;
207 }else if($user->role = "user" AND $thisFile->uploaded_by != $user->id){
208 $hiddenFiles = $user->hiddenfiles;
209 if(empty($user->hiddenfiles)){
210 $hiddenFiles = array($thisFile->id);
211 }else{
212 $hiddenFilesArray = json_decode($hiddenFiles);
213 $hiddenFiles = array_push($hiddenFiles, $thisFile->id);
214 }
215 Database::table("users")->where("id", $user->id)->update(array("hiddenfiles" => json_encode($hiddenFiles)));
216 }else{
217 File::delete($thisFile->filename, "files");
218 File::delete($thisFile->filename, "copies");
219 Database::table("files")->where("id", $thisFile->id)->delete();
220 }
221 }else{
222 if ($actualFile == "original") {
223 File::delete($fileId, "files");
224 }else{
225 File::delete($fileId, "files");
226 File::delete($fileId, "copies");
227 }
228 }
229 return true;
230 }
231
232 /**
233 * Record file history
234 *
235 * @param string $document_key
236 * @param string $activity
237 * @param string $type
238 * @return true
239 */
240 public static function keephistory($document_key, $activity, $type = "default") {
241 $document = Database::table("files")->where("document_key", $document_key)->first();
242 Database::table("history")->insert(array("company" => $document->company, "file" => $document_key, "activity" => $activity, "type" => $type));
243 return true;
244 }
245
246 /**
247 * Save notifications
248 *
249 * @param int $user
250 * @param string $notification
251 * @param string $type
252 * @return true
253 */
254 public static function notification($user, $notification, $type = "warning") {
255 Database::table("notifications")->insert(array("user" => $user, "message" => $notification, "type" => $type));
256 return true;
257 }
258
259 /**
260 * Convert file to PDF
261 *
262 * @param string $document_key
263 * @return array
264 */
265 public static function convert($document_key) {
266 $user = Auth::user();
267 $document = Database::table("files")->where("document_key", $document_key)->first();
268 $outputName = Str::random(32).".pdf";
269 if (env('USE_CLOUD_CONVERT') == "Enabled" && !empty(env('CLOUDCONVERT_APP_KEY'))) {
270 $api = new Api(env('CLOUDCONVERT_APP_KEY'));
271 try {
272 $api->convert([
273 'inputformat' => $document->extension,
274 'outputformat' => 'pdf',
275 'input' => 'upload',
276 'file' => fopen(config("app.storage").'/files/'.$document->filename, 'r'),
277 ])
278 ->wait()
279 ->download(config("app.storage").'/files/'.$outputName);
280 } catch (\CloudConvert\Exceptions\ApiBadRequestException $e) {
281 return responder("error", "Failed!", $e->getMessage());
282 } catch (\CloudConvert\Exceptions\ApiConversionFailedException $e) {
283 return responder("error", "Failed!", $e->getMessage());
284 } catch (\CloudConvert\Exceptions\ApiTemporaryUnavailableException $e) {
285 return responder("error", "Failed!", $e->getMessage());
286 } catch (\Exception $e) {
287 return responder("error", "Failed!", $e->getMessage());
288 }
289 }else if(env('USE_CLOUD_CONVERT') == "Disabled"){
290 return responder("error", "Failed!", "Cloud Convert is not enabled, please enable on system settings page.");
291 }else{
292 return responder("error", "Failed!", "Your Cloud Convert API Key is empty.");
293 }
294 self::deletefile($document->filename, true);
295 self::keepcopy($outputName);
296 $data = array(
297 "filename" => $outputName,
298 "size" => round(filesize(config("app.storage")."/files/".$outputName) / 1000),
299 "extension" => "pdf"
300 );
301 Database::table("files")->where("document_key", $document_key)->update($data);
302 $activity = 'File converted to PDF by <span class="text-primary">'.escape($user->fname.' '.$user->lname).'</span>.';
303 self::keephistory($document_key, $activity);
304 return responder("success", "Complete!", "Conversion successfully completed.");
305 }
306
307 /**
308 * Check file orientation
309 *
310 * @param float $width
311 * @param float $height
312 * @return string
313 */
314 public static function orientation($width, $height) {
315 if ($width > $height) {
316 return "L";
317 }else{
318 return "P";
319 }
320 }
321
322 /**
323 * Protect file
324 *
325 * @param string $document_key
326 * @return true
327 */
328 public static function protect($permission, $userpassword, $ownerpassword, $document_key) {
329 $user = Auth::user();
330 $document = Database::table("files")->where("document_key", $document_key)->first();
331 $pdf = new PDF();
332 $inputPath = config("app.storage")."/files/".$document->filename;
333 $outputName = Str::random(32).".pdf";
334 $outputPath = config("app.storage")."/files/". $outputName;
335 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
336 if (env("PKI_STATUS") == "Enabled") {
337 $certificate = 'file://'.realpath(config("app.storage").'/credentials/tcpdf.crt');
338 $reason = $document->sign_reason.' • Digital Signature | '.$user->fname.' '.$user->lname.', '.self::ipaddress().','.date("F j, Y H:i");
339 $info = array( 'Name' => $userName, 'Location' => env("APP_URL"), 'Reason' => $reason, 'ContactInfo' => env("APP_URL") );
340 $pdf->setSignature($certificate, $certificate, 'information', '', 1, $info, true);
341 }
342 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
343 $pdf->SetProtection($permission, $userpassword, $ownerpassword, 0, null);
344 $pdf->numPages = $pdf->setSourceFile($inputPath);
345 foreach(range(1, $pdf->numPages, 1) as $page) {
346 try {
347 $pdf->_tplIdx = $pdf->importPage($page);
348 }
349 catch(\Exception $e) {
350 return false;
351 }
352 $size = $pdf->getTemplateSize($pdf->_tplIdx);
353 $pdf->AddPage(self::orientation($size['w'], $size['h']), array($size['w'], $size['h']), true);
354 $pdf->useTemplate($pdf->_tplIdx);
355 }
356 $pdf->Output($outputPath, 'F');
357 Database::table("files")->where("document_key", $document_key)->update(array("filename" => $outputName));
358 $activity = '<span class="text-primary">'.escape($user->fname.' '.$user->lname).'</span> has activated document protection.';
359 self::keephistory($document_key, $activity, "danger");
360 self::deletefile($document->filename, true);
361 self::keepcopy($outputName);
362 return true;
363 }
364
365 /**
366 * Sign & Edit document
367 *
368 * @param string $document_key
369 * @return array
370 */
371 public static function sign($document_key, $actions, $docWidth, $signing_key, $public = false) {
372 if (!empty($signing_key) && !$public) {
373 $request = Database::table("requests")->where("signing_key", $signing_key)->first();
374 $sender = Database::table("users")->where("id", $request->sender)->first();
375 $userName = $request->email;
376 $user = Auth::user();
377 $userName = $user->fname.' '.$user->lname;
378 $signature = config("app.storage")."signatures/".$user->signature;
379 }else if ($public) {
380 $userName = "Guest";
381 $signature = null;
382 }else{
383 $user = Auth::user();
384 $userName = $user->fname.' '.$user->lname;
385 $signature = config("app.storage")."signatures/".$user->signature;
386 }
387
388 $document = Database::table("files")->where("document_key", $document_key)->first();
389 $pdf = new PDF(null, 'px');
390 $pdf->SetAutoPageBreak(FALSE, PDF_MARGIN_BOTTOM);
391 $inputPath = config("app.storage")."files/".$document->filename;
392 $outputName = Str::random(32).".pdf";
393 $outputPath = config("app.storage")."/files/". $outputName;
394 $pdf->numPages = $pdf->setSourceFile($inputPath);
395 $actions = json_decode(base64_decode($actions), true);
396 $templateFields = array($docWidth);
397 $signed = $updatedFields = $editted = false;
398 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
399 if (env("PKI_STATUS") == "Enabled") {
400 $certificate = 'file://'.realpath(config("app.storage").'/credentials/tcpdf.crt');
401 $reason = $document->sign_reason.' • Digital Signature | '.$userName.', '.self::ipaddress().','.date("F j, Y H:i");
402 $info = array( 'Name' => $userName, 'Location' => env("APP_URL"), 'Reason' => $reason, 'ContactInfo' => env("APP_URL") );
403 $pdf->setSignature($certificate, $certificate, 'information', '', 1, $info, true);
404 }
405 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
406 foreach(range(1, $pdf->numPages, 1) as $page) {
407 $rotate = false;
408 $degree = 0;
409 try {
410 $pdf->_tplIdx = $pdf->importPage($page);
411 }
412 catch(\Exception $e) {
413 return false;
414 }
415 foreach($actions as $action) {
416 if(((int) $action['page']) === $page && $action['type'] == "rotate") {
417 $rotate = $editted = true;
418 $degree = $action['degree'];
419 break;
420 }
421 }
422 $size = $pdf->getTemplateSize($pdf->_tplIdx);
423 $scale = round($size['w'] / $docWidth, 3);
424 $pdf->AddPage(self::orientation($size['w'], $size['h']), array($size['w'], $size['h'], 'Rotate'=>$degree), true);
425 $pdf->useTemplate($pdf->_tplIdx);
426 foreach($actions as $action) {
427 if(((int) $action['page']) === $page) {
428 if ($action['group'] == "input") {
429 $updatedFields = true;
430 $templateFields[] = $action;
431 continue;
432 }elseif ($action['type'] == "image") {
433 $editted = true;
434 $imageArray = explode( ',', $action['image'] );
435 $imgdata = base64_decode($imageArray[1]);
436 $pdf->Image('@'.$imgdata, self::scale($action['xPos'], $scale), self::scale($action['yPos'], $scale), self::scale($action['width'], $scale), self::scale($action['height'], $scale), '', '', '', false);
437 }elseif ($action['type'] == "symbol" || $action['type'] == "shape" || $action['type'] == "stamp") {
438 $editted = true;
439 $svg = str_replace("%22", '"', $action['image']);
440 $pdf->ImageSVG('@'.$svg, self::scale($action['xPos'], $scale), self::scale($action['yPos'], $scale), self::scale($action['width'], $scale), self::scale($action['height'], $scale), '', '', '', 0, false);
441 }else if ($action['type'] == "drawing") {
442 $editted = true;
443 $imageArray = explode( ',', $action['drawing'] );
444 $imgdata = base64_decode($imageArray[1]);
445 $pdf->Image('@'.$imgdata, 0, 0, $size['w'], $size['h'], '', '', '', false);
446 }else if ($action['type'] == "signature") {
447 $signed = true;
448 if (!$public) {
449 $pdf->Image($signature, self::scale($action['xPos'], $scale), self::scale($action['yPos'], $scale), self::scale($action['width'], $scale), self::scale($action['height'], $scale), '', '', '', false);
450 }else{
451 $imageArray = explode( ',', $action['image'] );
452 $imgdata = base64_decode($imageArray[1]);
453 $pdf->Image('@'.$imgdata, self::scale($action['xPos'], $scale), self::scale($action['yPos'], $scale), self::scale($action['width'], $scale), self::scale($action['height'], $scale), '', '', '', false);
454 }
455 }elseif ($action['type'] == "text") {
456 $editted = true;
457 $pdf->SetFont($action['font'], $action['bold'].$action['italic'], $action['fontsize'] - 3);
458 $pdf->writeHTMLCell( self::scale($action['width'] + 50, $scale), self::scale($action['height'], $scale), self::scale($action['xPos'], $scale) - 3, self::scale($action['yPos'], $scale), str_replace("%22", '"', $action['text']), 0, 0, false, true, '', true );
459 }
460 }
461 }
462 }
463 $pdf->Output($outputPath, 'F');
464 if (count($templateFields) > 1) {
465 Database::table("files")->where("document_key", $document_key)->update(array("filename" => $outputName, "editted" => "Yes", "template_fields" => json_encode($templateFields)));
466 }else{
467 Database::table("files")->where("document_key", $document_key)->update(array("filename" => $outputName, "editted" => "Yes"));
468 }
469 if (!empty($signing_key)) {
470 $request = Database::table("requests")->where("signing_key", $signing_key)->first();
471 $sender = Database::table("users")->where("id", $request->sender)->first();
472 Database::table("requests")->where("signing_key", $signing_key)->update(array("status" => "Signed", "update_time" => date("Y-m-d H-i-s")));
473 $notification = '<span class="text-primary">'.escape($userName).'</span> accepted a signing invitation of this <a href="'.url("Document@open").$request->document.'">document</a>.';
474 Signer::notification($sender->id, $notification, "accept");
475 $documentLink = env("APP_URL")."/document/".$request->document;
476 $send = Mail::send(
477 $sender->email, "Signing invitation accepted by ".$userName,
478 array(
479 "title" => "Signing invitation accepted.",
480 "subtitle" => "Click the link below to view document.",
481 "buttonText" => "View Document",
482 "buttonLink" => $documentLink,
483 "message" => $userName." has accepted and signed the signing invitation you had sent. Click the link above to view the document.<br><br>Cheers!<br>".env("APP_NAME")." Team"
484 ),
485 "withbutton"
486 );
487 if(!empty($request->chain_emails)){
488 self::nextRecipient($request->id);
489 }
490 }
491 if ($updatedFields) {
492 $activity = '<span class="text-primary">'.escape($userName).'</span> updated template fields document.';
493 self::keephistory($document_key, $activity, "default");
494 }
495 if ($editted) {
496 $activity = '<span class="text-primary">'.escape($userName).'</span> editted the document.';
497 self::keephistory($document_key, $activity);
498 }
499 if ($signed) {
500 Database::table("files")->where("document_key", $document_key)->update(array("status" => "Signed"));
501 $activity = '<span class="text-primary">'.escape($userName).'</span> signed the document.';
502 self::keephistory($document_key, $activity, "success");
503 }
504 self::deletefile($document->filename, "original");
505 self::renamecopy($document->filename, $outputName);
506 return true;
507 }
508
509 /**
510 * Scale element dimension
511 *
512 * @param int $dimension
513 * @return int
514 */
515 public static function scale($dimension, $scale) {
516 return round($dimension * $scale);
517 }
518
519 /**
520 * Scale position on axis
521 *
522 * @param int $position
523 * @return int
524 */
525 public static function adjustPositions($position) {
526 return round($position - 83);
527 }
528
529 /**
530 * Get Ip Address
531 *
532 * @param int $position
533 * @return int
534 */
535 public static function ipaddress() {
536 $ipaddress = '';
537 if (getenv('HTTP_CLIENT_IP'))
538 $ipaddress = getenv('HTTP_CLIENT_IP');
539 else if(getenv('HTTP_X_FORWARDED_FOR'))
540 $ipaddress = getenv('HTTP_X_FORWARDED_FOR');
541 else if(getenv('HTTP_X_FORWARDED'))
542 $ipaddress = getenv('HTTP_X_FORWARDED');
543 else if(getenv('HTTP_FORWARDED_FOR'))
544 $ipaddress = getenv('HTTP_FORWARDED_FOR');
545 else if(getenv('HTTP_FORWARDED'))
546 $ipaddress = getenv('HTTP_FORWARDED');
547 else if(getenv('REMOTE_ADDR'))
548 $ipaddress = getenv('REMOTE_ADDR');
549 else
550 $ipaddress = 'UNKNOWN';
551
552 return $ipaddress;
553 }
554
555 /**
556 * Send the next request on queue
557 *
558 * @param int $requestId
559 * @return true
560 */
561 public static function nextRecipient($requestId) {
562 $request = Database::table("requests")->where("id", $requestId)->first();
563 $sender = Database::table("users")->where("id", $request->sender)->first();
564 $emails = json_decode($request->chain_emails, true);
565 $chain_positions = str_replace( array('["[',']","[',']"]'), array('[[', '],[', ']]'), $request->chain_positions );
566 $positions = json_decode($chain_positions, true);
567 $activity = 'Signing request (Chained) sent to <span class="text-primary">'.escape($emails[0]).'</span> by <span class="text-primary">'.escape($sender->fname.' '.$sender->lname).'</span>.';
568 self::keephistory($request->document, $activity, "default");
569 $chainEmails = $chainPositions = '';
570
571 if(count($emails) > 1){
572 $chainEmails = $emails;
573 unset($chainEmails[0]);
574 $chainEmails = array_values ( $chainEmails );
575 $chainEmails = json_encode($chainEmails);
576 $chainPositions = $positions;
577 unset($chainPositions[0]);
578 $chainPositions = array_values ( $chainPositions );
579 $chainPositions = json_encode($chainPositions);
580 }
581
582 $signingKey = Str::random(32);
583 if( env('GUEST_SIGNING') == "Enabled" AND env('FORCE_GUEST_SIGNING') == "Enabled"){
584 $signingLink = env("APP_URL")."/view/".$request->document."?signingKey=".$signingKey;
585 }else{
586 $signingLink = env("APP_URL")."/document/".$request->document."?signingKey=".$signingKey;
587 }
588 $trackerLink = env("APP_URL")."/mailopen?signingKey=".$signingKey;
589 $receiverData = Database::table("users")->where("email", $emails[0])->first();
590 if (!empty($receiverData)) { $receiver = $receiverData->id; }else{ $receiver = 0; }
591 $requestData = array( "sender_note" => escape($request->sender_note), "chain_emails" => $chainEmails, "chain_positions" => $chainPositions, "company" => $sender->company, "document" => $request->document, "signing_key" => $signingKey, "positions" => json_encode($positions[0]), "email" => $emails[0], "sender" => $sender->id, "receiver" => $receiver );
592 Database::table("requests")->insert($requestData);
593 $send = Mail::send(
594 $emails[0], $sender->fname." ".$sender->lname." has invited you to sign a document",
595 array(
596 "title" => "Document Signing invite",
597 "subtitle" => "Click the link below to respond to the invite.",
598 "buttonText" => "Sign Now",
599 "buttonLink" => $signingLink,
600 "message" => "You have been invited to sign a document by ".$sender->fname." ".$sender->lname.". Click the link above to respond to the invite.<br><strong>Message:</strong> ".$request->sender_note."<br><br>Cheers!<br>".env("APP_NAME")." Team
601 <img src='".$trackerLink."' width='0' height='0'>"
602 ),
603 "withbutton"
604 );
605 return true;
606 }
607
608}