Skip to content

Commit 8a4e80b

Browse files
authored
Merge pull request #124 from norkunas/new-apis
Add new api endpoints
2 parents 1240f5f + 1402712 commit 8a4e80b

File tree

10 files changed

+323
-2
lines changed

10 files changed

+323
-2
lines changed

src/Apps.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,38 @@ public function update($id, array $data)
8282
'Authorization' => 'Basic '.$this->api->getConfig()->getUserAuthKey(),
8383
], json_encode($data));
8484
}
85+
86+
/**
87+
* Create a new segment for application with provided data.
88+
*
89+
* @param string $appId ID of your application
90+
* @param array $data Segment Data
91+
*
92+
* @return array
93+
*/
94+
public function createSegment($appId, array $data)
95+
{
96+
$data = $this->resolverFactory->createSegmentResolver()->resolve($data);
97+
98+
return $this->api->request('POST', '/apps/'.$appId.'/segments', [
99+
'Authorization' => 'Basic '.$this->api->getConfig()->getApplicationAuthKey(),
100+
], json_encode($data));
101+
}
102+
103+
/**
104+
* Delete existing segment from your application.
105+
*
106+
* Application auth key must be set.
107+
*
108+
* @param string $appId Application ID
109+
* @param string $segmentId Segment ID
110+
*
111+
* @return array
112+
*/
113+
public function deleteSegment($appId, $segmentId)
114+
{
115+
return $this->api->request('DELETE', '/apps/'.$appId.'/segments/'.$segmentId, [
116+
'Authorization' => 'Basic '.$this->api->getConfig()->getApplicationAuthKey(),
117+
]);
118+
}
85119
}

src/Notifications.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,4 +113,26 @@ public function cancel($id)
113113
'Authorization' => 'Basic '.$this->api->getConfig()->getApplicationAuthKey(),
114114
]);
115115
}
116+
117+
/**
118+
* View the devices sent a notification.
119+
*
120+
* Application authentication key and ID must be set.
121+
*
122+
* @param string $id Notification ID
123+
* @param array $data
124+
*
125+
* @return array
126+
*/
127+
public function history($id, array $data)
128+
{
129+
$url = '/notifications/'.$id.'/history?app_id='.$this->api->getConfig()->getApplicationId();
130+
131+
$data = $this->resolverFactory->createNotificationResolver()->resolve($data);
132+
133+
return $this->api->request('POST', $url, [
134+
'Authorization' => 'Basic '.$this->api->getConfig()->getApplicationAuthKey(),
135+
'Cache-Control' => 'no-cache',
136+
], json_encode($data));
137+
}
116138
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace OneSignal\Resolver;
4+
5+
use Symfony\Component\OptionsResolver\OptionsResolver;
6+
7+
class NotificationHistoryResolver implements ResolverInterface
8+
{
9+
/**
10+
* {@inheritdoc}
11+
*/
12+
public function resolve(array $data)
13+
{
14+
return (new OptionsResolver())
15+
->setRequired('events')
16+
->setAllowedTypes('events', 'string')
17+
->setAllowedValues('events', ['sent', 'clicked'])
18+
->setRequired('email')
19+
->setAllowedTypes('email', 'string')
20+
->resolve($data);
21+
}
22+
}

src/Resolver/ResolverFactory.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ public function createAppResolver()
1818
return new AppResolver();
1919
}
2020

21+
public function createSegmentResolver()
22+
{
23+
return new SegmentResolver();
24+
}
25+
2126
public function createDeviceSessionResolver()
2227
{
2328
return new DeviceSessionResolver();
@@ -47,4 +52,9 @@ public function createNotificationResolver()
4752
{
4853
return new NotificationResolver($this->config);
4954
}
55+
56+
public function createNotificationHistoryResolver()
57+
{
58+
return new NotificationHistoryResolver();
59+
}
5060
}

src/Resolver/SegmentResolver.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
namespace OneSignal\Resolver;
4+
5+
use Symfony\Component\OptionsResolver\Options;
6+
use Symfony\Component\OptionsResolver\OptionsResolver;
7+
8+
class SegmentResolver implements ResolverInterface
9+
{
10+
/**
11+
* {@inheritdoc}
12+
*/
13+
public function resolve(array $data)
14+
{
15+
return (new OptionsResolver())
16+
->setDefined('id')
17+
->setAllowedTypes('id', 'string')
18+
->setRequired('name')
19+
->setAllowedTypes('name', 'string')
20+
->setDefined('filters')
21+
->setAllowedTypes('filters', 'array')
22+
->setNormalizer('filters', function (Options $options, array $values) {
23+
return $this->normalizeFilters($options, $values);
24+
})
25+
->resolve($data);
26+
}
27+
28+
private function normalizeFilters(Options $options, array $values)
29+
{
30+
$filters = [];
31+
32+
foreach ($values as $filter) {
33+
if (isset($filter['field']) || isset($filter['operator'])) {
34+
$filters[] = $filter;
35+
}
36+
}
37+
38+
return $filters;
39+
}
40+
}

