Skip to content
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- FlowDB now enables partitionwise aggregation planning by default

### Fixed
- Queries that have multiple of the same subquery with different parameters no longer cause duplicate scopes in tokens. [#6580](https://github.com/Flowminder/FlowKit/issues/6580)

### Removed

Expand Down
20 changes: 11 additions & 9 deletions flowapi/flowapi/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,21 +72,21 @@ def grab_on_key_list(in_iter, search_keys):
@grab_on_key_list.register
def _(in_iter: dict, search_keys: list):
for key, value in in_iter.items():
try:
yield _search_for_nested_keys(in_iter, search_keys)
except (KeyError, TypeError):
pass
yield from grab_on_key_list(value, search_keys)
try:
yield _search_for_nested_keys(in_iter, search_keys)
except (KeyError, TypeError):
pass


@grab_on_key_list.register
def _(in_iter: list, search_keys: list):
for value in in_iter:
try:
yield _search_for_nested_keys(value, search_keys)
except (KeyError, TypeError):
pass
yield from grab_on_key_list(value, search_keys)
try:
yield _search_for_nested_keys(value, search_keys)
except (KeyError, TypeError):
pass


def _search_for_nested_keys(in_iter: dict, search_keys: Any) -> Any:
Expand Down Expand Up @@ -210,7 +210,9 @@ async def query_to_scopes(query_dict):
except Exception:
raise BadQueryError
agg_unit = await get_agg_unit(query_dict)
return [f"{agg_unit}:{tl_query_name}:{query_name}" for query_name in query_list]
return list(
Copy link
Member

Choose a reason for hiding this comment

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

Do we need this to be a list, or could we return a set instead? (I don't think it matters much either way, but if we return a set it's perhaps clearer that the scopes will be non-duplicated)

Copy link
Contributor Author

@Thingus Thingus May 9, 2024

Choose a reason for hiding this comment

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

It's compared to other lists when we check it against the requested scopes; now I say that, a set would be better there too, but that probably belongs in a different PR

set(f"{agg_unit}:{tl_query_name}:{query_name}" for query_name in query_list)
)


def tl_schema_scope_string(tl_query, query_string) -> set:
Expand Down
28 changes: 28 additions & 0 deletions flowapi/tests/unit/test_permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import prance
import quart
from flowapi import permissions
from flowapi.permissions import (
query_to_scopes,
tl_schema_scope_string,
schema_to_scopes,
grab_on_key_list,
Expand Down Expand Up @@ -147,6 +149,32 @@ def test_scopes_from_query():
}
assert tl_schema_scope_string(tl_query, input) == expected

# TODO Test that params dedupe properly


async def test_query_dedupes(monkeypatch):
async def mock_get_agg_unit(query_dict):
return "dummy_agg_unit"

monkeypatch.setattr(permissions, "get_agg_unit", mock_get_agg_unit)
input = dict(
query_kind="test",
aggregation_unit="dummy_agg_unit",
sub_param_1=dict(
query_kind="dummy_query",
aggregation_unit="dummy_agg_unit",
date="2020/01/01",
),
sub_param_2=dict(
query_kind="dummy_query",
aggregation_unit="dummy_agg_unit",
date="2020/01/02",
),
)
expected = ["dummy_agg_unit:test:test", "dummy_agg_unit:test:dummy_query"]
result = await query_to_scopes(input)
assert sorted(expected) == sorted(result)


def test_grab_on_key_list():
input = {"1": [{}, {}, {"3": "success"}]}
Expand Down