Skip to content

Commit

Permalink
Merge pull request #1333 from antograssiot/group-filter-whitelist
Browse files Browse the repository at this point in the history
[2.1] Allow to specify a whitelist of serialization groups for Group Filter
  • Loading branch information
dunglas committed Aug 29, 2017
2 parents 2fd1c35 + 61c12da commit 4286838
Show file tree
Hide file tree
Showing 5 changed files with 270 additions and 4 deletions.
230 changes: 229 additions & 1 deletion features/serializer/group_filter.feature
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,140 @@ Feature: Filter with serialization groups on items and collections
}
"""


Scenario: Get a collection of resources by groups dummy_foo, dummy_qux, without overriding and with whitelist
When I send a "GET" request to "/dummy_groups?whitelisted_groups[]=dummy_foo&whitelisted_groups[]=dummy_qux"
Then the response status code should be 200
And the response should be in JSON
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"
And the JSON should be valid according to this schema:
"""
{
"type": "object",
"properties": {
"@context": {"pattern": "^/contexts/DummyGroup$"},
"@id": {"pattern": "^/dummy_groups$"},
"@type": {"pattern": "^hydra:Collection$"},
"hydra:member": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"@id": {},
"@type": {},
"id": {},
"foo": {},
"bar": {},
"baz": {}
},
"additionalProperties": false,
"required": ["@id", "@type", "id", "foo", "bar", "baz"]
},
{
"type": "object",
"properties": {
"@id": {},
"@type": {},
"id": {},
"foo": {},
"bar": {},
"baz": {}
},
"additionalProperties": false,
"required": ["@id", "@type", "id", "foo", "bar", "baz"]
},
{
"type": "object",
"properties": {
"@id": {},
"@type": {},
"id": {},
"foo": {},
"bar": {},
"baz": {}
},
"additionalProperties": false,
"required": ["@id", "@type", "id", "foo", "bar", "baz"]
}
],
"additionalItems": false,
"maxItems": 3,
"minItems": 3
},
"hydra:view": {
"type": "object",
"properties": {
"@id": {"pattern": "^/dummy_groups\\?whitelisted_groups%5B%5D=dummy_foo&whitelisted_groups%5B%5D=dummy_qux&page=1$"},
"@type": {"pattern": "^hydra:PartialCollectionView$"}
}
}
}
}
"""

Scenario: Get a collection of resources by groups dummy_foo, dummy_qux with overriding and with whitelist
When I send a "GET" request to "/dummy_groups?override_whitelisted_groups[]=dummy_foo&override_whitelisted_groups[]=dummy_qux"
Then the response status code should be 200
And the response should be in JSON
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"
And the JSON should be valid according to this schema:
"""
{
"type": "object",
"properties": {
"@context": {"pattern": "^/contexts/DummyGroup$"},
"@id": {"pattern": "^/dummy_groups$"},
"@type": {"pattern": "^hydra:Collection$"},
"hydra:member": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"@id": {},
"@type": {},
"foo": {}
},
"additionalProperties": false,
"required": ["@id", "@type", "foo"]
},
{
"type": "object",
"properties": {
"@id": {},
"@type": {},
"foo": {}
},
"additionalProperties": false,
"required": ["@id", "@type", "foo"]
},
{
"type": "object",
"properties": {
"@id": {},
"@type": {},
"foo": {}
},
"additionalProperties": false,
"required": ["@id", "@type", "foo"]
}
],
"additionalItems": false,
"maxItems": 3,
"minItems": 3
},
"hydra:view": {
"type": "object",
"properties": {
"@id": {"pattern": "^/dummy_groups\\?override_whitelisted_groups%5B%5D=dummy_foo&override_whitelisted_groups%5B%5D=dummy_qux&page=1$"},
"@type": {"pattern": "^hydra:PartialCollectionView$"}
}
}
}
}
"""

Scenario: Get a collection of resources by group empty and without overriding
When I send a "GET" request to "/dummy_groups?groups[]="
Then the response status code should be 200
Expand Down Expand Up @@ -495,6 +629,49 @@ Feature: Filter with serialization groups on items and collections
}
"""

Scenario: Get a resource by groups dummy_foo, dummy_qux and without overriding and with whitelist
When I send a "GET" request to "/dummy_groups/1?whitelisted_groups[]=dummy_foo&whitelisted_groups[]=dummy_qux"
Then the response status code should be 200
And the response should be in JSON
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"
And the JSON should be valid according to this schema:
"""
{
"type": "object",
"properties": {
"@context": {"pattern": "^/contexts/DummyGroup$"},
"@id": {"pattern": "^/dummy_groups/1$"},
"@type": {"pattern": "^DummyGroup$"},
"id": {},
"foo": {},
"bar": {},
"baz": {}
},
"additionalProperties": false,
"required": ["@context", "@id", "@type", "id", "foo", "bar", "baz"]
}
"""

Scenario: Get a resource by groups dummy_foo, dummy_qux and with overriding and with whitelist
When I send a "GET" request to "/dummy_groups/1?override_whitelisted_groups[]=dummy_foo&override_whitelisted_groups[]=dummy_qux"
Then the response status code should be 200
And the response should be in JSON
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"
And the JSON should be valid according to this schema:
"""
{
"type": "object",
"properties": {
"@context": {"pattern": "^/contexts/DummyGroup$"},
"@id": {"pattern": "^/dummy_groups/1$"},
"@type": {"pattern": "^DummyGroup$"},
"foo": {}
},
"additionalProperties": false,
"required": ["@context", "@id", "@type", "foo"]
}
"""

