File: /mnt/data/ghayatcom/ghayatcom-api/app/Http/Controllers/Api/SumsubController.php
<?php
namespace App\Http\Controllers\Api;
// namespace App\Http\Controllers;
use App\Country;
use App\Http\Controllers\Controller;
use App\Http\Requests\SumsubProfileRequest;
use App\Http\Requests\SumsubUploadRequest;
use App\Http\Requests\UserIdRequest;
use App\Http\Requests\SumsubTokenRequest;
use App\Http\Requests\AddSumsubDocumentRequest;
use App\Library\S3Library;
use App\Sumsub;
use App\User;
use Config;
use DB;
use Exception;
use GuzzleHttp;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\MultipartStream;
use GuzzleHttp\Stream\Stream;
use Illuminate\Database\QueryException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Storage;
use Throwable;
/**
* App\Http\Controllers\Api
*
* @property mixed $sumsub_test_base_url
* @property mixed $sumsub_app_token
* @property mixed $secret_key
* @property mixed $level_name
*/
class SumsubController extends Controller
{
public function __construct()
{
$this->sumsub_test_base_url = Config::get('sumsub.sumsub_test_base_url');
$this->sumsub_app_token = Config::get('sumsub.sumsub_app_token');
$this->secret_key = Config::get('sumsub.sumsub_secret_key');
$this->level_name = Config::get('sumsub.level_name');
}
public function webhook(Request $request)
{
$input = file_get_contents("php://input");
$events = (array) json_decode($input, true);
// $url = '/resources/applicants/'.$events['applicantId'].'/one';
// $request = new GuzzleHttp\Psr7\Request('GET', $this->sumsub_test_base_url.$url);
// $responseBody = $this->sendHttpRequest($request, $url)->getBody();
// $data = json_decode($responseBody);
$status = '0';
if(isset($events['reviewResult'])) {
/**
* @var array $events
*/
if(isset($events['reviewResult']['reviewAnswer'])) {
if($events['reviewResult']['reviewAnswer'] == 'GREEN') {
$status = '1';
}
if($events['reviewResult']['reviewAnswer'] == 'RED') {
$status = '2';
}
}
}
$sumsub = Sumsub::firstOrNew([
'application_id' => $events['applicantId']
]);
$sumsub->type = 'PASSPORT';
$sumsub->external_user_id = $events['externalUserId'];
// $sumsub->file_name = $events['reviewStatus'].' - '.$events['reviewResult'];
$sumsub->status = $status;
$sumsub->response_json = json_encode($events);
$sumsub->save();
return true;
}
public function getProfileDetails(SumsubProfileRequest $request)
{
$validated = $request->validated();
try {
$status = Sumsub::where('user_id', $request->user_id)->orderBy('id', 'desc')->first();
if ($status) {
$applicantId = $status->application_id;
$upload_id = $status->upload_id;
$url = '/resources/applicants/'.$applicantId.'/one';
$request = new GuzzleHttp\Psr7\Request('GET', $this->sumsub_test_base_url.$url);
$responseBody = $this->sendHttpRequest($request, $url)->getBody();
$data = json_decode($responseBody);
$first_name = '';
$last_name = '';
$gender = '';
$dob = '';
$idcard_number = '';
$country = '';
$country_data = [];
/**
* @var object $data
*/
if (isset($data->info)) {
$first_name = isset($data->info->firstNameEn) ? $data->info->firstNameEn : '';
$last_name = isset($data->info->lastNameEn) ? $data->info->lastNameEn : '';
$gender = isset($data->info->gender) ? $data->info->gender : '';
$dob = isset($data->info->dob) ? $data->info->dob : '';
$idcard_number = isset($data->info->idDocs[0]->number) ? $data->info->idDocs[0]->number : '';
$country = isset($data->info->country) ? $data->info->country : '';
if ($country != '') {
$country_data = Country::select('id', 'name')->where('iso3', $country)->first();
}
}
$response_array = ['first_name' =>$first_name, 'last_name'=>$last_name, 'gender'=>$gender, 'dob'=>$dob, 'idcard_number'=>$idcard_number, 'country'=>$country, 'country_name'=>$country_data];
return self::sentResponse(200, $response_array, __('digimed_validation.success_response.sumsub_status'));
} else {
return self::sentResponse(401, [], __('digimed_validation.error_response.user_not_found'));
}
} catch (Exception | Throwable | QueryException $e) {
return self::sentResponse(500, [], $e->getMessage());
}
}
public function createApplicant($external_user_id)
{
$levelName = $this->level_name;
$requestBody = [
'externalUserId' => $external_user_id, //$request->externalUserId
];
$url = '/resources/applicants?levelName='.$levelName;
$request = new GuzzleHttp\Psr7\Request('POST', $this->sumsub_test_base_url.$url);
$request = $request->withHeader('Content-Type', 'application/json');
$request = $request->withBody(GuzzleHttp\Psr7\Utils::streamFor(json_encode($requestBody)));
$responseBody = $this->sendHttpRequest($request, $url)->getBody();
$final = json_decode($responseBody);
/** @var object $final */
return $final->id;
}
public function sendHttpRequest($request, $url)
{
$client = new GuzzleHttp\Client();
$ts = time();
$request = $request->withHeader('X-App-Token', $this->sumsub_app_token);
$request = $request->withHeader('X-App-Access-Sig', $this->createSignature($ts, $request->getMethod(), $url, $request->getBody()));
$request = $request->withHeader('X-App-Access-Ts', $ts);
// Reset stream offset to read body in `send` method from the start
$request->getBody()->rewind();
try {
$response = $client->send($request);
if ($response->getStatusCode() != 200 && $response->getStatusCode() != 201) {
// https://developers.sumsub.com/api-reference/#errors
// If an unsuccessful answer is received, please log the value of the "correlationId" parameter.
// Then perhaps you should throw the exception. (depends on the logic of your code)
}
} catch (GuzzleHttp\Exception\GuzzleException $e) {
$response = $e->getMessage();
error_log($e);
}
return $response;
}
private function createSignature($ts, $httpMethod, $url, $httpBody)
{
/**
* @var string $secret_key
*/
$secret_key = $this->secret_key;
return hash_hmac('sha256', $ts.strtoupper($httpMethod).$url.$httpBody, $secret_key);
}
public function addNewDocument($application_id, $file_path, $type)
{
try {
$metadata = ['idDocType' => $type, 'country' => 'MLT'];
$multipart = new MultipartStream([
[
'name' => 'metadata',
'contents' => json_encode($metadata),
],
[
'name' => 'content',
'contents' => (Config::get('filesystems.default') == 's3') ? file_get_contents($file_path, true) : fopen($file_path, 'r'),
],
]);
$url = '/resources/applicants/'.$application_id.'/info/idDoc';
$request = new GuzzleHttp\Psr7\Request('POST', $this->sumsub_test_base_url.$url);
$request = $request->withBody($multipart);
return $this->sendHttpRequest($request, $url)->getHeader('X-Image-Id')[0];
} catch (Exception | Throwable | QueryException $e) {
return '';
}
}
public function getApplicantStatus($applicantId)
{
$applicantId = $applicantId; //'61a0c1437b606d000185157d';
$url = '/resources/applicants/'.$applicantId.'/requiredIdDocsStatus';
$request = new GuzzleHttp\Psr7\Request('GET', $this->sumsub_test_base_url.$url);
$responseBody = $this->sendHttpRequest($request, $url)->getBody();
// dd(json_decode($responseBody));
return json_decode($responseBody);
}
public function getAccessToken($externalUserId, $levelName)
{
$url = '/resources/accessTokens?userId='.$externalUserId.'&levelName='.$levelName;
$request = new GuzzleHttp\Psr7\Request('POST', $this->sumsub_test_base_url.$url);
return $this->sendHttpRequest($request, $url)->getBody();
}
public function getStatus(UserIdRequest $request)
{
$validated = $request->validated();
try {
$user_id = $request->user_id;
$user = User::where('id', $user_id)->first();
// $sumsub = Sumsub::where('user_id', $user_id)->orderBy('id', 'desc')->first();
// if ($sumsub) {
// $sumsubId = $sumsub->id;
// $upload_id = $sumsub->upload_id;
// $application_id = $sumsub->application_id;
// $status = $sumsub->status;
// if($status == '1') {
User::where('id', $user_id)->where('user_completion', 1)->update(['user_completion' => Config::get('onboard_lists.for_patient_list.1.id')]);
$response_array = ['sumsub'=>'1', 'user_id'=>$user_id, 'status' => '1', 'status_value' =>'Approved', 'admin_approval'=>$user->status];
return self::sentResponse(200, $response_array, __('digimed_validation.success_response.sumsub_verified'));
// } else if($status == '2') {
// User::where('id', $user_id)->update(['user_completion' => 1]);
// $response_array = ['sumsub'=>'2', 'user_id'=>$user_id, 'status' => '2', 'status_value' =>'Rejected', 'admin_approval'=>$user->status];
// return self::sentResponse(406, $response_array, __('digimed_validation.error_response.sumsub_rejected'));
// } else {
// $response_array = ['sumsub' => '0', 'user_id'=>$user_id, 'status' => '0', 'status_value' =>'In Progress', 'admin_approval'=>$user->status];
// return self::sentResponse(202, $response_array, __('digimed_validation.error_response.awaiting_sumsub_approval'));
// }
// } else {
// $response_array = ['sumsub' => '-1', 'user_id'=>$user_id, 'status' =>'-1', 'status_value' =>'', 'admin_approval'=>$user->status];
// return self::sentResponse(404, $response_array, __('digimed_validation.error_response.sumsub_not_found'));
// }
} catch (Exception | Throwable | QueryException $e) {
return self::sentResponse(500, [], $e->getMessage());
}
}
public function accessToken(SumsubTokenRequest $request)
{
try {
$validated = $request->validated();
$user_id = $request->user_id;
$rejected = $request->rejected;
$external_user_id = substr(md5($request->user_id), 0, 10);
if($rejected){
$cnt = Sumsub::where("id",$user_id)->count();
if($cnt > 0){
$external_user_id = substr(md5($request->user_id."-".$cnt), 0, 10);
}
}
$sumsub_cnt = Sumsub::where('user_id', $user_id)->count();
$externalUserId = $external_user_id;
$levelName = $this->level_name;
$url = "/resources/accessTokens?userId=" . $externalUserId . "&levelName=" . $levelName;
$request = new GuzzleHttp\Psr7\Request('POST', $this->sumsub_test_base_url.$url);
$output = $this->sendHttpRequest($request, $url)->getBody();
$output = json_decode($output);
return self::sentResponse(200, $output, __('digimed_validation.success_response.access_token'));
} catch (Exception | Throwable | QueryException $e) {
return self::sentResponse(500, [], $e->getMessage());
}
}
public function addSumsubDocument(AddSumsubDocumentRequest $request){
try {
$validated = $request->validated();
DB::beginTransaction();
$status = $this->getApplicantStatus($request->application_id);
if(isset($status->IDENTITY)){
$identity = $status->IDENTITY;
$doc_type = $identity->idDocType;
$doc_status = 0;
$doc_id = 0;
if(isset($identity->reviewResult->reviewAnswer)){
$sumsub_status = $identity->reviewResult->reviewAnswer;
if($sumsub_status == "GREEN"){
$doc_status = '1';
}
else if($sumsub_status == "RED") {
$doc_status = '2';
}
else {
$doc_status = '0';
}
}
else {
$doc_status = '0';
}
if(!empty($identity->imageIds)){
$doc_id = end($identity->imageIds);
}
}
else{
$doc_type = '0';
$doc_status = '0';
$doc_id = 0;
}
$list = Sumsub::where('application_id',$request->application_id)->where('external_user_id', $request->external_user_id)->get();
$cnt = $list->count();
if($cnt != 0){
$sumsub = Sumsub::where('application_id',$request->application_id)->where('external_user_id', $request->external_user_id)->first();
}
else {
$sumsub = new Sumsub();
}
$sumsub->user_id = $request->user_id;
$sumsub->application_id = $request->application_id;
$sumsub->type = $doc_type;
$sumsub->external_user_id = $request->external_user_id;
$sumsub->file_name = $request->file_name;
$sumsub->upload_id = $doc_id;
$sumsub->status = $doc_status;
$sumsub->created_by = $request->user_id;
$sumsub->save();
DB::commit();
$response_array = ['user_id' => $request->user_id,'application_id'=>$request->application_id];
return self::sentResponse(200, $response_array, __('digimed_validation.success_response.sumsub_document_added'));
} catch (Exception | Throwable | QueryException $e) {
DB::rollback();
return self::sentResponse(500, [], $e->getMessage());
}
}
}