Skip to content

Commit 8e1c14e

Browse files
authored
fix: Allow querying for reviews with neither reviewed/unreviewed. (#1040)
1 parent f115846 commit 8e1c14e

File tree

4 files changed

+159
-7
lines changed

4 files changed

+159
-7
lines changed

custom_components/frigate/api.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ async def async_get_reviews(
133133
after: float | None = None,
134134
before: float | None = None,
135135
limit: int | None = None,
136-
reviewed: bool = False,
136+
reviewed: bool | None = None,
137137
decode_json: bool = True,
138138
) -> list[dict[str, Any]]:
139139
"""Get review items from the API."""
@@ -145,7 +145,7 @@ async def async_get_reviews(
145145
"after": after,
146146
"before": before,
147147
"limit": limit,
148-
"reviewed": int(reviewed),
148+
"reviewed": int(reviewed) if reviewed is not None else None,
149149
}
150150

151151
return cast(

custom_components/frigate/ws_api.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ async def ws_get_reviews(
249249
msg.get("after"),
250250
msg.get("before"),
251251
msg.get("limit"),
252-
msg.get("reviewed", False),
252+
msg.get("reviewed"),
253253
decode_json=False,
254254
),
255255
)

tests/test_api.py

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -928,10 +928,10 @@ async def test_async_get_classification_model_classes_api_error(
928928
assert result == []
929929

930930

931-
async def test_async_get_reviews(
931+
async def test_async_get_reviews_unreviewed(
932932
aiohttp_session: aiohttp.ClientSession, aiohttp_server: Any
933933
) -> None:
934-
"""Test async_get_reviews."""
934+
"""Test async_get_reviews with reviewed=False (unreviewed only)."""
935935
reviews_in = [
936936
{
937937
"id": "1735000000.123456-abc123",
@@ -978,6 +978,82 @@ async def reviews_handler(request: web.Request) -> web.Response:
978978
)
979979

980980

981+
async def test_async_get_reviews_reviewed(
982+
aiohttp_session: aiohttp.ClientSession, aiohttp_server: Any
983+
) -> None:
984+
"""Test async_get_reviews with reviewed=True (reviewed only)."""
985+
reviews_in = [
986+
{
987+
"id": "1735000000.123456-abc123",
988+
"camera": "front_door",
989+
"start_time": 1735000000.0,
990+
"end_time": 1735000060.0,
991+
"severity": "alert",
992+
"thumb_path": "/media/frigate/clips/review/thumb.webp",
993+
"data": {"detections": ["person"], "objects": ["person"]},
994+
}
995+
]
996+
997+
async def reviews_handler(request: web.Request) -> web.Response:
998+
"""Reviews handler."""
999+
_assert_request_params(
1000+
request,
1001+
{
1002+
"cameras": "test_camera",
1003+
"reviewed": "1",
1004+
},
1005+
)
1006+
return web.json_response(reviews_in)
1007+
1008+
server = await start_frigate_server(
1009+
aiohttp_server, [web.get("/api/review", reviews_handler)]
1010+
)
1011+
1012+
frigate_client = FrigateApiClient(str(server.make_url("/")), aiohttp_session)
1013+
assert reviews_in == await frigate_client.async_get_reviews(
1014+
cameras=["test_camera"],
1015+
reviewed=True,
1016+
)
1017+
1018+
1019+
async def test_async_get_reviews_no_filter(
1020+
aiohttp_session: aiohttp.ClientSession, aiohttp_server: Any
1021+
) -> None:
1022+
"""Test async_get_reviews with reviewed=None (all reviews, no filter)."""
1023+
reviews_in = [
1024+
{
1025+
"id": "1735000000.123456-abc123",
1026+
"camera": "front_door",
1027+
"start_time": 1735000000.0,
1028+
"end_time": 1735000060.0,
1029+
"severity": "alert",
1030+
"thumb_path": "/media/frigate/clips/review/thumb.webp",
1031+
"data": {"detections": ["person"], "objects": ["person"]},
1032+
}
1033+
]
1034+
1035+
async def reviews_handler(request: web.Request) -> web.Response:
1036+
"""Reviews handler - should NOT have 'reviewed' param."""
1037+
# Verify 'reviewed' is NOT in the query params
1038+
assert "reviewed" not in request.query
1039+
_assert_request_params(
1040+
request,
1041+
{
1042+
"cameras": "test_camera",
1043+
},
1044+
)
1045+
return web.json_response(reviews_in)
1046+
1047+
server = await start_frigate_server(
1048+
aiohttp_server, [web.get("/api/review", reviews_handler)]
1049+
)
1050+
1051+
frigate_client = FrigateApiClient(str(server.make_url("/")), aiohttp_session)
1052+
assert reviews_in == await frigate_client.async_get_reviews(
1053+
cameras=["test_camera"],
1054+
)
1055+
1056+
9811057
async def test_async_set_reviews_viewed(
9821058
aiohttp_session: aiohttp.ClientSession, aiohttp_server: Any
9831059
) -> None:

tests/test_ws_api.py

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -657,8 +657,10 @@ async def test_unload_unsubscribes_from_events(
657657
response = await ws_client.receive_json()
658658

659659

660-
async def test_get_reviews_success(hass: HomeAssistant, hass_ws_client: Any) -> None:
661-
"""Test retrieving reviews successfully."""
660+
async def test_get_reviews_unreviewed_success(
661+
hass: HomeAssistant, hass_ws_client: Any
662+
) -> None:
663+
"""Test retrieving unreviewed reviews (reviewed=False)."""
662664

663665
mock_client = create_mock_frigate_client()
664666
await setup_mock_frigate_config_entry(hass, client=mock_client)
@@ -698,6 +700,80 @@ async def test_get_reviews_success(hass: HomeAssistant, hass_ws_client: Any) ->
698700
assert response["result"] == reviews_success
699701

700702

703+
async def test_get_reviews_reviewed_success(
704+
hass: HomeAssistant, hass_ws_client: Any
705+
) -> None:
706+
"""Test retrieving reviewed reviews (reviewed=True)."""
707+
708+
mock_client = create_mock_frigate_client()
709+
await setup_mock_frigate_config_entry(hass, client=mock_client)
710+
711+
ws_client = await hass_ws_client()
712+
reviews_json = {
713+
"id": 1,
714+
"type": "frigate/reviews/get",
715+
"instance_id": TEST_FRIGATE_INSTANCE_ID,
716+
"cameras": [TEST_CAMERA],
717+
"reviewed": True,
718+
}
719+
720+
reviews_success = {"reviews": "data"}
721+
mock_client.async_get_reviews = AsyncMock(return_value=reviews_success)
722+
await ws_client.send_json(reviews_json)
723+
724+
response = await ws_client.receive_json()
725+
mock_client.async_get_reviews.assert_called_with(
726+
[TEST_CAMERA],
727+
None,
728+
None,
729+
None,
730+
None,
731+
None,
732+
None,
733+
True,
734+
decode_json=False,
735+
)
736+
assert response["success"]
737+
assert response["result"] == reviews_success
738+
739+
740+
async def test_get_reviews_no_filter_success(
741+
hass: HomeAssistant, hass_ws_client: Any
742+
) -> None:
743+
"""Test retrieving all reviews (no reviewed filter)."""
744+
745+
mock_client = create_mock_frigate_client()
746+
await setup_mock_frigate_config_entry(hass, client=mock_client)
747+
748+
ws_client = await hass_ws_client()
749+
reviews_json = {
750+
"id": 1,
751+
"type": "frigate/reviews/get",
752+
"instance_id": TEST_FRIGATE_INSTANCE_ID,
753+
"cameras": [TEST_CAMERA],
754+
# No "reviewed" field - should pass None to the API
755+
}
756+
757+
reviews_success = {"reviews": "data"}
758+
mock_client.async_get_reviews = AsyncMock(return_value=reviews_success)
759+
await ws_client.send_json(reviews_json)
760+
761+
response = await ws_client.receive_json()
762+
mock_client.async_get_reviews.assert_called_with(
763+
[TEST_CAMERA],
764+
None,
765+
None,
766+
None,
767+
None,
768+
None,
769+
None,
770+
None, # No reviewed filter
771+
decode_json=False,
772+
)
773+
assert response["success"]
774+
assert response["result"] == reviews_success
775+
776+
701777
async def test_get_reviews_instance_not_found(
702778
hass: HomeAssistant, hass_ws_client: Any
703779
) -> None:

0 commit comments

Comments
 (0)