tests/OneSignal/Tests/AbstractApiTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ abstract class AbstractApiTest extends TestCase
1717
protected $api;
1818

1919
/**
20-
* @var ResolverFactory
20+
* @var ResolverFactory|\PHPUnit_Framework_MockObject_MockObject
2121
*/
2222
protected $resolverFactory;
2323

@@ -28,7 +28,7 @@ public function setUp()
2828

2929
$resolverFactory = $this->createMock(ResolverFactory::class);
3030
$resolverMethods = array_filter(get_class_methods($resolverFactory), function ($method) {
31-
return strpos($method, 'create') === 0;
31+
return 0 === strpos($method, 'create');
3232
});
3333
foreach ($resolverMethods as $method) {
3434
$resolverFactory->method($method)->willReturn($mockResolver);

tests/OneSignal/Tests/AppsTest.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,32 @@ public function testUpdate()
6969
$this->resolverFactory->expects($this->once())->method('createAppResolver');
7070
$this->assertEquals($expectedRequest, $this->apps->update($fakeId, ['data' => 'myData']));
7171
}
72+
73+
public function testCreateSegment()
74+
{
75+
$fakeAppId = '85f0e7eb-df11-4a86-ab5a-603a6c0a14c6';
76+
$expectedRequest = [
77+
'POST',
78+
'/apps/'.$fakeAppId.'/segments',
79+
['Authorization' => 'Basic fakeApplicationAuthKey'],
80+
'{"id":"52d5a7cb-59fe-4d0c-a0b9-9a39a21475ad","name":"Custom Segment","filters":[{"field":"session_count","relation":">","value":"1"},{"operator":"AND"},{"field":"tag","relation":"!=","key":"tag_key","value":"1"},{"operator":"OR"},{"field":"last_session","relation":"<","value":"30"}]}',
81+
];
82+
83+
$this->resolverFactory->expects($this->once())->method('createSegmentResolver');
84+
$this->assertEquals($expectedRequest, $this->apps->createSegment($fakeAppId, ['id' => '52d5a7cb-59fe-4d0c-a0b9-9a39a21475ad', 'name' => 'Custom Segment', 'filters' => [['field' => 'session_count', 'relation' => '>', 'value' => '1'], ['operator' => 'AND'], ['field' => 'tag', 'relation' => '!=', 'key' => 'tag_key', 'value' => '1'], ['operator' => 'OR'], ['field' => 'last_session', 'relation' => '<', 'value' => '30']]]));
85+
}
86+
87+
public function testDeleteSegment()
88+
{
89+
$fakeAppId = '85f0e7eb-df11-4a86-ab5a-603a6c0a14c6';
90+
$fakeSegmentId = 'a98c618f-f680-4b3a-9cdd-0957873c13b6';
91+
$expectedRequest = [
92+
'DELETE',
93+
'/apps/'.$fakeAppId.'/segments/'.$fakeSegmentId,
94+
['Authorization' => 'Basic fakeApplicationAuthKey'],
95+
null,
96+
];
97+
98+
$this->assertEquals($expectedRequest, $this->apps->deleteSegment($fakeAppId, $fakeSegmentId));
99+
}
72100
}

tests/OneSignal/Tests/NotificationsTest.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,17 @@ public function testCancel()
8181

