Add Admin API endpoints to list, fetch and delete room reports#19648
Add Admin API endpoints to list, fetch and delete room reports#19648H-Shay wants to merge 24 commits into
Conversation
|
test failure looks to be flake |
| } | ||
| ], | ||
| "next_batch": 2, | ||
| "total": 4 |
There was a problem hiding this comment.
We should consider if total is worth returning (probably not) given the COUNT(*) will have to scan the whole table.
I'm guessing this was done to match the event reports endpoint (introduced in matrix-org/synapse#8217).
There was a problem hiding this comment.
It's useful to know the total number of reports associated with a given room or user id. The speed of the query is much less of a concern.
There was a problem hiding this comment.
It's useful (same reason offset pagination is useful) but it paints ourselves into a corner. At some scale, this gets too slow to use (on top of the resource strain on the database).
See https://wiki.postgresql.org/wiki/Count_estimate
In this case, we can get our own count estimate by just looking at the stream id. Overall, I think we should just skip. If it's something necessary, it can be introduced in its own PR with its own justifications and analysis.
There was a problem hiding this comment.
Looking at the id does not give the number of reports a given user has submitted or are against a given room, which the current count does (when provided the relevant filter). These are both signals that are actively used in production (for events, but we would use them for rooms as soon as this endpoint is available) so I guess this needs to be moved to another PR if it's an absolute blocker for this PR.
| "get_event_reports_paginate", _get_event_reports_paginate_txn | ||
| ) | ||
|
|
||
| async def delete_room_report(self, report_id: int) -> bool: |
| self.assertEqual(400, channel.code, msg=channel.json_body) | ||
| self.assertEqual(Codes.INVALID_PARAM, channel.json_body["errcode"]) | ||
| self.assertEqual( | ||
| "The report_id parameter must be a string representing a positive integer.", |
There was a problem hiding this comment.
| "The report_id parameter must be a string representing a positive integer.", | |
| "The report_id parameter must be a string representing a room report ID (positive integer).", |
There was a problem hiding this comment.
Ohh, this is checking the human readable error. I thought this was the assertion message when this failed.
We should shy away from asserting human readable messages as they change over time, can be translated, etc.
| # first created room report gets `id`=2 | ||
| self.url = "/_synapse/admin/v1/room_reports/2" |
There was a problem hiding this comment.
| # first created room report gets `id`=2 | |
| self.url = "/_synapse/admin/v1/room_reports/2" | |
| # first created room report gets `id`=2 | |
| self.fetch_report_url = "/_synapse/admin/v1/room_reports/2" |
|
Test failure is surprising but not related to this PR AFAICT. The test changes are split over two commits so I am not going to link them in each comment, but everything else should have a response. |
| ) -> tuple[int, JsonDict]: | ||
| await assert_requester_is_admin(self._auth, request) | ||
|
|
||
| message = "The report_id parameter must be a string representing a room report ID (positive integer)." |
There was a problem hiding this comment.
Might as well inline this or at-least move this to where its used
| ) | ||
| self.assertEqual(200, channel.code, msg=channel.json_body) | ||
|
|
||
| def _check_fields(self, content: list[JsonDict]) -> None: |
There was a problem hiding this comment.
It looks like there is an update but it's not quite what I had in mind.
I'd expect to just match the report ID's in order.
And then _check_expected_room_report_fields(...) would be like the previous _check_fields(...) which checked the shape.
And we would have:
def _check_expected_room_reports_response(self, response_json: JsonDict) -> None:
for room_report in todo:
_check_expected_room_report_fields(room_report)| self._check_expected_room_report_fields( | ||
| channel.json_body["room_reports"], [self.room_reports[3]] | ||
| ) | ||
|
|
There was a problem hiding this comment.
Sanity check reports returned are for the room
| self.assertEqual(200, channel.code, msg=channel.json_body) | ||
| second_page = channel.json_body["room_reports"] | ||
| self.assertEqual(len(second_page), 5) | ||
| self.assertNotIn("next_batch", channel.json_body) |
There was a problem hiding this comment.
| self.assertNotIn("next_batch", channel.json_body) | |
| # Nothing more to paginate | |
| self.assertNotIn("next_batch", channel.json_body) |
| shorthand=False, | ||
| ) | ||
| self.assertEqual(200, channel.code, msg=channel.json_body) | ||
| # there is no endpoint to get the id of a room report, so we fetch it from the db |
There was a problem hiding this comment.
This is a bit unfortunate. I assumed that submitting a report would return some sort of ID.
There was a problem hiding this comment.
synapse/synapse/rest/client/reporting.py
Line 164 in 003febe
| self.hs.get_datastores().main.db_pool.simple_select_one( | ||
| table="room_reports", | ||
| keyvalues={"room_id": room_id}, | ||
| retcols=("id",), | ||
| allow_none=False, | ||
| ) |
There was a problem hiding this comment.
This looks sketchy as it doesn't define a ORDER.
If sorting is not chosen, the rows will be returned in an unspecified order
-- https://www.postgresql.org/docs/current/queries-order.html
There was a problem hiding this comment.
is this a concern if there are no duplicate rows? each room_id reported is unique, and the underlying transaction raises an error if more than one row matches, eg:
synapse/synapse/storage/database.py
Line 2294 in 003febe
There was a problem hiding this comment.
As far as I can tell, you can have multiple reports per room and per user.
We should have a query that makes sure we grab the latest report from the given user/room.
| self.hs.get_datastores().main.db_pool.simple_delete( | ||
| "room_stats_state", | ||
| {"room_id": self.room_reports[1]["room_id"]}, | ||
| desc="_", |
There was a problem hiding this comment.
We can have a good description like test_delete_room_from_room_stats_state
Adds Admin API endpoints to manage room reports. Follow on from #17270, which added the endpoints to report rooms.