Make reason and score optional for report_event (#10077)

Implements MSC2414: https://github.com/matrix-org/matrix-doc/pull/2414
See #8551 

Signed-off-by: Callum Brown <callum@calcuode.com>
This commit is contained in:
Callum Brown 2021-05-27 18:42:23 +01:00 committed by GitHub
parent f828a70be3
commit 8fb9af570f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 105 additions and 13 deletions

View file

@ -0,0 +1 @@
Make reason and score parameters optional for reporting content. Implements [MSC2414](https://github.com/matrix-org/matrix-doc/pull/2414). Contributed by Callum Brown.

View file

@ -75,9 +75,9 @@ The following fields are returned in the JSON response body:
* `name`: string - The name of the room. * `name`: string - The name of the room.
* `event_id`: string - The ID of the reported event. * `event_id`: string - The ID of the reported event.
* `user_id`: string - This is the user who reported the event and wrote the reason. * `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. * `reason`: string - Comment made by the `user_id` in this report. May be blank or `null`.
* `score`: integer - Content is reported based upon a negative score, where -100 is * `score`: integer - Content is reported based upon a negative score, where -100 is
"most offensive" and 0 is "inoffensive". "most offensive" and 0 is "inoffensive". May be `null`.
* `sender`: string - This is the ID of the user who sent the original message/event that * `sender`: string - This is the ID of the user who sent the original message/event that
was reported. was reported.
* `canonical_alias`: string - The canonical alias of the room. `null` if the room does not * `canonical_alias`: string - The canonical alias of the room. `null` if the room does not

View file

@ -16,11 +16,7 @@ import logging
from http import HTTPStatus from http import HTTPStatus
from synapse.api.errors import Codes, SynapseError from synapse.api.errors import Codes, SynapseError
from synapse.http.servlet import ( from synapse.http.servlet import RestServlet, parse_json_object_from_request
RestServlet,
assert_params_in_dict,
parse_json_object_from_request,
)
from ._base import client_patterns from ._base import client_patterns
@ -42,15 +38,14 @@ class ReportEventRestServlet(RestServlet):
user_id = requester.user.to_string() user_id = requester.user.to_string()
body = parse_json_object_from_request(request) body = parse_json_object_from_request(request)
assert_params_in_dict(body, ("reason", "score"))
if not isinstance(body["reason"], str): if not isinstance(body.get("reason", ""), str):
raise SynapseError( raise SynapseError(
HTTPStatus.BAD_REQUEST, HTTPStatus.BAD_REQUEST,
"Param 'reason' must be a string", "Param 'reason' must be a string",
Codes.BAD_JSON, Codes.BAD_JSON,
) )
if not isinstance(body["score"], int): if not isinstance(body.get("score", 0), int):
raise SynapseError( raise SynapseError(
HTTPStatus.BAD_REQUEST, HTTPStatus.BAD_REQUEST,
"Param 'score' must be an integer", "Param 'score' must be an integer",
@ -61,7 +56,7 @@ class ReportEventRestServlet(RestServlet):
room_id=room_id, room_id=room_id,
event_id=event_id, event_id=event_id,
user_id=user_id, user_id=user_id,
reason=body["reason"], reason=body.get("reason"),
content=body, content=body,
received_ts=self.clock.time_msec(), received_ts=self.clock.time_msec(),
) )

View file

@ -1498,7 +1498,7 @@ class RoomStore(RoomBackgroundUpdateStore, RoomWorkerStore, SearchStore):
room_id: str, room_id: str,
event_id: str, event_id: str,
user_id: str, user_id: str,
reason: str, reason: Optional[str],
content: JsonDict, content: JsonDict,
received_ts: int, received_ts: int,
) -> None: ) -> None:

View file

@ -64,7 +64,7 @@ class EventReportsTestCase(unittest.HomeserverTestCase):
user_tok=self.admin_user_tok, user_tok=self.admin_user_tok,
) )
for _ in range(5): for _ in range(5):
self._create_event_and_report( self._create_event_and_report_without_parameters(
room_id=self.room_id2, room_id=self.room_id2,
user_tok=self.admin_user_tok, user_tok=self.admin_user_tok,
) )
@ -378,6 +378,19 @@ class EventReportsTestCase(unittest.HomeserverTestCase):
) )
self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"]) self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
def _create_event_and_report_without_parameters(self, room_id, user_tok):
"""Create and report an event, but omit reason and score"""
resp = self.helper.send(room_id, tok=user_tok)
event_id = resp["event_id"]
channel = self.make_request(
"POST",
"rooms/%s/report/%s" % (room_id, event_id),
json.dumps({}),
access_token=user_tok,
)
self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
def _check_fields(self, content): def _check_fields(self, content):
"""Checks that all attributes are present in an event report""" """Checks that all attributes are present in an event report"""
for c in content: for c in content:

View file

@ -0,0 +1,83 @@
# Copyright 2021 Callum Brown
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import json
import synapse.rest.admin
from synapse.rest.client.v1 import login, room
from synapse.rest.client.v2_alpha import report_event
from tests import unittest
class ReportEventTestCase(unittest.HomeserverTestCase):
servlets = [
synapse.rest.admin.register_servlets,
login.register_servlets,
room.register_servlets,
report_event.register_servlets,
]
def prepare(self, reactor, clock, hs):
self.admin_user = self.register_user("admin", "pass", admin=True)
self.admin_user_tok = self.login("admin", "pass")
self.other_user = self.register_user("user", "pass")
self.other_user_tok = self.login("user", "pass")
self.room_id = self.helper.create_room_as(
self.other_user, tok=self.other_user_tok, is_public=True
)
self.helper.join(self.room_id, user=self.admin_user, tok=self.admin_user_tok)
resp = self.helper.send(self.room_id, tok=self.admin_user_tok)
self.event_id = resp["event_id"]
self.report_path = "rooms/{}/report/{}".format(self.room_id, self.event_id)
def test_reason_str_and_score_int(self):
data = {"reason": "this makes me sad", "score": -100}
self._assert_status(200, data)
def test_no_reason(self):
data = {"score": 0}
self._assert_status(200, data)
def test_no_score(self):
data = {"reason": "this makes me sad"}
self._assert_status(200, data)
def test_no_reason_and_no_score(self):
data = {}
self._assert_status(200, data)
def test_reason_int_and_score_str(self):
data = {"reason": 10, "score": "string"}
self._assert_status(400, data)
def test_reason_zero_and_score_blank(self):
data = {"reason": 0, "score": ""}
self._assert_status(400, data)
def test_reason_and_score_null(self):
data = {"reason": None, "score": None}
self._assert_status(400, data)
def _assert_status(self, response_status, data):
channel = self.make_request(
"POST",
self.report_path,
json.dumps(data),
access_token=self.other_user_tok,
)
self.assertEqual(
response_status, int(channel.result["code"]), msg=channel.result["body"]
)