HEX
Server: Apache/2.4.41 (Ubuntu)
System: Linux ip-172-31-42-149 5.15.0-1084-aws #91~20.04.1-Ubuntu SMP Fri May 2 07:00:04 UTC 2025 aarch64
User: ubuntu (1000)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: /var/www/vhost/disk-apps/demo.sports-crowd.com/app/Core/ZapSign/Application/ZapSignService.php
<?php

declare(strict_types=1);

namespace App\Core\ZapSign\Application;

use App\Core\ZapSign\DocumentStatusEnum;
use App\Core\ZapSign\DocumentTypesEnum;
use App\DocumentAnalytic;
use App\Services\AcademyDocumentService;
use App\Services\AcademyService;
use Illuminate\Http\Request;
use App\Http\Controllers\UtilController;
use App\IntegrationProvider;
use Illuminate\Support\Facades\DB;

class ZapSignService
{

    private $academyDocumentService;
    private $academyService;
    private $utilController;

    public function __construct()
    {
        $this->academyDocumentService = new AcademyDocumentService;
        $this->academyService = new AcademyService;
        $this->utilController = new UtilController;
    }

    public function autocomplete(Request $request)
    {
        if ($link = $this->academyDocumentService->validateDocumentStatus($request)) {
            if ($link['r'] && str_contains($link['d'], 'zapsign')) {
                return $link;
            }
        }

        $validProviderData = $this->validateProviderData();
        if (!$validProviderData['r']) {
            return $validProviderData;
        }
        $providerData = $validProviderData['providerData'];

        $data = $this->mapDataDocument($request);
        $this->utilController->logFile(json_encode($data), 'zapsign');
        $document = $this->createDocument($data, $providerData);
        if (!$document['r']) {
            return $document;
        }
        $this->registerDocumentAnalitics($document['data']);
        $response = $this->mapResponse($request, $document['data']);
        return $response;
    }

    public function webhooksListener(Request $request)
    {
        header('Content-Type: application/json');
        $this->utilController->logFile($request, 'zapsign');

        $content = json_decode($request->getContent(), true);
        if (!$content) {
            return array('r' => false, 'm' => __('messages.error_updating'));
        }

        $answers = $this->findValueByKey($content, 'answers');
        $webhook = $this->findValueByValueKey($answers, 'webhook');
        if ($webhook) {
            if (!str_contains($webhook, $request->getSchemeAndHttpHost())) {
                $this->resendWebhook($webhook, $request);
                return;
            }
        }

        $user = $this->findValueByValueKey($answers, 'academyUserId');
        $document = $this->findValueByValueKey($answers, 'documentId');
        $signed_file = $this->findValueByKey($content, 'signed_file');

        if (!$user || !$document || !$signed_file) {
            return array('r' => false, 'm' => __('messages.error_updating'));
        }

        $parameters                     = new \stdClass();
        $parameters->user               = $user;
        $parameters->document           = $document;
        $parameters->file               = $this->convertUrltoBase64($signed_file);
        $parameters->extension          = $this->convertUrltoExtension($signed_file);
        $response                       = $this->academyDocumentService->uploadUserAcademyDocumentExternal($parameters);

        $file = $response['r'] ? $response['data']['link'] : $signed_file;
        $this->updateDocumentAnalitics($content, $file);
        return $response;
    }

    public function documentAnalytics(Request $request)
    {
        $data = $this->mapDocumentAnalytics($request);
        return view('document_analytics.report', compact('data'));
    }

    private function validateProviderData()
    {
        $providerData = $this->providerData();
        if (!$providerData) {
            return array("r" => false, "m" => __('messages.integrations.provider_not_found'));
        } else if (!$providerData->active) {
            return array("r" => false, "m" => __('messages.integrations.provider_not_active'));
        }
        return array("r" => true, "m" => __('messages.integrations.validate_data_successfully'), 'providerData' => $providerData);
    }

    private function providerData()
    {
        return IntegrationProvider::where('alias', 'zapsign')->where('active', 1)->first();
    }

