Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatically create nested R object rules if required #1

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions bridgekeeper/rule_r_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,36 @@ def test_nested_rule_object():
assert shrubbery_nomatch not in qs


def test_nested_one_to_many_rule_object():
user = UserFactory()

shrubbery_match = ShrubberyFactory(branch=user.profile.branch)
shrubbery_nomatch = ShrubberyFactory()
branch_profile_check_r = R(branch=R(profile=R(user=lambda user: user)))

assert branch_profile_check_r.check(user, shrubbery_match)
assert not branch_profile_check_r.check(user, shrubbery_nomatch)

qs = branch_profile_check_r.filter(user, Shrubbery.objects.all())
assert shrubbery_match in qs
assert shrubbery_nomatch not in qs


def test_unnested_one_to_many_rule_object():
user = UserFactory()

shrubbery_match = ShrubberyFactory(branch=user.profile.branch)
shrubbery_nomatch = ShrubberyFactory()
branch_profile_check_r = R(branch__profile__user=lambda user: user)

assert branch_profile_check_r.check(user, shrubbery_match)
assert not branch_profile_check_r.check(user, shrubbery_nomatch)

qs = branch_profile_check_r.filter(user, Shrubbery.objects.all())
assert shrubbery_match in qs
assert shrubbery_nomatch not in qs


def test_many_relation_to_user():
s1 = StoreFactory()
s2 = StoreFactory()
Expand Down
10 changes: 9 additions & 1 deletion bridgekeeper/rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,15 @@ def check(self, user, instance=None):
# Find the appropriate LHS on this object, traversing
# foreign keys if necessary.
lhs = instance
for key_fragment in key.split("__"):
fragments = key.split("__")
for i, key_fragment in enumerate(fragments):
# Catch a many-to-many or many-to-one traversal and split it
# across multiple Rules
if not hasattr(lhs.__class__, "_meta"):
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect there is a better way to detect this (like possibly even just if isinstance(lhs, Manager): as is used further down

new_kwargs = {"__".join(fragments[i:]): value}
value = R(**new_kwargs)
break

field = lhs.__class__._meta.get_field(key_fragment,)
if isinstance(field, ForeignObjectRel):
attr = field.get_accessor_name()
Expand Down