8282
$this->assertEquals($expectedRequest, $this->notifications->cancel($fakeId));
8383
}
84+
85+
public function testHistory()
86+
{
87+
$fakeId = 1234;
88+
$expectedRequest = [
89+
'POST',
90+
'/notifications/'.$fakeId.'/history?app_id=fakeApplicationId',
91+
['Authorization' => 'Basic fakeApplicationAuthKey', 'Cache-Control' => 'no-cache'],
92+
'{"events":"sent","email":"example@example.com"}',
93+
];
94+
95+
$this->assertEquals($expectedRequest, $this->notifications->history($fakeId, ['events' => 'sent', 'email' => 'example@example.com']));
96+
}
8497
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
namespace OneSignal\Tests\Resolver;
4+
5+
use OneSignal\Resolver\NotificationHistoryResolver;
6+
use PHPUnit\Framework\TestCase;
7+
8+
class NotificationHistoryResolverTest extends TestCase
9+
{
10+
/**
11+
* @var NotificationHistoryResolver
12+
*/
13+
private $notificationHistoryResolver;
14+
15+
public function setUp()
16+
{
17+
$this->notificationHistoryResolver = new NotificationHistoryResolver();
18+
}
19+
20+
public function testResolveWithValidValues()
21+
{
22+
$expectedData = [
23+
'events' => 'sent',
24+
'email' => 'example@example.com',
25+
];
26+
27+
$this->assertEquals($expectedData, $this->notificationHistoryResolver->resolve($expectedData));
28+
}
29+
30+
/**
31+
* @expectedException \Symfony\Component\OptionsResolver\Exception\MissingOptionsException
32+
*/
33+
public function testResolveWithMissingRequiredValue()
34+
{
35+
$this->notificationHistoryResolver->resolve([]);
36+
}
37+
38+
public function wrongValueTypesProvider()
39+
{
40+
return [
41+
[['events' => 666, 'email' => 'example@example.com']],
42+
[['events' => 'sent', 'email' => 666]],
43+
];
44+
}
45+
46+
/**
47+
* @dataProvider wrongValueTypesProvider
48+
* @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
49+
*/
50+
public function testResolveWithWrongValueTypes($wrongOption)
51+
{
52+
$this->notificationHistoryResolver->resolve($wrongOption);
53+
}
54+
55+
/**
56+
* @expectedException \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException
57+
*/
58+
public function testResolveWithWrongOption()
59+
{
60+
$this->notificationHistoryResolver->resolve(['events' => 'sent', 'wrongOption' => 'wrongValue']);
61+
}
62+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<?php
2+
3+
namespace OneSignal\Tests\Resolver;
4+
5+
use OneSignal\Resolver\SegmentResolver;
6+
use OneSignal\Tests\PrivateAccessorTrait;
7+
use PHPUnit\Framework\TestCase;
8+
use Symfony\Component\OptionsResolver\OptionsResolver;
9+
10+
class SegmentResolverTest extends TestCase
11+
{
12+
use PrivateAccessorTrait;
13+
14+
/**
15+
* @var SegmentResolver
16+
*/
17+
private $segmentResolver;
18+
19+
public function setUp()
20+
{
21+
$this->segmentResolver = new SegmentResolver();
22+
}
23+
24+
public function testResolveWithValidValues()
25+
{
26+
$expectedData = [
27+
'id' => '52d5a7cb-59fe-4d0c-a0b9-9a39a21475ad',
28+
'name' => 'Custom Segment',
29+
'filters' => [],
30+
];
31+
32+
$this->assertEquals($expectedData, $this->segmentResolver->resolve($expectedData));
33+
}
34+
35+
public function wrongValueTypesProvider()
36+
{
37+
return [
38+
[['id' => 666, 'name' => '']],
39+
[['name' => 666]],
40+
[['filters' => 666, 'name' => '']],
41+
];
42+
}
43+
44+
/**
45+
* @dataProvider wrongValueTypesProvider
46+
* @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
47+
*/
48+
public function testResolveWithWrongValueTypes($wrongOption)
49+
{
50+
$this->segmentResolver->resolve($wrongOption);
51+
}
52+
53+
/**
54+
* @expectedException \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException
55+
*/
56+
public function testResolveWithWrongOption()
57+
{
58+
$this->segmentResolver->resolve(['wrongOption' => 'wrongValue']);
59+
}
60+
61+
/****** Private functions testing ******/
62+
63+
public function testNormalizeFilters()
64+
{
65+
$method = $this->getPrivateMethod(SegmentResolver::class, 'normalizeFilters');
66+
67+
$inputData = [
68+
new OptionsResolver(),
69+
[
70+
['wrongField' => 'wrongValue'],
71+
['field' => 'session_count', 'relation' => '>', 'value' => '1'],
72+
['operator' => 'AND'],
73+
['field' => 'tag', 'relation' => '!=', 'key' => 'tag_key', 'value' => '1'],
74+
['operator' => 'OR'],
75+
['field' => 'last_session', 'relation' => '<', 'value' => '30'],
76+
],
77+
];
78+
79+
$expectedData =
80+
[
81+
['field' => 'session_count', 'relation' => '>', 'value' => '1'],
82+
['operator' => 'AND'],
83+
['field' => 'tag', 'relation' => '!=', 'key' => 'tag_key', 'value' => '1'],
84+
['operator' => 'OR'],
85+
['field' => 'last_session', 'relation' => '<', 'value' => '30'],
86+
];
87+
88+
$this->assertEquals($expectedData, $method->invokeArgs($this->segmentResolver, $inputData));
89+
}
90+
}

0 commit comments

Comments
 (0)