Fork of Pleroma with site-specific changes and feature branches https://git.pleroma.social/pleroma/pleroma
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

415 lines
13KB

  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. defmodule Pleroma.NotificationTest do
  5. use Pleroma.DataCase
  6. alias Pleroma.Web.TwitterAPI.TwitterAPI
  7. alias Pleroma.Web.CommonAPI
  8. alias Pleroma.{User, Notification}
  9. alias Pleroma.Web.ActivityPub.Transmogrifier
  10. import Pleroma.Factory
  11. describe "create_notifications" do
  12. test "notifies someone when they are directly addressed" do
  13. user = insert(:user)
  14. other_user = insert(:user)
  15. third_user = insert(:user)
  16. {:ok, activity} =
  17. TwitterAPI.create_status(user, %{
  18. "status" => "hey @#{other_user.nickname} and @#{third_user.nickname}"
  19. })
  20. {:ok, [notification, other_notification]} = Notification.create_notifications(activity)
  21. notified_ids = Enum.sort([notification.user_id, other_notification.user_id])
  22. assert notified_ids == [other_user.id, third_user.id]
  23. assert notification.activity_id == activity.id
  24. assert other_notification.activity_id == activity.id
  25. end
  26. end
  27. describe "create_notification" do
  28. test "it doesn't create a notification for user if the user blocks the activity author" do
  29. activity = insert(:note_activity)
  30. author = User.get_by_ap_id(activity.data["actor"])
  31. user = insert(:user)
  32. {:ok, user} = User.block(user, author)
  33. assert nil == Notification.create_notification(activity, user)
  34. end
  35. test "it doesn't create a notification for user if he is the activity author" do
  36. activity = insert(:note_activity)
  37. author = User.get_by_ap_id(activity.data["actor"])
  38. assert nil == Notification.create_notification(activity, author)
  39. end
  40. test "it doesn't create a notification for follow-unfollow-follow chains" do
  41. user = insert(:user)
  42. followed_user = insert(:user)
  43. {:ok, _, _, activity} = TwitterAPI.follow(user, %{"user_id" => followed_user.id})
  44. Notification.create_notification(activity, followed_user)
  45. TwitterAPI.unfollow(user, %{"user_id" => followed_user.id})
  46. {:ok, _, _, activity_dupe} = TwitterAPI.follow(user, %{"user_id" => followed_user.id})
  47. assert nil == Notification.create_notification(activity_dupe, followed_user)
  48. end
  49. test "it doesn't create a notification for like-unlike-like chains" do
  50. user = insert(:user)
  51. liked_user = insert(:user)
  52. {:ok, status} = TwitterAPI.create_status(liked_user, %{"status" => "Yui is best yuru"})
  53. {:ok, fav_status} = TwitterAPI.fav(user, status.id)
  54. Notification.create_notification(fav_status, liked_user)
  55. TwitterAPI.unfav(user, status.id)
  56. {:ok, dupe} = TwitterAPI.fav(user, status.id)
  57. assert nil == Notification.create_notification(dupe, liked_user)
  58. end
  59. test "it doesn't create a notification for repeat-unrepeat-repeat chains" do
  60. user = insert(:user)
  61. retweeted_user = insert(:user)
  62. {:ok, status} =
  63. TwitterAPI.create_status(retweeted_user, %{
  64. "status" => "Send dupe notifications to the shadow realm"
  65. })
  66. {:ok, retweeted_activity} = TwitterAPI.repeat(user, status.id)
  67. Notification.create_notification(retweeted_activity, retweeted_user)
  68. TwitterAPI.unrepeat(user, status.id)
  69. {:ok, dupe} = TwitterAPI.repeat(user, status.id)
  70. assert nil == Notification.create_notification(dupe, retweeted_user)
  71. end
  72. end
  73. describe "get notification" do
  74. test "it gets a notification that belongs to the user" do
  75. user = insert(:user)
  76. other_user = insert(:user)
  77. {:ok, activity} =
  78. TwitterAPI.create_status(user, %{"status" => "hey @#{other_user.nickname}"})
  79. {:ok, [notification]} = Notification.create_notifications(activity)
  80. {:ok, notification} = Notification.get(other_user, notification.id)
  81. assert notification.user_id == other_user.id
  82. end
  83. test "it returns error if the notification doesn't belong to the user" do
  84. user = insert(:user)
  85. other_user = insert(:user)
  86. {:ok, activity} =
  87. TwitterAPI.create_status(user, %{"status" => "hey @#{other_user.nickname}"})
  88. {:ok, [notification]} = Notification.create_notifications(activity)
  89. {:error, _notification} = Notification.get(user, notification.id)
  90. end
  91. end
  92. describe "dismiss notification" do
  93. test "it dismisses a notification that belongs to the user" do
  94. user = insert(:user)
  95. other_user = insert(:user)
  96. {:ok, activity} =
  97. TwitterAPI.create_status(user, %{"status" => "hey @#{other_user.nickname}"})
  98. {:ok, [notification]} = Notification.create_notifications(activity)
  99. {:ok, notification} = Notification.dismiss(other_user, notification.id)
  100. assert notification.user_id == other_user.id
  101. end
  102. test "it returns error if the notification doesn't belong to the user" do
  103. user = insert(:user)
  104. other_user = insert(:user)
  105. {:ok, activity} =
  106. TwitterAPI.create_status(user, %{"status" => "hey @#{other_user.nickname}"})
  107. {:ok, [notification]} = Notification.create_notifications(activity)
  108. {:error, _notification} = Notification.dismiss(user, notification.id)
  109. end
  110. end
  111. describe "clear notification" do
  112. test "it clears all notifications belonging to the user" do
  113. user = insert(:user)
  114. other_user = insert(:user)
  115. third_user = insert(:user)
  116. {:ok, activity} =
  117. TwitterAPI.create_status(user, %{
  118. "status" => "hey @#{other_user.nickname} and @#{third_user.nickname} !"
  119. })
  120. {:ok, _notifs} = Notification.create_notifications(activity)
  121. {:ok, activity} =
  122. TwitterAPI.create_status(user, %{
  123. "status" => "hey again @#{other_user.nickname} and @#{third_user.nickname} !"
  124. })
  125. {:ok, _notifs} = Notification.create_notifications(activity)
  126. Notification.clear(other_user)
  127. assert Notification.for_user(other_user) == []
  128. assert Notification.for_user(third_user) != []
  129. end
  130. end
  131. describe "set_read_up_to()" do
  132. test "it sets all notifications as read up to a specified notification ID" do
  133. user = insert(:user)
  134. other_user = insert(:user)
  135. {:ok, _activity} =
  136. TwitterAPI.create_status(user, %{
  137. "status" => "hey @#{other_user.nickname}!"
  138. })
  139. {:ok, _activity} =
  140. TwitterAPI.create_status(user, %{
  141. "status" => "hey again @#{other_user.nickname}!"
  142. })
  143. [n2, n1] = notifs = Notification.for_user(other_user)
  144. assert length(notifs) == 2
  145. assert n2.id > n1.id
  146. {:ok, _activity} =
  147. TwitterAPI.create_status(user, %{
  148. "status" => "hey yet again @#{other_user.nickname}!"
  149. })
  150. Notification.set_read_up_to(other_user, n2.id)
  151. [n3, n2, n1] = Notification.for_user(other_user)
  152. assert n1.seen == true
  153. assert n2.seen == true
  154. assert n3.seen == false
  155. end
  156. end
  157. describe "notification target determination" do
  158. test "it sends notifications to addressed users in new messages" do
  159. user = insert(:user)
  160. other_user = insert(:user)
  161. {:ok, activity} =
  162. CommonAPI.post(user, %{
  163. "status" => "hey @#{other_user.nickname}!"
  164. })
  165. assert other_user in Notification.get_notified_from_activity(activity)
  166. end
  167. test "it sends notifications to mentioned users in new messages" do
  168. user = insert(:user)
  169. other_user = insert(:user)
  170. create_activity = %{
  171. "@context" => "https://www.w3.org/ns/activitystreams",
  172. "type" => "Create",
  173. "to" => ["https://www.w3.org/ns/activitystreams#Public"],
  174. "actor" => user.ap_id,
  175. "object" => %{
  176. "type" => "Note",
  177. "content" => "message with a Mention tag, but no explicit tagging",
  178. "tag" => [
  179. %{
  180. "type" => "Mention",
  181. "href" => other_user.ap_id,
  182. "name" => other_user.nickname
  183. }
  184. ],
  185. "attributedTo" => user.ap_id
  186. }
  187. }
  188. {:ok, activity} = Transmogrifier.handle_incoming(create_activity)
  189. assert other_user in Notification.get_notified_from_activity(activity)
  190. end
  191. test "it does not send notifications to users who are only cc in new messages" do
  192. user = insert(:user)
  193. other_user = insert(:user)
  194. create_activity = %{
  195. "@context" => "https://www.w3.org/ns/activitystreams",
  196. "type" => "Create",
  197. "to" => ["https://www.w3.org/ns/activitystreams#Public"],
  198. "cc" => [other_user.ap_id],
  199. "actor" => user.ap_id,
  200. "object" => %{
  201. "type" => "Note",
  202. "content" => "hi everyone",
  203. "attributedTo" => user.ap_id
  204. }
  205. }
  206. {:ok, activity} = Transmogrifier.handle_incoming(create_activity)
  207. assert other_user not in Notification.get_notified_from_activity(activity)
  208. end
  209. test "it does not send notification to mentioned users in likes" do
  210. user = insert(:user)
  211. other_user = insert(:user)
  212. third_user = insert(:user)
  213. {:ok, activity_one} =
  214. CommonAPI.post(user, %{
  215. "status" => "hey @#{other_user.nickname}!"
  216. })
  217. {:ok, activity_two, _} = CommonAPI.favorite(activity_one.id, third_user)
  218. assert other_user not in Notification.get_notified_from_activity(activity_two)
  219. end
  220. test "it does not send notification to mentioned users in announces" do
  221. user = insert(:user)
  222. other_user = insert(:user)
  223. third_user = insert(:user)
  224. {:ok, activity_one} =
  225. CommonAPI.post(user, %{
  226. "status" => "hey @#{other_user.nickname}!"
  227. })
  228. {:ok, activity_two, _} = CommonAPI.repeat(activity_one.id, third_user)
  229. assert other_user not in Notification.get_notified_from_activity(activity_two)
  230. end
  231. end
  232. describe "notification lifecycle" do
  233. test "liking an activity results in 1 notification, then 0 if the activity is deleted" do
  234. user = insert(:user)
  235. other_user = insert(:user)
  236. {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
  237. assert length(Notification.for_user(user)) == 0
  238. {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
  239. assert length(Notification.for_user(user)) == 1
  240. {:ok, _} = CommonAPI.delete(activity.id, user)
  241. assert length(Notification.for_user(user)) == 0
  242. end
  243. test "liking an activity results in 1 notification, then 0 if the activity is unliked" do
  244. user = insert(:user)
  245. other_user = insert(:user)
  246. {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
  247. assert length(Notification.for_user(user)) == 0
  248. {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
  249. assert length(Notification.for_user(user)) == 1
  250. {:ok, _, _, _} = CommonAPI.unfavorite(activity.id, other_user)
  251. assert length(Notification.for_user(user)) == 0
  252. end
  253. test "repeating an activity results in 1 notification, then 0 if the activity is deleted" do
  254. user = insert(:user)
  255. other_user = insert(:user)
  256. {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
  257. assert length(Notification.for_user(user)) == 0
  258. {:ok, _, _} = CommonAPI.repeat(activity.id, other_user)
  259. assert length(Notification.for_user(user)) == 1
  260. {:ok, _} = CommonAPI.delete(activity.id, user)
  261. assert length(Notification.for_user(user)) == 0
  262. end
  263. test "repeating an activity results in 1 notification, then 0 if the activity is unrepeated" do
  264. user = insert(:user)
  265. other_user = insert(:user)
  266. {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
  267. assert length(Notification.for_user(user)) == 0
  268. {:ok, _, _} = CommonAPI.repeat(activity.id, other_user)
  269. assert length(Notification.for_user(user)) == 1
  270. {:ok, _, _} = CommonAPI.unrepeat(activity.id, other_user)
  271. assert length(Notification.for_user(user)) == 0
  272. end
  273. test "liking an activity which is already deleted does not generate a notification" do
  274. user = insert(:user)
  275. other_user = insert(:user)
  276. {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
  277. assert length(Notification.for_user(user)) == 0
  278. {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
  279. assert length(Notification.for_user(user)) == 0
  280. {:error, _} = CommonAPI.favorite(activity.id, other_user)
  281. assert length(Notification.for_user(user)) == 0
  282. end
  283. test "repeating an activity which is already deleted does not generate a notification" do
  284. user = insert(:user)
  285. other_user = insert(:user)
  286. {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
  287. assert length(Notification.for_user(user)) == 0
  288. {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
  289. assert length(Notification.for_user(user)) == 0
  290. {:error, _} = CommonAPI.repeat(activity.id, other_user)
  291. assert length(Notification.for_user(user)) == 0
  292. end
  293. test "replying to a deleted post without tagging does not generate a notification" do
  294. user = insert(:user)
  295. other_user = insert(:user)
  296. {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
  297. {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
  298. {:ok, _reply_activity} =
  299. CommonAPI.post(other_user, %{
  300. "status" => "test reply",
  301. "in_reply_to_status_id" => activity.id
  302. })
  303. assert length(Notification.for_user(user)) == 0
  304. end
  305. end
  306. end