Skip to content

Commit

Permalink
Fix interfaces with duplicate directives (#3674)
Browse files Browse the repository at this point in the history
Co-authored-by: Arthur Bayr <arthur.bayr@sdox.io>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Thiago Bellini Ribeiro <hackedbellini@gmail.com>
Co-authored-by: Thiago Bellini Ribeiro <thiago@bellini.dev>
  • Loading branch information
5 people authored Oct 21, 2024
1 parent 56172dc commit 9947fee
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 5 deletions.
5 changes: 5 additions & 0 deletions RELEASE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Release type: patch

This release addresses a bug where directives were being added multiple times when defined in an interface which multiple objects inherits from.

The fix involves deduplicating directives when applying extensions/permissions to a field, ensuring that each directive is only added once.
16 changes: 12 additions & 4 deletions strawberry/permission.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,19 @@ def __init__(
self.use_directives = use_directives

def apply(self, field: StrawberryField) -> None:
"""Applies all of the permission directives to the schema and sets up silent permissions."""
"""Applies all of the permission directives (deduped) to the schema and sets up silent permissions."""
if self.use_directives:
field.directives.extend(
p.schema_directive for p in self.permissions if p.schema_directive
)
permission_directives = [
perm.schema_directive
for perm in self.permissions
if perm.schema_directive
]
# Iteration, because we want to keep order
for perm_directive in permission_directives:
# Dedupe multiple directives
if perm_directive in field.directives:
continue
field.directives.append(perm_directive)
# We can only fail silently if the field is optional or a list
if self.fail_silently:
if isinstance(field.type, StrawberryOptional):
Expand Down
69 changes: 68 additions & 1 deletion tests/test_printer/test_schema_directives.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import textwrap
from enum import Enum
from typing import List, Optional, Union
from typing import Any, List, Optional, Union
from typing_extensions import Annotated

import strawberry
from strawberry import BasePermission, Info
from strawberry.permission import PermissionExtension
from strawberry.printer import print_schema
from strawberry.schema.config import StrawberryConfig
from strawberry.schema_directive import Location
Expand Down Expand Up @@ -532,6 +534,71 @@ class Query:
assert print_schema(schema) == textwrap.dedent(expected_output).strip()


def test_dedupe_multiple_equal_directives():
class MemberRoleRequired(BasePermission):
message = "Keine Rechte"

def has_permission(self, source, info: Info, **kwargs: Any) -> bool:
return True

@strawberry.interface
class MyInterface:
id: strawberry.ID

@strawberry.field(
extensions=[PermissionExtension(permissions=[MemberRoleRequired()])]
)
def hello(self, info: Info) -> str:
return "world"

@strawberry.type
class MyType1(MyInterface):
name: str

@strawberry.type
class MyType2(MyInterface):
age: int

@strawberry.type
class Query:
@strawberry.field
def my_type(self, info: Info) -> MyInterface:
return MyType1(id=strawberry.ID("1"), name="Hello")

expected_output = """
directive @memberRoleRequired on FIELD_DEFINITION
interface MyInterface {
id: ID!
hello: String! @memberRoleRequired
}
type MyType1 implements MyInterface {
id: ID!
hello: String! @memberRoleRequired
name: String!
}
type MyType2 implements MyInterface {
id: ID!
hello: String! @memberRoleRequired
age: Int!
}
type Query {
myType: MyInterface!
}
"""

schema = strawberry.Schema(Query, types=[MyType1, MyType2])

assert print_schema(schema) == textwrap.dedent(expected_output).strip()

retval = schema.execute_sync("{ myType { id hello } }")
assert retval.errors is None
assert retval.data == {"myType": {"id": "1", "hello": "world"}}


def test_print_directive_on_union():
@strawberry.type
class A:
Expand Down

0 comments on commit 9947fee

Please sign in to comment.