    private function resendWebhook($webhook, $request)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $webhook);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $request->getContent());
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_exec($ch);
        curl_close($ch);
    }

    private function mapDataDocument($request)
    {
        $templateId = $this->academyDocumentService->getExternalFormId($request->get('documentId'));
        $params = $this->encryptParamsData($request);

        $academyUser = $this->academyService->find($request->get('academyUserId'));
        $signerName = $academyUser ? $academyUser->advisor_name . ' ' . $academyUser->advisor_last_name : 'ZapSign';
        $signerEmail = $academyUser ? $academyUser->advisor_mail : '';
        $data   = [
            "template_id"               => $templateId,
            "signer_name"               => $signerName,
            "signer_email"              => $signerEmail,
            "send_automatic_email"      => false,
            "send_automatic_whatsapp"   => false,
            "lang"                      => "en-us",
            "external_id"               => null,
            "signer_has_incomplete_fields"  => true,
            "data"                      => $params
        ];
        return $data;
    }

    private function encryptParamsData($request)
    {
        $data = [];
        $data[] = [
            'de'    => 'webhook',
            'para'  => $request->getSchemeAndHttpHost() . '/api/zapsign/webhooksListener'
        ];
        $data[] = [
            'de'    => 'academyUserId',
            'para'  => $request->get('academyUserId') . ''
        ];
        $data[] = [
            'de'    => 'documentId',
            'para'  => $request->get('documentId') . ''
        ];

        $dataAcademy = $this->academyService->mapDataAcademy($request->get('academyUserId'));
        $data = array_merge($data, $dataAcademy);
        return $data;
    }

    private function createDocument($data, $providerData)
    {
        try {
            $client = new \GuzzleHttp\Client();
            $response = $client->post($providerData->endpoint . "/api/v1/models/create-doc/", [
                'headers' => [
                    'Content-Type'  => 'application/json',
                    'Authorization' => 'Bearer ' . $providerData->password
                ],
                'body'              => json_encode($data),
            ]);

            $body = $response->getBody()->getContents();
            $body = json_decode($body, true);
            return array("r" => true, "m" => __('messages.academy_document.document_uploaded_successfully'), "data" => $body);
        } catch (\Exception $e) {
            return array("r" => false, "m" => $e->getMessage());
        }
    }

    private function registerDocumentAnalitics($data)
    {
        $token = $this->findValueByKey($data, 'token');
        $name  = $this->findValueByKey($data, 'name');
        if ($token) {
            DocumentAnalytic::updateOrCreate(
                ['token' => $token],
                [
                    'token'     => $token,
                    'name'      => $name,
                    'status'    => DocumentStatusEnum::PENDING,
                    'type'      => DocumentTypesEnum::SIGNATURE
                ]
            );
        }
    }

    private function updateDocumentAnalitics($data, $file)
    {
        $token = $this->findValueByKey($data, 'token');
        if ($token) {
            DocumentAnalytic::updateOrCreate(
                ['token' => $token],
                [
                    'token'     => $token,
                    'status'    => DocumentStatusEnum::SIGNED,
                    'file'      => $file
                ]
            );
        }
    }

    private function mapResponse($request, $data)
    {
        $link = $this->findValueByKey($data, 'sign_url');
        if ($link) {
            $this->academyDocumentService->updateDocumentLink($request, $link);
            return array("r" => true, "m" => __('messages.academy_document.sign_url_found_successfully'), "d" => $link);
        } else {
            return array("r" => false, "m" => __('messages.academy_document.sign_url_not_found'));
        }
    }

    private function findValueByKey($jsonObject, $searchKey)
    {
        if (array_key_exists($searchKey, $jsonObject)) {
            return $jsonObject[$searchKey];
        }

        foreach ($jsonObject as $key => $value) {
            if (is_array($value)) {
                $result = $this->findValueByKey($value, $searchKey);
                if ($result !== null) {
                    return $result;
                }
            }
        }

        return null;
    }

    private function findValueByValueKey($data, $key)
    {
        $value;
        foreach ($data as $item) {
            if ($item['variable'] == $key) {
                $value = $item['value'];
            }
        }
        return $value;
    }

    private function convertUrltoBase64($url)
    {
        return chunk_split(base64_encode(file_get_contents($url)));
    }

    private function convertUrltoExtension($url)
    {
        return pathinfo(parse_url($url, PHP_URL_PATH), PATHINFO_EXTENSION);
    }

    private function mapDocumentAnalytics()
    {
        $data = DocumentAnalytic::select(
            'name',
            DB::raw('COUNT(*) AS created'),
            DB::raw('COUNT(CASE WHEN status = "signed" THEN 1 END) AS signed'),
            DB::raw('COUNT(CASE WHEN status = "pending" THEN 1 END) AS pending'),
            DB::raw('COUNT(CASE WHEN status = "rejected" THEN 1 END) AS rejected'),
            DB::raw('ROUND((COUNT(CASE WHEN status = "signed" THEN 1 END) / COUNT(*)) * 100) AS efficiency'),
        )
            ->groupBy('name')
            ->get();

        return $data;
    }
}