Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Split admin API for reported events into a detail and a list view #8539

Merged
merged 10 commits into from
Oct 26, 2020
2 changes: 1 addition & 1 deletion changelog.d/8539.feature
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Split admin API for reported events (`GET /_synapse/admin/v1/event_reports`) into detail and list endpoints. Contributed by @dklimpel.
Split admin API for reported events (`GET /_synapse/admin/v1/event_reports`) into detail and list endpoints. This is a breaking change to #8217 which was introduced in synapse v1.21.0. Those who already use this API should check their scripts. Contributed by @dklimpel.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
Split admin API for reported events (`GET /_synapse/admin/v1/event_reports`) into detail and list endpoints. This is a breaking change to #8217 which was introduced in synapse v1.21.0. Those who already use this API should check their scripts. Contributed by @dklimpel.
Split admin API for reported events (`GET /_synapse/admin/v1/event_reports`) into detail and list endpoints. This is a breaking change to #8217 which was introduced in Synapse v1.21.0. Those who already use this API should check their scripts. Contributed by @dklimpel.

42 changes: 15 additions & 27 deletions docs/admin_api/event_reports.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,30 +17,26 @@ It returns a JSON body like the following:
{
"event_reports": [
{
"content": {
"reason": "foo",
"score": -100
},
"event_id": "$bNUFCwGzWca1meCGkjp-zwslF-GfVcXukvRLI1_FaVY",
"id": 2,
"reason": "foo",
"score": -100,
"received_ts": 1570897107409,
"room_alias": "#alias1:matrix.org",
"canonical_alias": "#alias1:matrix.org",
"room_id": "!ERAgBpSOcCCuTJqQPk:matrix.org",
"name": "Matrix HQ",
"sender": "@foobar:matrix.org",
"user_id": "@foo:matrix.org"
},
{
"content": {
"reason": "bar",
"score": -100
},
"event_id": "$3IcdZsDaN_En-S1DF4EMCy3v4gNRKeOJs8W5qTOKj4I",
"id": 3,
"reason": "bar",
"score": -100,
"received_ts": 1598889612059,
"room_alias": "#alias2:matrix.org",
"canonical_alias": "#alias2:matrix.org",
"room_id": "!eGvUQuTCkHGVwNMOjv:matrix.org",
"name": "Your room name here",
"sender": "@foobar:matrix.org",
"user_id": "@bar:matrix.org"
}
Expand Down Expand Up @@ -76,16 +72,13 @@ The following fields are returned in the JSON response body:
- ``id``: integer - ID of event report.
- ``received_ts``: integer - The timestamp (in milliseconds since the unix epoch) when this report was sent.
- ``room_id``: string - The ID of the room in which the event being reported is located.
- ``name``: string - The name of the room.
- ``event_id``: string - The ID of the reported event.
- ``user_id``: string - This is the user who reported the event and wrote the reason.
- ``reason``: string - Comment made by the ``user_id`` in this report. May be blank.
- ``content``: object - Content of reported event.

- ``reason``: string - Comment made by the ``user_id`` in this report. May be blank.
- ``score``: integer - Content is reported based upon a negative score, where -100 is "most offensive" and 0 is "inoffensive".

- ``score``: integer - Content is reported based upon a negative score, where -100 is "most offensive" and 0 is "inoffensive".
- ``sender``: string - This is the ID of the user who sent the original message/event that was reported.
- ``room_alias``: string - The alias of the room. ``null`` if the room does not have a canonical alias set.
- ``canonical_alias``: string - The canonical alias of the room. ``null`` if the room does not have a canonical alias set.
- ``next_token``: integer - Indication for pagination. See above.
- ``total``: integer - Total number of event reports related to the query (``user_id`` and ``room_id``).

Expand All @@ -106,10 +99,6 @@ It returns a JSON body like the following:
.. code:: jsonc

{
"content": {
"reason": "foo",
"score": -100
},
"event_id": "$bNUFCwGzWca1meCGkjp-zwslF-GfVcXukvRLI1_FaVY",
"event_json": {
"auth_events": [
Expand Down Expand Up @@ -146,9 +135,11 @@ It returns a JSON body like the following:
},
"id": <report_id>,
"reason": "foo",
"score": -100,
"received_ts": 1570897107409,
"room_alias": "#alias1:matrix.org",
"canonical_alias": "#alias1:matrix.org",
"room_id": "!ERAgBpSOcCCuTJqQPk:matrix.org",
"name": "Matrix HQ",
"sender": "@foobar:matrix.org",
"user_id": "@foo:matrix.org"
}
Expand All @@ -164,14 +155,11 @@ The following fields are returned in the JSON response body:
- ``id``: integer - ID of event report.
- ``received_ts``: integer - The timestamp (in milliseconds since the unix epoch) when this report was sent.
- ``room_id``: string - The ID of the room in which the event being reported is located.
- ``name``: string - The name of the room.
- ``event_id``: string - The ID of the reported event.
- ``user_id``: string - This is the user who reported the event and wrote the reason.
- ``reason``: string - Comment made by the ``user_id`` in this report. May be blank.
anoadragon453 marked this conversation as resolved.
Show resolved Hide resolved
- ``content``: object - Content of the event report.

- ``reason``: string - Comment made by the ``user_id`` in this report. May be blank.
- ``score``: integer - Content is reported based upon a negative score, where -100 is "most offensive" and 0 is "inoffensive".

- ``score``: integer - Content is reported based upon a negative score, where -100 is "most offensive" and 0 is "inoffensive".
- ``sender``: string - This is the ID of the user who sent the original message/event that was reported.
- ``room_alias``: string - The alias of the room. ``null`` if the room does not have a canonical alias set.
- ``canonical_alias``: string - The canonical alias of the room. ``null`` if the room does not have a canonical alias set.
- ``event_json``: object - Details of the original event that was reported.
2 changes: 1 addition & 1 deletion synapse/rest/admin/event_reports.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ async def on_GET(self, request, report_id):
)
try:
report_id = int(report_id)
except Exception:
except ValueError:
raise SynapseError(400, message, errcode=Codes.INVALID_PARAM)

if report_id < 0:
Expand Down
66 changes: 41 additions & 25 deletions synapse/storage/databases/main/room.py
Original file line number Diff line number Diff line change
Expand Up @@ -1429,34 +1429,40 @@ def _get_event_report_txn(txn, report_id):
er.room_id,
er.event_id,
er.user_id,
er.reason,
er.content,
events.sender,
room_aliases.room_alias,
room_stats_state.canonical_alias,
room_stats_state.name,
event_json.json AS event_json
FROM event_reports AS er
LEFT JOIN room_aliases
ON room_aliases.room_id = er.room_id
JOIN events
LEFT JOIN events
ON events.event_id = er.event_id
JOIN event_json
ON event_json.event_id = er.event_id
JOIN room_stats_state
ON room_stats_state.room_id = er.room_id
WHERE er.id = ?
"""

txn.execute(sql, [report_id])
rows = self.db_pool.cursor_to_dict(txn)
row = txn.fetchone()

if not rows:
if not row:
return None

event_report = rows[0]

try:
event_report["content"] = db_to_json(event_report["content"])
event_report["event_json"] = db_to_json(event_report["event_json"])
except Exception:
pass
event_report = {
"id": row[0],
"received_ts": row[1],
"room_id": row[2],
"event_id": row[3],
"user_id": row[4],
"score": db_to_json(row[5]).get("score"),
"reason": db_to_json(row[5]).get("reason"),
"sender": row[6],
"canonical_alias": row[7],
"name": row[8],
"event_json": db_to_json(row[9]),
}

return event_report

Expand Down Expand Up @@ -1521,15 +1527,15 @@ def _get_event_reports_paginate_txn(txn):
er.room_id,
er.event_id,
er.user_id,
er.reason,
er.content,
events.sender,
room_aliases.room_alias
room_stats_state.canonical_alias,
room_stats_state.name
FROM event_reports AS er
LEFT JOIN room_aliases
ON room_aliases.room_id = er.room_id
JOIN events
LEFT JOIN events
ON events.event_id = er.event_id
JOIN room_stats_state
ON room_stats_state.room_id = er.room_id
{where_clause}
ORDER BY er.received_ts {order}
LIMIT ?
Expand All @@ -1540,14 +1546,24 @@ def _get_event_reports_paginate_txn(txn):

args += [limit, start]
txn.execute(sql, args)
event_reports = self.db_pool.cursor_to_dict(txn)

event_reports = []
if count > 0:
Copy link
Member

Choose a reason for hiding this comment

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

This if probably isn't necessary (assuming our DB code isn't buggy). event_reports will still end up as an empty list.

for row in event_reports:
try:
row["content"] = db_to_json(row["content"])
except Exception:
continue
for row in txn:
event_reports.append(
{
"id": row[0],
"received_ts": row[1],
"room_id": row[2],
"event_id": row[3],
"user_id": row[4],
"score": db_to_json(row[5]).get("score"),
"reason": db_to_json(row[5]).get("reason"),
"sender": row[6],
"canonical_alias": row[7],
"name": row[8],
}
)

return event_reports, count

Expand Down
49 changes: 23 additions & 26 deletions tests/rest/admin/test_event_reports.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,12 +378,11 @@ def _check_fields(self, content):
self.assertIn("room_id", c)
self.assertIn("event_id", c)
self.assertIn("user_id", c)
self.assertIn("reason", c)
self.assertIn("content", c)
self.assertIn("sender", c)
self.assertIn("room_alias", c)
self.assertIn("score", c["content"])
self.assertIn("reason", c["content"])
self.assertIn("canonical_alias", c)
self.assertIn("name", c)
self.assertIn("score", c)
self.assertIn("reason", c)


class EventReportDetailTestCase(unittest.HomeserverTestCase):
Expand Down Expand Up @@ -467,7 +466,7 @@ def test_invalid_report_id(self):
self.assertEqual(400, int(channel.result["code"]), msg=channel.result["body"])
self.assertEqual(Codes.INVALID_PARAM, channel.json_body["errcode"])
self.assertEqual(
"The report_id parameter must be a positive integer.",
"The report_id parameter must be a string representing a positive integer.",
channel.json_body["error"],
)

Expand All @@ -482,7 +481,7 @@ def test_invalid_report_id(self):
self.assertEqual(400, int(channel.result["code"]), msg=channel.result["body"])
self.assertEqual(Codes.INVALID_PARAM, channel.json_body["errcode"])
self.assertEqual(
"The report_id parameter must be a positive integer.",
"The report_id parameter must be a string representing a positive integer.",
channel.json_body["error"],
)

Expand All @@ -497,7 +496,7 @@ def test_invalid_report_id(self):
self.assertEqual(400, int(channel.result["code"]), msg=channel.result["body"])
self.assertEqual(Codes.INVALID_PARAM, channel.json_body["errcode"])
self.assertEqual(
"The report_id parameter must be a positive integer.",
"The report_id parameter must be a string representing a positive integer.",
channel.json_body["error"],
)

Expand Down Expand Up @@ -535,21 +534,19 @@ def _create_event_and_report(self, room_id, user_tok):
def _check_fields(self, content):
"""Checks that all attributes are present in a event report
"""
for c in content:
self.assertIn("id", c)
self.assertIn("received_ts", c)
self.assertIn("room_id", c)
self.assertIn("event_id", c)
self.assertIn("user_id", c)
self.assertIn("reason", c)
self.assertIn("content", c)
self.assertIn("sender", c)
self.assertIn("room_alias", c)
self.assertIn("event_json", c)
self.assertIn("score", c["content"])
self.assertIn("reason", c["content"])
self.assertIn("auth_events", c["event_json"])
self.assertIn("type", c["event_json"])
self.assertIn("room_id", c["event_json"])
self.assertIn("sender", c["event_json"])
self.assertIn("content", c["event_json"])
self.assertIn("id", content)
self.assertIn("received_ts", content)
self.assertIn("room_id", content)
self.assertIn("event_id", content)
self.assertIn("user_id", content)
self.assertIn("sender", content)
self.assertIn("canonical_alias", content)
self.assertIn("name", content)
self.assertIn("event_json", content)
self.assertIn("score", content)
self.assertIn("reason", content)
self.assertIn("auth_events", content["event_json"])
self.assertIn("type", content["event_json"])
self.assertIn("room_id", content["event_json"])
self.assertIn("sender", content["event_json"])
self.assertIn("content", content["event_json"])