Skip to content

Commit 46a6754

Browse files
LuborRodRodion Liuborets
andauthored
SDK-2151 Static Liveness Check (#290)
* SDK-2151 Static Liveness Check * SDK-2151 Add additional assert Co-authored-by: Rodion Liuborets <[email protected]>
1 parent b4c3fe6 commit 46a6754

File tree

8 files changed

+214
-5
lines changed

8 files changed

+214
-5
lines changed

src/DocScan/Session/Create/Check/RequestedLivenessCheckBuilder.php

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44

55
namespace Yoti\DocScan\Session\Create\Check;
66

7+
use Yoti\DocScan\Constants;
78
use Yoti\Util\Validation;
89

910
class RequestedLivenessCheckBuilder
1011
{
1112
private const ZOOM = 'ZOOM';
13+
private const STATIC = 'STATIC';
1214

1315
/**
1416
* @var string
@@ -20,11 +22,21 @@ class RequestedLivenessCheckBuilder
2022
*/
2123
private $maxRetries = 1;
2224

25+
/**
26+
* @var string|null
27+
*/
28+
private $manualCheck = null;
29+
2330
public function forZoomLiveness(): self
2431
{
2532
return $this->forLivenessType(self::ZOOM);
2633
}
2734

35+
public function forStaticLiveness(): self
36+
{
37+
return $this->forLivenessType(self::STATIC);
38+
}
39+
2840
public function forLivenessType(string $livenessType): self
2941
{
3042
$this->livenessType = $livenessType;
@@ -37,12 +49,23 @@ public function withMaxRetries(int $maxRetries): self
3749
return $this;
3850
}
3951

52+
public function withoutManualCheck(): self
53+
{
54+
return $this->withManualCheck(Constants::NEVER);
55+
}
56+
57+
private function withManualCheck(string $manualCheck): self
58+
{
59+
$this->manualCheck = $manualCheck;
60+
return $this;
61+
}
62+
4063
public function build(): RequestedLivenessCheck
4164
{
4265
Validation::notEmptyString($this->livenessType, 'livenessType');
4366
Validation::notNull($this->maxRetries, 'maxRetries');
4467

45-
$config = new RequestedLivenessConfig($this->livenessType, $this->maxRetries);
68+
$config = new RequestedLivenessConfig($this->livenessType, $this->maxRetries, $this->manualCheck);
4669
return new RequestedLivenessCheck($config);
4770
}
4871
}

src/DocScan/Session/Create/Check/RequestedLivenessConfig.php

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,33 @@ class RequestedLivenessConfig implements RequestedCheckConfigInterface
1818
*/
1919
private $maxRetries;
2020

21-
public function __construct(string $livenessType, int $maxRetries)
21+
/**
22+
* @var string|null
23+
*/
24+
private $manualCheck;
25+
26+
public function __construct(string $livenessType, int $maxRetries, string $manualCheck = null)
2227
{
2328
$this->livenessType = $livenessType;
2429
$this->maxRetries = $maxRetries;
30+
$this->manualCheck = $manualCheck;
2531
}
2632

2733
/**
2834
* @return stdClass
2935
*/
3036
public function jsonSerialize(): stdClass
3137
{
32-
return (object) [
38+
$data = [
3339
'liveness_type' => $this->getLivenessType(),
3440
'max_retries' => $this->getMaxRetries(),
3541
];
42+
43+
if (null !== $this->manualCheck) {
44+
$data['manual_check'] = $this->getManualCheck();
45+
}
46+
47+
return (object)$data;
3648
}
3749

3850
/**
@@ -50,4 +62,12 @@ public function getMaxRetries(): int
5062
{
5163
return $this->maxRetries;
5264
}
65+
66+
/**
67+
* @return string|null
68+
*/
69+
public function getManualCheck(): ?string
70+
{
71+
return $this->manualCheck;
72+
}
5373
}

src/DocScan/Session/Retrieve/ResourceContainer.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ private function parseLivenessCapture(array $livenessCaptures): array
8888
case 'ZOOM':
8989
$parsedLivenessCaptures[] = new ZoomLivenessResourceResponse($capture);
9090
break;
91+
case 'STATIC':
92+
$parsedLivenessCaptures[] = new StaticLivenessResourceResponse($capture);
93+
break;
9194
default:
9295
$parsedLivenessCaptures[] = new LivenessResourceResponse($capture);
9396
break;
@@ -142,6 +145,14 @@ public function getZoomLivenessResources(): array
142145
return $this->filterLivenessByType(ZoomLivenessResourceResponse::class);
143146
}
144147

