test_event_reports.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2020 Dirk Klimpel
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. import json
  16. import synapse.rest.admin
  17. from synapse.api.errors import Codes
  18. from synapse.rest.client.v1 import login, room
  19. from synapse.rest.client.v2_alpha import report_event
  20. from tests import unittest
  21. class EventReportsTestCase(unittest.HomeserverTestCase):
  22. servlets = [
  23. synapse.rest.admin.register_servlets,
  24. login.register_servlets,
  25. room.register_servlets,
  26. report_event.register_servlets,
  27. ]
  28. def prepare(self, reactor, clock, hs):
  29. self.admin_user = self.register_user("admin", "pass", admin=True)
  30. self.admin_user_tok = self.login("admin", "pass")
  31. self.other_user = self.register_user("user", "pass")
  32. self.other_user_tok = self.login("user", "pass")
  33. self.room_id1 = self.helper.create_room_as(
  34. self.other_user, tok=self.other_user_tok, is_public=True
  35. )
  36. self.helper.join(self.room_id1, user=self.admin_user, tok=self.admin_user_tok)
  37. self.room_id2 = self.helper.create_room_as(
  38. self.other_user, tok=self.other_user_tok, is_public=True
  39. )
  40. self.helper.join(self.room_id2, user=self.admin_user, tok=self.admin_user_tok)
  41. # Two rooms and two users. Every user sends and reports every room event
  42. for i in range(5):
  43. self._create_event_and_report(
  44. room_id=self.room_id1, user_tok=self.other_user_tok,
  45. )
  46. for i in range(5):
  47. self._create_event_and_report(
  48. room_id=self.room_id2, user_tok=self.other_user_tok,
  49. )
  50. for i in range(5):
  51. self._create_event_and_report(
  52. room_id=self.room_id1, user_tok=self.admin_user_tok,
  53. )
  54. for i in range(5):
  55. self._create_event_and_report(
  56. room_id=self.room_id2, user_tok=self.admin_user_tok,
  57. )
  58. self.url = "/_synapse/admin/v1/event_reports"
  59. def test_no_auth(self):
  60. """
  61. Try to get an event report without authentication.
  62. """
  63. channel = self.make_request("GET", self.url, b"{}")
  64. self.assertEqual(401, int(channel.result["code"]), msg=channel.result["body"])
  65. self.assertEqual(Codes.MISSING_TOKEN, channel.json_body["errcode"])
  66. def test_requester_is_no_admin(self):
  67. """
  68. If the user is not a server admin, an error 403 is returned.
  69. """
  70. channel = self.make_request("GET", self.url, access_token=self.other_user_tok,)
  71. self.assertEqual(403, int(channel.result["code"]), msg=channel.result["body"])
  72. self.assertEqual(Codes.FORBIDDEN, channel.json_body["errcode"])
  73. def test_default_success(self):
  74. """
  75. Testing list of reported events
  76. """
  77. channel = self.make_request("GET", self.url, access_token=self.admin_user_tok,)
  78. self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
  79. self.assertEqual(channel.json_body["total"], 20)
  80. self.assertEqual(len(channel.json_body["event_reports"]), 20)
  81. self.assertNotIn("next_token", channel.json_body)
  82. self._check_fields(channel.json_body["event_reports"])
  83. def test_limit(self):
  84. """
  85. Testing list of reported events with limit
  86. """
  87. channel = self.make_request(
  88. "GET", self.url + "?limit=5", access_token=self.admin_user_tok,
  89. )
  90. self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
  91. self.assertEqual(channel.json_body["total"], 20)
  92. self.assertEqual(len(channel.json_body["event_reports"]), 5)
  93. self.assertEqual(channel.json_body["next_token"], 5)
  94. self._check_fields(channel.json_body["event_reports"])
  95. def test_from(self):
  96. """
  97. Testing list of reported events with a defined starting point (from)
  98. """
  99. channel = self.make_request(
  100. "GET", self.url + "?from=5", access_token=self.admin_user_tok,
  101. )
  102. self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
  103. self.assertEqual(channel.json_body["total"], 20)
  104. self.assertEqual(len(channel.json_body["event_reports"]), 15)
  105. self.assertNotIn("next_token", channel.json_body)
  106. self._check_fields(channel.json_body["event_reports"])
  107. def test_limit_and_from(self):
  108. """
  109. Testing list of reported events with a defined starting point and limit
  110. """
  111. channel = self.make_request(
  112. "GET", self.url + "?from=5&limit=10", access_token=self.admin_user_tok,
  113. )
  114. self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
  115. self.assertEqual(channel.json_body["total"], 20)
  116. self.assertEqual(channel.json_body["next_token"], 15)
  117. self.assertEqual(len(channel.json_body["event_reports"]), 10)
  118. self._check_fields(channel.json_body["event_reports"])
  119. def test_filter_room(self):
  120. """
  121. Testing list of reported events with a filter of room
  122. """
  123. channel = self.make_request(
  124. "GET",
  125. self.url + "?room_id=%s" % self.room_id1,
  126. access_token=self.admin_user_tok,
  127. )
  128. self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
  129. self.assertEqual(channel.json_body["total"], 10)
  130. self.assertEqual(len(channel.json_body["event_reports"]), 10)
  131. self.assertNotIn("next_token", channel.json_body)
  132. self._check_fields(channel.json_body["event_reports"])
  133. for report in channel.json_body["event_reports"]:
  134. self.assertEqual(report["room_id"], self.room_id1)
  135. def test_filter_user(self):
  136. """
  137. Testing list of reported events with a filter of user
  138. """
  139. channel = self.make_request(
  140. "GET",
  141. self.url + "?user_id=%s" % self.other_user,
  142. access_token=self.admin_user_tok,
  143. )
  144. self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
  145. self.assertEqual(channel.json_body["total"], 10)
  146. self.assertEqual(len(channel.json_body["event_reports"]), 10)
  147. self.assertNotIn("next_token", channel.json_body)
  148. self._check_fields(channel.json_body["event_reports"])
  149. for report in channel.json_body["event_reports"]:
  150. self.assertEqual(report["user_id"], self.other_user)
  151. def test_filter_user_and_room(self):
  152. """
  153. Testing list of reported events with a filter of user and room
  154. """
  155. channel = self.make_request(
  156. "GET",
  157. self.url + "?user_id=%s&room_id=%s" % (self.other_user, self.room_id1),
  158. access_token=self.admin_user_tok,
  159. )
  160. self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
  161. self.assertEqual(channel.json_body["total"], 5)
  162. self.assertEqual(len(channel.json_body["event_reports"]), 5)
  163. self.assertNotIn("next_token", channel.json_body)
  164. self._check_fields(channel.json_body["event_reports"])
  165. for report in channel.json_body["event_reports"]:
  166. self.assertEqual(report["user_id"], self.other_user)
  167. self.assertEqual(report["room_id"], self.room_id1)
  168. def test_valid_search_order(self):
  169. """
  170. Testing search order. Order by timestamps.
  171. """
  172. # fetch the most recent first, largest timestamp
  173. channel = self.make_request(
  174. "GET", self.url + "?dir=b", access_token=self.admin_user_tok,
  175. )
  176. self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
  177. self.assertEqual(channel.json_body["total"], 20)
  178. self.assertEqual(len(channel.json_body["event_reports"]), 20)
  179. report = 1
  180. while report < len(channel.json_body["event_reports"]):
  181. self.assertGreaterEqual(
  182. channel.json_body["event_reports"][report - 1]["received_ts"],
  183. channel.json_body["event_reports"][report]["received_ts"],
  184. )
  185. report += 1
  186. # fetch the oldest first, smallest timestamp
  187. channel = self.make_request(
  188. "GET", self.url + "?dir=f", access_token=self.admin_user_tok,
  189. )
  190. self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
  191. self.assertEqual(channel.json_body["total"], 20)
  192. self.assertEqual(len(channel.json_body["event_reports"]), 20)
  193. report = 1
  194. while report < len(channel.json_body["event_reports"]):
  195. self.assertLessEqual(
  196. channel.json_body["event_reports"][report - 1]["received_ts"],
  197. channel.json_body["event_reports"][report]["received_ts"],
  198. )
  199. report += 1
  200. def test_invalid_search_order(self):
  201. """
  202. Testing that a invalid search order returns a 400
  203. """
  204. channel = self.make_request(
  205. "GET", self.url + "?dir=bar", access_token=self.admin_user_tok,
  206. )
  207. self.assertEqual(400, int(channel.result["code"]), msg=channel.result["body"])
  208. self.assertEqual(Codes.INVALID_PARAM, channel.json_body["errcode"])
  209. self.assertEqual("Unknown direction: bar", channel.json_body["error"])
  210. def test_limit_is_negative(self):
  211. """
  212. Testing that a negative limit parameter returns a 400
  213. """
  214. channel = self.make_request(
  215. "GET", self.url + "?limit=-5", access_token=self.admin_user_tok,
  216. )
  217. self.assertEqual(400, int(channel.result["code"]), msg=channel.result["body"])
  218. self.assertEqual(Codes.INVALID_PARAM, channel.json_body["errcode"])
  219. def test_from_is_negative(self):
  220. """
  221. Testing that a negative from parameter returns a 400
  222. """
  223. channel = self.make_request(
  224. "GET", self.url + "?from=-5", access_token=self.admin_user_tok,
  225. )
  226. self.assertEqual(400, int(channel.result["code"]), msg=channel.result["body"])
  227. self.assertEqual(Codes.INVALID_PARAM, channel.json_body["errcode"])
  228. def test_next_token(self):
  229. """
  230. Testing that `next_token` appears at the right place
  231. """
  232. # `next_token` does not appear
  233. # Number of results is the number of entries
  234. channel = self.make_request(
  235. "GET", self.url + "?limit=20", access_token=self.admin_user_tok,
  236. )
  237. self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
  238. self.assertEqual(channel.json_body["total"], 20)
  239. self.assertEqual(len(channel.json_body["event_reports"]), 20)
  240. self.assertNotIn("next_token", channel.json_body)
  241. # `next_token` does not appear
  242. # Number of max results is larger than the number of entries
  243. channel = self.make_request(
  244. "GET", self.url + "?limit=21", access_token=self.admin_user_tok,
  245. )
  246. self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
  247. self.assertEqual(channel.json_body["total"], 20)
  248. self.assertEqual(len(channel.json_body["event_reports"]), 20)
  249. self.assertNotIn("next_token", channel.json_body)
  250. # `next_token` does appear
  251. # Number of max results is smaller than the number of entries
  252. channel = self.make_request(
  253. "GET", self.url + "?limit=19", access_token=self.admin_user_tok,
  254. )
  255. self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
  256. self.assertEqual(channel.json_body["total"], 20)
  257. self.assertEqual(len(channel.json_body["event_reports"]), 19)
  258. self.assertEqual(channel.json_body["next_token"], 19)
  259. # Check
  260. # Set `from` to value of `next_token` for request remaining entries
  261. # `next_token` does not appear
  262. channel = self.make_request(
  263. "GET", self.url + "?from=19", access_token=self.admin_user_tok,
  264. )
  265. self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
  266. self.assertEqual(channel.json_body["total"], 20)
  267. self.assertEqual(len(channel.json_body["event_reports"]), 1)
  268. self.assertNotIn("next_token", channel.json_body)
  269. def _create_event_and_report(self, room_id, user_tok):
  270. """Create and report events
  271. """
  272. resp = self.helper.send(room_id, tok=user_tok)
  273. event_id = resp["event_id"]
  274. channel = self.make_request(
  275. "POST",
  276. "rooms/%s/report/%s" % (room_id, event_id),
  277. json.dumps({"score": -100, "reason": "this makes me sad"}),
  278. access_token=user_tok,
  279. )
  280. self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
  281. def _check_fields(self, content):
  282. """Checks that all attributes are present in an event report
  283. """
  284. for c in content:
  285. self.assertIn("id", c)
  286. self.assertIn("received_ts", c)
  287. self.assertIn("room_id", c)
  288. self.assertIn("event_id", c)
  289. self.assertIn("user_id", c)
  290. self.assertIn("sender", c)
  291. self.assertIn("canonical_alias", c)
  292. self.assertIn("name", c)
  293. self.assertIn("score", c)
  294. self.assertIn("reason", c)
  295. class EventReportDetailTestCase(unittest.HomeserverTestCase):
  296. servlets = [
  297. synapse.rest.admin.register_servlets,
  298. login.register_servlets,
  299. room.register_servlets,
  300. report_event.register_servlets,
  301. ]
  302. def prepare(self, reactor, clock, hs):
  303. self.admin_user = self.register_user("admin", "pass", admin=True)
  304. self.admin_user_tok = self.login("admin", "pass")
  305. self.other_user = self.register_user("user", "pass")
  306. self.other_user_tok = self.login("user", "pass")
  307. self.room_id1 = self.helper.create_room_as(
  308. self.other_user, tok=self.other_user_tok, is_public=True
  309. )
  310. self.helper.join(self.room_id1, user=self.admin_user, tok=self.admin_user_tok)
  311. self._create_event_and_report(
  312. room_id=self.room_id1, user_tok=self.other_user_tok,
  313. )
  314. # first created event report gets `id`=2
  315. self.url = "/_synapse/admin/v1/event_reports/2"
  316. def test_no_auth(self):
  317. """
  318. Try to get event report without authentication.
  319. """
  320. channel = self.make_request("GET", self.url, b"{}")
  321. self.assertEqual(401, int(channel.result["code"]), msg=channel.result["body"])
  322. self.assertEqual(Codes.MISSING_TOKEN, channel.json_body["errcode"])
  323. def test_requester_is_no_admin(self):
  324. """
  325. If the user is not a server admin, an error 403 is returned.
  326. """
  327. channel = self.make_request("GET", self.url, access_token=self.other_user_tok,)
  328. self.assertEqual(403, int(channel.result["code"]), msg=channel.result["body"])
  329. self.assertEqual(Codes.FORBIDDEN, channel.json_body["errcode"])
  330. def test_default_success(self):
  331. """
  332. Testing get a reported event
  333. """
  334. channel = self.make_request("GET", self.url, access_token=self.admin_user_tok,)
  335. self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
  336. self._check_fields(channel.json_body)
  337. def test_invalid_report_id(self):
  338. """
  339. Testing that an invalid `report_id` returns a 400.
  340. """
  341. # `report_id` is negative
  342. channel = self.make_request(
  343. "GET",
  344. "/_synapse/admin/v1/event_reports/-123",
  345. access_token=self.admin_user_tok,
  346. )
  347. self.assertEqual(400, int(channel.result["code"]), msg=channel.result["body"])
  348. self.assertEqual(Codes.INVALID_PARAM, channel.json_body["errcode"])
  349. self.assertEqual(
  350. "The report_id parameter must be a string representing a positive integer.",
  351. channel.json_body["error"],
  352. )
  353. # `report_id` is a non-numerical string
  354. channel = self.make_request(
  355. "GET",
  356. "/_synapse/admin/v1/event_reports/abcdef",
  357. access_token=self.admin_user_tok,
  358. )
  359. self.assertEqual(400, int(channel.result["code"]), msg=channel.result["body"])
  360. self.assertEqual(Codes.INVALID_PARAM, channel.json_body["errcode"])
  361. self.assertEqual(
  362. "The report_id parameter must be a string representing a positive integer.",
  363. channel.json_body["error"],
  364. )
  365. # `report_id` is undefined
  366. channel = self.make_request(
  367. "GET",
  368. "/_synapse/admin/v1/event_reports/",
  369. access_token=self.admin_user_tok,
  370. )
  371. self.assertEqual(400, int(channel.result["code"]), msg=channel.result["body"])
  372. self.assertEqual(Codes.INVALID_PARAM, channel.json_body["errcode"])
  373. self.assertEqual(
  374. "The report_id parameter must be a string representing a positive integer.",
  375. channel.json_body["error"],
  376. )
  377. def test_report_id_not_found(self):
  378. """
  379. Testing that a not existing `report_id` returns a 404.
  380. """
  381. channel = self.make_request(
  382. "GET",
  383. "/_synapse/admin/v1/event_reports/123",
  384. access_token=self.admin_user_tok,
  385. )
  386. self.assertEqual(404, int(channel.result["code"]), msg=channel.result["body"])
  387. self.assertEqual(Codes.NOT_FOUND, channel.json_body["errcode"])
  388. self.assertEqual("Event report not found", channel.json_body["error"])
  389. def _create_event_and_report(self, room_id, user_tok):
  390. """Create and report events
  391. """
  392. resp = self.helper.send(room_id, tok=user_tok)
  393. event_id = resp["event_id"]
  394. channel = self.make_request(
  395. "POST",
  396. "rooms/%s/report/%s" % (room_id, event_id),
  397. json.dumps({"score": -100, "reason": "this makes me sad"}),
  398. access_token=user_tok,
  399. )
  400. self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
  401. def _check_fields(self, content):
  402. """Checks that all attributes are present in a event report
  403. """
  404. self.assertIn("id", content)
  405. self.assertIn("received_ts", content)
  406. self.assertIn("room_id", content)
  407. self.assertIn("event_id", content)
  408. self.assertIn("user_id", content)
  409. self.assertIn("sender", content)
  410. self.assertIn("canonical_alias", content)
  411. self.assertIn("name", content)
  412. self.assertIn("event_json", content)
  413. self.assertIn("score", content)
  414. self.assertIn("reason", content)
  415. self.assertIn("auth_events", content["event_json"])
  416. self.assertIn("type", content["event_json"])
  417. self.assertIn("room_id", content["event_json"])
  418. self.assertIn("sender", content["event_json"])
  419. self.assertIn("content", content["event_json"])