Scenario: Get a resource by group empty and without overriding
When I send a "GET" request to "/dummy_groups/1?groups[]="
Then the response status code should be 200
Expand Down Expand Up @@ -725,7 +902,6 @@ Feature: Filter with serialization groups on items and collections
}
"""

@dropSchema
Scenario: Create a resource by group empty and with overriding
When I add "Content-Type" header equal to "application/ld+json"
And I send a "POST" request to "/dummy_groups?override_groups[]=" with body:
Expand All @@ -748,3 +924,55 @@ Feature: Filter with serialization groups on items and collections
"@type": "DummyGroup"
}
"""

Scenario: Create a resource by groups dummy, dummy_baz, without overriding and with whitelist
When I add "Content-Type" header equal to "application/ld+json"
And I send a "POST" request to "/dummy_groups?whitelisted_groups[]=dummy&whitelisted_groups[]=dummy_baz" with body:
"""
{
"foo": "Foo",
"bar": "Bar",
"baz": "Baz",
"qux": "Qux"
}
"""
Then the response status code should be 201
And the response should be in JSON
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"
And the JSON should be equal to:
"""
{
"@context": "\/contexts\/DummyGroup",
"@id": "\/dummy_groups\/19",
"@type": "DummyGroup",
"id": 19,
"foo": "Foo",
"bar": "Bar",
"baz": "Baz"
}
"""

@dropSchema
Scenario: Create a resource by groups dummy, dummy_baz, with overriding and with whitelist
When I add "Content-Type" header equal to "application/ld+json"
And I send a "POST" request to "/dummy_groups?override_whitelisted_groups[]=dummy&override_whitelisted_groups[]=dummy_baz" with body:
"""
{
"foo": "Foo",
"bar": "Bar",
"baz": "Baz",
"qux": "Qux"
}
"""
Then the response status code should be 201
And the response should be in JSON
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"
And the JSON should be equal to:
"""
{
"@context": "\/contexts\/DummyGroup",
"@id": "\/dummy_groups\/20",
"@type": "DummyGroup",
"baz": "Baz"
}
"""
8 changes: 6 additions & 2 deletions src/Serializer/Filter/GroupFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@ final class GroupFilter implements FilterInterface
{
private $overrideDefaultGroups;
private $parameterName;
private $whitelist;

public function __construct(string $parameterName = 'groups', bool $overrideDefaultGroups = false)
public function __construct(string $parameterName = 'groups', bool $overrideDefaultGroups = false, array $whitelist = null)
{
$this->overrideDefaultGroups = $overrideDefaultGroups;
$this->parameterName = $parameterName;
$this->whitelist = $whitelist;
}

/**
Expand All @@ -39,7 +41,9 @@ public function apply(Request $request, bool $normalization, array $attributes,
if (!is_array($groups = $request->query->get($this->parameterName))) {
return;
}

if (null !== $this->whitelist) {
$groups = array_intersect($this->whitelist, $groups);
}
if (!$this->overrideDefaultGroups && isset($context['groups'])) {
$groups = array_merge((array) $context['groups'], $groups);
}
Expand Down
4 changes: 3 additions & 1 deletion tests/Fixtures/TestBundle/Entity/DummyGroup.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@
* "denormalization_context"={"groups"={"dummy_write"}},
* "filters"={
* "dummy_group.group",
* "dummy_group.override_group"
* "dummy_group.override_group",
* "dummy_group.whitelist_group",
* "dummy_group.override_whitelist_group"
* }
* })
*/
Expand Down
10 changes: 10 additions & 0 deletions tests/Fixtures/app/config/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,16 @@ services:
arguments: [ 'override_groups', true ]
tags: [ { name: 'api_platform.filter', id: 'dummy_group.override_group' } ]

app.entity.filter.dummy_group.whitelist_group:
parent: 'api_platform.serializer.group_filter'
arguments: [ 'whitelisted_groups', false, ['dummy_foo', 'dummy_baz'] ]
tags: [ { name: 'api_platform.filter', id: 'dummy_group.whitelist_group' } ]

app.entity.filter.dummy_group.override_whitelist_group:
parent: 'api_platform.serializer.group_filter'
arguments: [ 'override_whitelisted_groups', true, ['dummy_foo', 'dummy_baz'] ]
tags: [ { name: 'api_platform.filter', id: 'dummy_group.override_whitelist_group' } ]

app.related_dummy_resource.search_filter:
parent: 'api_platform.doctrine.orm.search_filter'
arguments: [ { 'relatedToDummyFriend.dummyFriend': 'exact', 'name': 'partial' } ]
Expand Down
22 changes: 22 additions & 0 deletions tests/Serializer/Filter/GroupFilterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,28 @@ public function testApplyWithoutGroupsInRequest()
$this->assertEquals(['groups' => ['foo', 'bar']], $context);
}

public function testApplyWithGroupsWhitelist()
{
$request = new Request(['groups' => ['foo', 'bar', 'baz']]);
$context = ['groups' => 'qux'];

$groupFilter = new GroupFilter('groups', false, ['foo', 'baz']);
$groupFilter->apply($request, true, [], $context);

$this->assertEquals(['groups' => ['qux', 'foo', 'baz']], $context);
}

public function testApplyWithGroupsWhitelistWithOverriding()
{
$request = new Request(['groups' => ['foo', 'bar', 'baz']]);
$context = ['groups' => 'qux'];

$groupFilter = new GroupFilter('groups', true, ['foo', 'baz']);
$groupFilter->apply($request, true, [], $context);

$this->assertEquals(['groups' => ['foo', 'baz']], $context);
}

public function testApplyWithInvalidGroupsInRequest()
{
$request = new Request(['groups' => 'foo,bar,baz']);
Expand Down

0 comments on commit 4286838

Please sign in to comment.