148+
/**
149+
* @return StaticLivenessResourceResponse[]
150+
*/
151+
public function getStaticLivenessResources(): array
152+
{
153+
return $this->filterLivenessByType(StaticLivenessResourceResponse::class);
154+
}
155+
145156
/**
146157
* @return FaceCaptureResourceResponse[]
147158
*/
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
namespace Yoti\DocScan\Session\Retrieve;
4+
5+
use Yoti\Exception\DateTimeException;
6+
7+
class StaticLivenessResourceResponse extends LivenessResourceResponse
8+
{
9+
/**
10+
* @var MediaResponse|null
11+
*/
12+
private $image;
13+
14+
15+
/**
16+
* StaticLivenessResourceResponse constructor.
17+
* @param array<string, mixed> $zoomLiveness
18+
* @throws DateTimeException
19+
*/
20+
public function __construct(array $zoomLiveness)
21+
{
22+
parent::__construct($zoomLiveness);
23+
24+
if (isset($zoomLiveness['image'])) {
25+
$this->image = new MediaResponse($zoomLiveness['image']['media']);
26+
}
27+
}
28+
29+
/**
30+
* @return MediaResponse|null
31+
*/
32+
public function getImage(): ?MediaResponse
33+
{
34+
return $this->image;
35+
}
36+
}

tests/DocScan/Session/Create/Check/RequestedLivenessCheckConfigTest.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,22 @@ class RequestedLivenessCheckConfigTest extends TestCase
1212
{
1313
private const SOME_LIVENESS_TYPE = 'someLivenessType';
1414
private const SOME_MAX_RETRIES = 5;
15+
private const NEVER = 'NEVER';
1516

1617
/**
1718
* @test
1819
* @covers ::__construct
1920
* @covers ::getLivenessType
2021
* @covers ::getMaxRetries
22+
* @covers ::getManualCheck
2123
*/
2224
public function shouldHoldValuesCorrectly()
2325
{
24-
$result = new RequestedLivenessConfig(self::SOME_LIVENESS_TYPE, self::SOME_MAX_RETRIES);
26+
$result = new RequestedLivenessConfig(self::SOME_LIVENESS_TYPE, self::SOME_MAX_RETRIES, self::NEVER);
2527

2628
$this->assertEquals(self::SOME_LIVENESS_TYPE, $result->getLivenessType());
2729
$this->assertEquals(self::SOME_MAX_RETRIES, $result->getMaxRetries());
30+
$this->assertEquals(self::NEVER, $result->getManualCheck());
2831
}
2932

3033
/**

tests/DocScan/Session/Create/Check/RequstedLivenessCheckBuilderTest.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class RequstedLivenessCheckBuilderTest extends TestCase
1313
{
1414
private const SOME_LIVENESS_TYPE = 'someLivenessType';
1515
private const SOME_MAX_RETRIES = 3;
16+
private const NEVER = 'NEVER';
1617

1718
/**
1819
* @test
@@ -82,4 +83,35 @@ public function shouldBuildWithZoomLivenessType()
8283

8384
$this->assertJsonStringEqualsJsonString(json_encode($expected), json_encode($result));
8485
}
86+
87+
/**
88+
* @test
89+
* @covers \Yoti\DocScan\Session\Create\Check\RequestedLivenessCheck::jsonSerialize
90+
* @covers ::forStaticLiveness
91+
* @covers ::withManualCheck
92+
* @covers ::withoutManualCheck
93+
* @covers ::withMaxRetries
94+
* @covers \Yoti\DocScan\Session\Create\Check\RequestedLivenessCheck::__construct
95+
* @covers \Yoti\DocScan\Session\Create\Check\RequestedLivenessCheck::getType
96+
* @covers \Yoti\DocScan\Session\Create\Check\RequestedLivenessCheck::getConfig
97+
*/
98+
public function shouldBuildWithStaticLivenessType()
99+
{
100+
$result = (new RequestedLivenessCheckBuilder())
101+
->forStaticLiveness()
102+
->withMaxRetries(self::SOME_MAX_RETRIES)
103+
->withoutManualCheck()
104+
->build();
105+
106+
$expected = [
107+
'type' => 'LIVENESS',
108+
'config' => [
109+
'liveness_type' => 'STATIC',
110+
'max_retries' => self::SOME_MAX_RETRIES,
111+
'manual_check' => self::NEVER,
112+
]
113+
];
114+
115+
$this->assertJsonStringEqualsJsonString(json_encode($expected), json_encode($result));
116+
}
85117
}

tests/DocScan/Session/Retrieve/ResourceContainerTest.php

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Yoti\Test\DocScan\Session\Retrieve;
66

77
use Yoti\DocScan\Session\Retrieve\ResourceContainer;
8+
use Yoti\DocScan\Session\Retrieve\StaticLivenessResourceResponse;
89
use Yoti\DocScan\Session\Retrieve\ZoomLivenessResourceResponse;
910
use Yoti\Test\TestCase;
1011

