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

Search sensors in API by asset #1219

Open
wants to merge 24 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
2d00ca5
feat: limit sensor api search to asset
joshuaunity Oct 22, 2024
e03759f
chore: added to changelog
joshuaunity Oct 23, 2024
7db6d45
chore: modify changelog
joshuaunity Oct 28, 2024
a69a924
refactor: removed extra permission checks and added extra filter layer
joshuaunity Oct 28, 2024
90e2c77
chore: added test for filtering by asset id
joshuaunity Oct 28, 2024
23ac6e2
refactor: all_accessible sesnor logic revamp
joshuaunity Oct 28, 2024
954962d
Merge branch 'main' into limit-sensors-search
joshuaunity Oct 29, 2024
37be8a8
refactor: updated query param name, logic and docstring
joshuaunity Oct 29, 2024
e9ce0b0
refactor: modified child asset query to be recursive
joshuaunity Oct 30, 2024
0d95d98
refactor: more concise query
joshuaunity Oct 30, 2024
c9dc708
refactor: extend test case
joshuaunity Oct 31, 2024
366568b
chore: recommiting
joshuaunity Oct 31, 2024
44a8aff
chore: update doc string
joshuaunity Oct 31, 2024
613e776
refactor: update test case for post sensor
joshuaunity Nov 1, 2024
9a391e9
refactor: update test case for post sensor v2
joshuaunity Nov 1, 2024
4bb8394
chore: pushing a suggestion
joshuaunity Nov 1, 2024
55bcf65
refactor: updated access logic for sensor index API
joshuaunity Nov 1, 2024
6dd2073
chore: updated test case due to change in sensor index API
joshuaunity Nov 1, 2024
49950b2
chore: update doc string and logic hierachy
joshuaunity Nov 1, 2024
e6cd1ea
refactor: updated logic and test case extentsion
joshuaunity Nov 4, 2024
5d0a626
chore: update docstring and added extra testcase
joshuaunity Nov 4, 2024
c794929
chore: added else statement
joshuaunity Nov 4, 2024
0c21942
chore: update testcase
joshuaunity Nov 4, 2024
6a71600
chore: test logic update
joshuaunity Nov 4, 2024
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 documentation/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ New features
* Speed up loading the accounts page,by making the pagination backend-based and adding support for that in the API [see `PR #1196 <https://github.com/FlexMeasures/flexmeasures/pull/1196>`_]
* Speed up loading the account detail page by by switching to server-side pagination for assets, replacing client-side pagination [see `PR #1202 <https://github.com/FlexMeasures/flexmeasures/pull/1202>`_]
* Simplify and Globalize toasts in the flexmeasures project [see `PR #1207 <https://github.com/FlexMeasures/flexmeasures/pull/1207>_`]
* Enhanced API for listing sensors: Added option to filter by asset ID [see `PR #1219 <https://github.com/FlexMeasures/flexmeasures/pull/1219>_`]
joshuaunity marked this conversation as resolved.
Show resolved Hide resolved

Infrastructure / Support
----------------------
Expand Down
49 changes: 44 additions & 5 deletions flexmeasures/api/v3_0/sensors.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
from flexmeasures.data.models.time_series import Sensor, TimedBelief
from flexmeasures.data.queries.utils import simplify_index
from flexmeasures.data.schemas.sensors import SensorSchema, SensorIdField
from flexmeasures.data.schemas import AssetIdField
from flexmeasures.api.common.schemas.search import SearchFilterField
from flexmeasures.api.common.schemas.sensors import UnitField
from flexmeasures.data.schemas.times import AwareDateTimeField, PlanningDurationField
Expand Down Expand Up @@ -69,7 +70,9 @@ class SensorAPI(FlaskView):
"account": AccountIdField(
data_key="account_id", load_default=AccountIdField.load_current
joshuaunity marked this conversation as resolved.
Show resolved Hide resolved
),
"all_accessible": fields.Boolean(required=False, missing=False),
"asset": AssetIdField(data_key="asset_id", required=False),
"all_accessible": fields.Boolean(required=False, load_default=False),
"include_public_assets": fields.Boolean(required=False, load_default=False),
"page": fields.Int(
required=False, validate=validate.Range(min=1), default=1
),
Expand All @@ -86,7 +89,9 @@ class SensorAPI(FlaskView):
def index(
self,
account: Account,
asset: GenericAsset | None = None,
all_accessible: bool = False,
include_public_assets: bool = False,
page: int | None = None,
per_page: int | None = None,
filter: list[str] | None = None,
Expand All @@ -97,11 +102,25 @@ def index(
.. :quickref: Sensor; Download sensor list

This endpoint returns all accessible sensors.
Accessible sensors are sensors in the same account as the current user.
Alternatively, you can use the `all_accessible` query parameter to list sensors from all assets that the `current_user` has read access to, as well as all public assets. The default value is `false`.
By default, "accessible sensors" means all sensors in the same account as the current user (if they have read permission to the account).

You can also specify any other `account` (an ID parameter), if the user has read-access to that.
Alternatively to filtering by account, we can filter by asset tree. If you send the `asset` parameter (an ID), then all sensors on that asset or its sub-assets are looked up (if the user has read access to that asset).

In any of the two custom filtering cases above, you can
- not filter by both account and asset, as that is not useful - if the asset is not part of the specified account, a 422 error is raised.
- add the parameter flag `include_public_assets`, which adds sensors under public assets, as well. The default value is `false`.

Finally, you can simply use the powerful `all_accessible` parameter to list sensors from all assets that the `current_user` has read access to, (across accounts and assets), as well as all public assets. The default value is `false`.

Only admins can use this endpoint to fetch sensors from a different account (by using the `account_id` query parameter).

The `filter` parameter allows you to search for sensors by name or account name.
The `unit` parameter allows you to filter by unit.

For the pagination of the sensor list, you can use the `page` and `per_page` query parameters, the `page` parameter is used to trigger
pagination, and the `per_page` parameter is used to specify the number of records per page. The default value for `page` is 1 and for `per_page` is 10.

**Example response**

An example of one sensor being returned:
Expand Down Expand Up @@ -139,15 +158,35 @@ def index(
accounts = account
else:
accounts: list = [account] if account else []

accounts = [
account for account in accounts if check_access(account, "read") is None
joshuaunity marked this conversation as resolved.
Show resolved Hide resolved
]
account_ids: list = [acc.id for acc in accounts]

filter_statement = GenericAsset.account_id.in_(account_ids)
if asset and asset.account_id not in account_ids:
joshuaunity marked this conversation as resolved.
Show resolved Hide resolved
return {"message": "Asset does not belong to the account"}, 422

if all_accessible is not None:
if asset is not None:
joshuaunity marked this conversation as resolved.
Show resolved Hide resolved
child_assets = (
db.session.query(GenericAsset)
.filter(GenericAsset.parent_asset_id == asset.id)
.all()
)
filter_statement = GenericAsset.id.in_(
[asset.id] + [a.id for a in child_assets]
)
else:
filter_statement = GenericAsset.account_id.in_(account_ids)

if all_accessible:
consultancy_account_ids: list = [
acc.consultancy_account_id for acc in accounts
]
account_ids.extend(consultancy_account_ids)

if include_public_assets or all_accessible:

filter_statement = or_(
filter_statement,
GenericAsset.account_id.is_(None),
Expand Down
Loading