forked from MirrorHub/synapse
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:
parent
f828a70be3
commit
8fb9af570f
6 changed files with 105 additions and 13 deletions
1
changelog.d/10077.feature
Normal file
1
changelog.d/10077.feature
Normal 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.
|
|
@ -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
|
||||||
|
|
|
@ -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(),
|
||||||
)
|
)
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
83
tests/rest/client/v2_alpha/test_report_event.py
Normal file
83
tests/rest/client/v2_alpha/test_report_event.py
Normal 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"]
|
||||||
|
)
|
Loading…
Reference in a new issue