@@ -20,6 +21,8 @@ class ResourceContainerTest extends TestCase
2021
* @covers ::parseLivenessCapture
2122
* @covers ::getIdDocuments
2223
* @covers ::getLivenessCapture
24+
* @covers ::getStaticLivenessResources
25+
* @covers ::getZoomLivenessResources
2326
* @covers ::getFaceCapture
2427
* @covers ::parseFaceCapture
2528
* @covers ::parseSupplementaryDocuments
@@ -38,6 +41,7 @@ public function shouldBuildCorrectly()
3841
],
3942
'liveness_capture' => [
4043
[ 'liveness_type' => 'ZOOM' ],
44+
[ 'liveness_type' => 'STATIC' ],
4145
[ 'liveness_type' => 'someUnknownType' ],
4246
],
4347
'face_capture' => [
@@ -48,8 +52,9 @@ public function shouldBuildCorrectly()
4852
$result = new ResourceContainer($input);
4953

5054
$this->assertCount(2, $result->getIdDocuments());
51-
$this->assertCount(2, $result->getLivenessCapture());
55+
$this->assertCount(3, $result->getLivenessCapture());
5256
$this->assertCount(1, $result->getZoomLivenessResources());
57+
$this->assertCount(1, $result->getStaticLivenessResources());
5358
$this->assertCount(2, $result->getSupplementaryDocuments());
5459
$this->assertCount(1, $result->getFaceCapture());
5560
}
@@ -84,6 +89,26 @@ public function shouldHandleZoomLivenessCapture()
8489
$this->assertInstanceOf(ZoomLivenessResourceResponse::class, $result->getLivenessCapture()[0]);
8590
}
8691

92+
/**
93+
* @test
94+
* @covers ::parseLivenessCapture
95+
* @covers ::getStaticLivenessResources
96+
* @covers ::getLivenessCapture
97+
*/
98+
public function shouldHandleStaticLivenessCapture()
99+
{
100+
$input = [
101+
'liveness_capture' => [
102+
[ 'liveness_type' => 'STATIC' ]
103+
],
104+
];
105+
106+
$result = new ResourceContainer($input);
107+
108+
$this->assertCount(1, $result->getLivenessCapture());
109+
$this->assertInstanceOf(StaticLivenessResourceResponse::class, $result->getLivenessCapture()[0]);
110+
}
111+
87112
/**
88113
* @test
89114
* @covers ::getZoomLivenessResources
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
namespace Yoti\Test\DocScan\Session\Retrieve;
4+
5+
use Yoti\DocScan\Session\Retrieve\MediaResponse;
6+
use Yoti\DocScan\Session\Retrieve\StaticLivenessResourceResponse;
7+
use Yoti\Test\TestCase;
8+
9+
/**
10+
* @coversDefaultClass \Yoti\DocScan\Session\Retrieve\StaticLivenessResourceResponse
11+
*/
12+
class StaticLivenessResourceResponseTest extends TestCase
13+
{
14+
private const SOME_LIVENESS_TYPE = 'someLivenessType';
15+
private const SOME_ID = '493ru49358gh945fh305';
16+
17+
/**
18+
* @test
19+
* @covers ::__construct
20+
* @covers ::getLivenessType
21+
* @covers ::getImage
22+
*/
23+
public function shouldBuildCorrectly()
24+
{
25+
$input = [
26+
'liveness_type' => self::SOME_LIVENESS_TYPE,
27+
'image' => [
28+
'media' => [
29+
'id' => self::SOME_ID,
30+
'type' => 'IMAGE',
31+
'created' => '2021-06-11T11:39:24Z',
32+
'last_updated' => '2021-06-11T11:39:24Z',
33+
]
34+
],
35+
36+
];
37+
38+
$result = new StaticLivenessResourceResponse($input);
39+
40+
$this->assertEquals(self::SOME_LIVENESS_TYPE, $result->getLivenessType());
41+
$this->assertEquals(self::SOME_ID, $result->getImage()->getId());
42+
$this->assertNotNull($result->getImage());
43+
$this->assertInstanceOf(MediaResponse::class, $result->getImage());
44+
}
45+
46+
/**
47+
* @test
48+
* @covers ::__construct
49+
* @covers ::getLivenessType
50+
* @covers ::getImage
51+
*/
52+
public function shouldNotThrowExceptionIfMissingValues()
53+
{
54+
$result = new StaticLivenessResourceResponse([]);
55+
56+
$this->assertNull($result->getLivenessType());
57+
$this->assertNull($result->getImage());
58+
}
59+
}

0 commit comments

Comments
 (0)