logo

pleroma

My custom branche(s) on git.pleroma.social/pleroma/pleroma git clone https://hacktivis.me/git/pleroma.git

side_effects_test.exs (33951B)


  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
  5. use Oban.Testing, repo: Pleroma.Repo
  6. use Pleroma.DataCase
  7. alias Pleroma.Activity
  8. alias Pleroma.Chat
  9. alias Pleroma.Chat.MessageReference
  10. alias Pleroma.Notification
  11. alias Pleroma.Object
  12. alias Pleroma.Repo
  13. alias Pleroma.Tests.ObanHelpers
  14. alias Pleroma.User
  15. alias Pleroma.Web.ActivityPub.ActivityPub
  16. alias Pleroma.Web.ActivityPub.Builder
  17. alias Pleroma.Web.ActivityPub.SideEffects
  18. alias Pleroma.Web.ActivityPub.Utils
  19. alias Pleroma.Web.CommonAPI
  20. alias Pleroma.Web.CommonAPI.ActivityDraft
  21. import Mock
  22. import Pleroma.Factory
  23. defp get_announces_of_object(%{data: %{"id" => id}} = _object) do
  24. Pleroma.Activity.Queries.by_type("Announce")
  25. |> Pleroma.Activity.Queries.by_object_id(id)
  26. |> Pleroma.Repo.all()
  27. end
  28. describe "handle_after_transaction" do
  29. test "it streams out notifications and streams" do
  30. author = insert(:user, local: true)
  31. recipient = insert(:user, local: true)
  32. {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
  33. {:ok, create_activity_data, _meta} =
  34. Builder.create(author, chat_message_data["id"], [recipient.ap_id])
  35. {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
  36. {:ok, _create_activity, meta} =
  37. SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
  38. assert [notification] = meta[:notifications]
  39. with_mocks([
  40. {
  41. Pleroma.Web.Streamer,
  42. [],
  43. [
  44. stream: fn _, _ -> nil end
  45. ]
  46. },
  47. {
  48. Pleroma.Web.Push,
  49. [],
  50. [
  51. send: fn _ -> nil end
  52. ]
  53. }
  54. ]) do
  55. SideEffects.handle_after_transaction(meta)
  56. assert called(Pleroma.Web.Streamer.stream(["user", "user:notification"], notification))
  57. assert called(Pleroma.Web.Streamer.stream(["user", "user:pleroma_chat"], :_))
  58. assert called(Pleroma.Web.Push.send(notification))
  59. end
  60. end
  61. end
  62. describe "blocking users" do
  63. setup do
  64. user = insert(:user)
  65. blocked = insert(:user)
  66. User.follow(blocked, user)
  67. User.follow(user, blocked)
  68. {:ok, block_data, []} = Builder.block(user, blocked)
  69. {:ok, block, _meta} = ActivityPub.persist(block_data, local: true)
  70. %{user: user, blocked: blocked, block: block}
  71. end
  72. test "it unfollows and blocks", %{user: user, blocked: blocked, block: block} do
  73. assert User.following?(user, blocked)
  74. assert User.following?(blocked, user)
  75. {:ok, _, _} = SideEffects.handle(block)
  76. refute User.following?(user, blocked)
  77. refute User.following?(blocked, user)
  78. assert User.blocks?(user, blocked)
  79. end
  80. test "it updates following relationship", %{user: user, blocked: blocked, block: block} do
  81. {:ok, _, _} = SideEffects.handle(block)
  82. refute Pleroma.FollowingRelationship.get(user, blocked)
  83. assert User.get_follow_state(user, blocked) == nil
  84. assert User.get_follow_state(blocked, user) == nil
  85. assert User.get_follow_state(user, blocked, nil) == nil
  86. assert User.get_follow_state(blocked, user, nil) == nil
  87. end
  88. test "it blocks but does not unfollow if the relevant setting is set", %{
  89. user: user,
  90. blocked: blocked,
  91. block: block
  92. } do
  93. clear_config([:activitypub, :unfollow_blocked], false)
  94. assert User.following?(user, blocked)
  95. assert User.following?(blocked, user)
  96. {:ok, _, _} = SideEffects.handle(block)
  97. refute User.following?(user, blocked)
  98. assert User.following?(blocked, user)
  99. assert User.blocks?(user, blocked)
  100. end
  101. end
  102. describe "update users" do
  103. setup do
  104. user = insert(:user, local: false)
  105. {:ok, update_data, []} =
  106. Builder.update(user, %{"id" => user.ap_id, "type" => "Person", "name" => "new name!"})
  107. {:ok, update, _meta} = ActivityPub.persist(update_data, local: true)
  108. %{user: user, update_data: update_data, update: update}
  109. end
  110. test "it updates the user", %{user: user, update: update} do
  111. {:ok, _, _} = SideEffects.handle(update)
  112. user = User.get_by_id(user.id)
  113. assert user.name == "new name!"
  114. end
  115. test "it uses a given changeset to update", %{user: user, update: update} do
  116. changeset = Ecto.Changeset.change(user, %{default_scope: "direct"})
  117. assert user.default_scope == "public"
  118. {:ok, _, _} = SideEffects.handle(update, user_update_changeset: changeset)
  119. user = User.get_by_id(user.id)
  120. assert user.default_scope == "direct"
  121. end
  122. end
  123. describe "update notes" do
  124. setup do
  125. make_time = fn ->
  126. Pleroma.Web.ActivityPub.Utils.make_date()
  127. end
  128. user = insert(:user)
  129. note = insert(:note, user: user, data: %{"published" => make_time.()})
  130. _note_activity = insert(:note_activity, note: note)
  131. updated_note =
  132. note.data
  133. |> Map.put("summary", "edited summary")
  134. |> Map.put("content", "edited content")
  135. |> Map.put("updated", make_time.())
  136. {:ok, update_data, []} = Builder.update(user, updated_note)
  137. {:ok, update, _meta} = ActivityPub.persist(update_data, local: true)
  138. %{
  139. user: user,
  140. note: note,
  141. object_id: note.id,
  142. update_data: update_data,
  143. update: update,
  144. updated_note: updated_note
  145. }
  146. end
  147. test "it updates the note", %{
  148. object_id: object_id,
  149. update: update,
  150. updated_note: updated_note
  151. } do
  152. {:ok, _, _} = SideEffects.handle(update, object_data: updated_note)
  153. updated_time = updated_note["updated"]
  154. new_note = Pleroma.Object.get_by_id(object_id)
  155. assert %{
  156. "summary" => "edited summary",
  157. "content" => "edited content",
  158. "updated" => ^updated_time
  159. } = new_note.data
  160. end
  161. test "it rejects updates with no updated attribute in object", %{
  162. object_id: object_id,
  163. update: update,
  164. updated_note: updated_note
  165. } do
  166. old_note = Pleroma.Object.get_by_id(object_id)
  167. updated_note = Map.drop(updated_note, ["updated"])
  168. {:ok, _, _} = SideEffects.handle(update, object_data: updated_note)
  169. new_note = Pleroma.Object.get_by_id(object_id)
  170. assert old_note.data == new_note.data
  171. end
  172. test "it rejects updates with updated attribute older than what we have in the original object",
  173. %{
  174. object_id: object_id,
  175. update: update,
  176. updated_note: updated_note
  177. } do
  178. old_note = Pleroma.Object.get_by_id(object_id)
  179. {:ok, creation_time, _} = DateTime.from_iso8601(old_note.data["published"])
  180. updated_note =
  181. Map.put(updated_note, "updated", DateTime.to_iso8601(DateTime.add(creation_time, -10)))
  182. {:ok, _, _} = SideEffects.handle(update, object_data: updated_note)
  183. new_note = Pleroma.Object.get_by_id(object_id)
  184. assert old_note.data == new_note.data
  185. end
  186. test "it rejects updates with updated attribute older than the last Update", %{
  187. object_id: object_id,
  188. update: update,
  189. updated_note: updated_note
  190. } do
  191. old_note = Pleroma.Object.get_by_id(object_id)
  192. {:ok, creation_time, _} = DateTime.from_iso8601(old_note.data["published"])
  193. updated_note =
  194. Map.put(updated_note, "updated", DateTime.to_iso8601(DateTime.add(creation_time, +10)))
  195. {:ok, _, _} = SideEffects.handle(update, object_data: updated_note)
  196. old_note = Pleroma.Object.get_by_id(object_id)
  197. {:ok, update_time, _} = DateTime.from_iso8601(old_note.data["updated"])
  198. updated_note =
  199. Map.put(updated_note, "updated", DateTime.to_iso8601(DateTime.add(update_time, -5)))
  200. {:ok, _, _} = SideEffects.handle(update, object_data: updated_note)
  201. new_note = Pleroma.Object.get_by_id(object_id)
  202. assert old_note.data == new_note.data
  203. end
  204. test "it updates using object_data", %{
  205. object_id: object_id,
  206. update: update,
  207. updated_note: updated_note
  208. } do
  209. updated_note = Map.put(updated_note, "summary", "mew mew")
  210. {:ok, _, _} = SideEffects.handle(update, object_data: updated_note)
  211. new_note = Pleroma.Object.get_by_id(object_id)
  212. assert %{"summary" => "mew mew", "content" => "edited content"} = new_note.data
  213. end
  214. test "it records the original note in formerRepresentations", %{
  215. note: note,
  216. object_id: object_id,
  217. update: update,
  218. updated_note: updated_note
  219. } do
  220. {:ok, _, _} = SideEffects.handle(update, object_data: updated_note)
  221. %{data: new_note} = Pleroma.Object.get_by_id(object_id)
  222. assert %{"summary" => "edited summary", "content" => "edited content"} = new_note
  223. assert [Map.drop(note.data, ["id", "formerRepresentations"])] ==
  224. new_note["formerRepresentations"]["orderedItems"]
  225. assert new_note["formerRepresentations"]["totalItems"] == 1
  226. end
  227. test "it puts the original note at the front of formerRepresentations", %{
  228. user: user,
  229. note: note,
  230. object_id: object_id,
  231. update: update,
  232. updated_note: updated_note
  233. } do
  234. {:ok, _, _} = SideEffects.handle(update, object_data: updated_note)
  235. %{data: first_edit} = Pleroma.Object.get_by_id(object_id)
  236. second_updated_note =
  237. note.data
  238. |> Map.put("summary", "edited summary 2")
  239. |> Map.put("content", "edited content 2")
  240. |> Map.put(
  241. "updated",
  242. first_edit["updated"]
  243. |> DateTime.from_iso8601()
  244. |> elem(1)
  245. |> DateTime.add(10)
  246. |> DateTime.to_iso8601()
  247. )
  248. {:ok, second_update_data, []} = Builder.update(user, second_updated_note)
  249. {:ok, update, _meta} = ActivityPub.persist(second_update_data, local: true)
  250. {:ok, _, _} = SideEffects.handle(update, object_data: second_updated_note)
  251. %{data: new_note} = Pleroma.Object.get_by_id(object_id)
  252. assert %{"summary" => "edited summary 2", "content" => "edited content 2"} = new_note
  253. original_version = Map.drop(note.data, ["id", "formerRepresentations"])
  254. first_edit = Map.drop(first_edit, ["id", "formerRepresentations"])
  255. assert [first_edit, original_version] ==
  256. new_note["formerRepresentations"]["orderedItems"]
  257. assert new_note["formerRepresentations"]["totalItems"] == 2
  258. end
  259. test "it does not prepend to formerRepresentations if no actual changes are made", %{
  260. note: note,
  261. object_id: object_id,
  262. update: update,
  263. updated_note: updated_note
  264. } do
  265. {:ok, _, _} = SideEffects.handle(update, object_data: updated_note)
  266. %{data: first_edit} = Pleroma.Object.get_by_id(object_id)
  267. updated_note =
  268. updated_note
  269. |> Map.put(
  270. "updated",
  271. first_edit["updated"]
  272. |> DateTime.from_iso8601()
  273. |> elem(1)
  274. |> DateTime.add(10)
  275. |> DateTime.to_iso8601()
  276. )
  277. {:ok, _, _} = SideEffects.handle(update, object_data: updated_note)
  278. %{data: new_note} = Pleroma.Object.get_by_id(object_id)
  279. assert %{"summary" => "edited summary", "content" => "edited content"} = new_note
  280. original_version = Map.drop(note.data, ["id", "formerRepresentations"])
  281. assert [original_version] ==
  282. new_note["formerRepresentations"]["orderedItems"]
  283. assert new_note["formerRepresentations"]["totalItems"] == 1
  284. end
  285. end
  286. describe "update questions" do
  287. setup do
  288. user = insert(:user)
  289. question =
  290. insert(:question,
  291. user: user,
  292. data: %{"published" => Pleroma.Web.ActivityPub.Utils.make_date()}
  293. )
  294. %{user: user, data: question.data, id: question.id}
  295. end
  296. test "allows updating choice count without generating edit history", %{
  297. user: user,
  298. data: data,
  299. id: id
  300. } do
  301. new_choices =
  302. data["oneOf"]
  303. |> Enum.map(fn choice -> put_in(choice, ["replies", "totalItems"], 5) end)
  304. updated_question =
  305. data
  306. |> Map.put("oneOf", new_choices)
  307. |> Map.put("updated", Pleroma.Web.ActivityPub.Utils.make_date())
  308. {:ok, update_data, []} = Builder.update(user, updated_question)
  309. {:ok, update, _meta} = ActivityPub.persist(update_data, local: true)
  310. {:ok, _, _} = SideEffects.handle(update, object_data: updated_question)
  311. %{data: new_question} = Pleroma.Object.get_by_id(id)
  312. assert [%{"replies" => %{"totalItems" => 5}}, %{"replies" => %{"totalItems" => 5}}] =
  313. new_question["oneOf"]
  314. refute Map.has_key?(new_question, "formerRepresentations")
  315. end
  316. test "allows updating choice count without updated field", %{
  317. user: user,
  318. data: data,
  319. id: id
  320. } do
  321. new_choices =
  322. data["oneOf"]
  323. |> Enum.map(fn choice -> put_in(choice, ["replies", "totalItems"], 5) end)
  324. updated_question =
  325. data
  326. |> Map.put("oneOf", new_choices)
  327. {:ok, update_data, []} = Builder.update(user, updated_question)
  328. {:ok, update, _meta} = ActivityPub.persist(update_data, local: true)
  329. {:ok, _, _} = SideEffects.handle(update, object_data: updated_question)
  330. %{data: new_question} = Pleroma.Object.get_by_id(id)
  331. assert [%{"replies" => %{"totalItems" => 5}}, %{"replies" => %{"totalItems" => 5}}] =
  332. new_question["oneOf"]
  333. refute Map.has_key?(new_question, "formerRepresentations")
  334. end
  335. test "allows updating choice count with updated field same as the creation date", %{
  336. user: user,
  337. data: data,
  338. id: id
  339. } do
  340. new_choices =
  341. data["oneOf"]
  342. |> Enum.map(fn choice -> put_in(choice, ["replies", "totalItems"], 5) end)
  343. updated_question =
  344. data
  345. |> Map.put("oneOf", new_choices)
  346. |> Map.put("updated", data["published"])
  347. {:ok, update_data, []} = Builder.update(user, updated_question)
  348. {:ok, update, _meta} = ActivityPub.persist(update_data, local: true)
  349. {:ok, _, _} = SideEffects.handle(update, object_data: updated_question)
  350. %{data: new_question} = Pleroma.Object.get_by_id(id)
  351. assert [%{"replies" => %{"totalItems" => 5}}, %{"replies" => %{"totalItems" => 5}}] =
  352. new_question["oneOf"]
  353. refute Map.has_key?(new_question, "formerRepresentations")
  354. end
  355. end
  356. describe "EmojiReact objects" do
  357. setup do
  358. poster = insert(:user)
  359. user = insert(:user)
  360. {:ok, post} = CommonAPI.post(poster, %{status: "hey"})
  361. {:ok, emoji_react_data, []} = Builder.emoji_react(user, post.object, "👌")
  362. {:ok, emoji_react, _meta} = ActivityPub.persist(emoji_react_data, local: true)
  363. %{emoji_react: emoji_react, user: user, poster: poster}
  364. end
  365. test "adds the reaction to the object", %{emoji_react: emoji_react, user: user} do
  366. {:ok, emoji_react, _} = SideEffects.handle(emoji_react)
  367. object = Object.get_by_ap_id(emoji_react.data["object"])
  368. assert object.data["reaction_count"] == 1
  369. assert ["👌", [user.ap_id], nil] in object.data["reactions"]
  370. end
  371. test "creates a notification", %{emoji_react: emoji_react, poster: poster} do
  372. {:ok, emoji_react, _} = SideEffects.handle(emoji_react)
  373. assert Repo.get_by(Notification, user_id: poster.id, activity_id: emoji_react.id)
  374. end
  375. end
  376. describe "Question objects" do
  377. setup do
  378. user = insert(:user)
  379. question = build(:question, user: user)
  380. question_activity = build(:question_activity, question: question)
  381. activity_data = Map.put(question_activity.data, "object", question.data["id"])
  382. meta = [object_data: question.data, local: false]
  383. {:ok, activity, meta} = ActivityPub.persist(activity_data, meta)
  384. %{activity: activity, meta: meta}
  385. end
  386. test "enqueues the poll end", %{activity: activity, meta: meta} do
  387. {:ok, activity, meta} = SideEffects.handle(activity, meta)
  388. assert_enqueued(
  389. worker: Pleroma.Workers.PollWorker,
  390. args: %{op: "poll_end", activity_id: activity.id},
  391. scheduled_at: NaiveDateTime.from_iso8601!(meta[:object_data]["closed"])
  392. )
  393. end
  394. end
  395. describe "delete users with confirmation pending" do
  396. setup do
  397. user = insert(:user, is_confirmed: false)
  398. {:ok, delete_user_data, _meta} = Builder.delete(user, user.ap_id)
  399. {:ok, delete_user, _meta} = ActivityPub.persist(delete_user_data, local: true)
  400. {:ok, delete: delete_user, user: user}
  401. end
  402. test "when activation is required", %{delete: delete, user: user} do
  403. clear_config([:instance, :account_activation_required], true)
  404. {:ok, _, _} = SideEffects.handle(delete)
  405. ObanHelpers.perform_all()
  406. refute User.get_cached_by_id(user.id)
  407. end
  408. end
  409. describe "Undo objects" do
  410. setup do
  411. poster = insert(:user)
  412. user = insert(:user)
  413. {:ok, post} = CommonAPI.post(poster, %{status: "hey"})
  414. {:ok, like} = CommonAPI.favorite(user, post.id)
  415. {:ok, reaction} = CommonAPI.react_with_emoji(post.id, user, "👍")
  416. {:ok, announce} = CommonAPI.repeat(post.id, user)
  417. {:ok, block} = CommonAPI.block(user, poster)
  418. {:ok, undo_data, _meta} = Builder.undo(user, like)
  419. {:ok, like_undo, _meta} = ActivityPub.persist(undo_data, local: true)
  420. {:ok, undo_data, _meta} = Builder.undo(user, reaction)
  421. {:ok, reaction_undo, _meta} = ActivityPub.persist(undo_data, local: true)
  422. {:ok, undo_data, _meta} = Builder.undo(user, announce)
  423. {:ok, announce_undo, _meta} = ActivityPub.persist(undo_data, local: true)
  424. {:ok, undo_data, _meta} = Builder.undo(user, block)
  425. {:ok, block_undo, _meta} = ActivityPub.persist(undo_data, local: true)
  426. %{
  427. like_undo: like_undo,
  428. post: post,
  429. like: like,
  430. reaction_undo: reaction_undo,
  431. reaction: reaction,
  432. announce_undo: announce_undo,
  433. announce: announce,
  434. block_undo: block_undo,
  435. block: block,
  436. poster: poster,
  437. user: user
  438. }
  439. end
  440. test "deletes the original block", %{
  441. block_undo: block_undo,
  442. block: block
  443. } do
  444. {:ok, _block_undo, _meta} = SideEffects.handle(block_undo)
  445. refute Activity.get_by_id(block.id)
  446. end
  447. test "unblocks the blocked user", %{block_undo: block_undo, block: block} do
  448. blocker = User.get_by_ap_id(block.data["actor"])
  449. blocked = User.get_by_ap_id(block.data["object"])
  450. {:ok, _block_undo, _} = SideEffects.handle(block_undo)
  451. refute User.blocks?(blocker, blocked)
  452. end
  453. test "an announce undo removes the announce from the object", %{
  454. announce_undo: announce_undo,
  455. post: post
  456. } do
  457. {:ok, _announce_undo, _} = SideEffects.handle(announce_undo)
  458. object = Object.get_by_ap_id(post.data["object"])
  459. assert object.data["announcement_count"] == 0
  460. assert object.data["announcements"] == []
  461. end
  462. test "deletes the original announce", %{announce_undo: announce_undo, announce: announce} do
  463. {:ok, _announce_undo, _} = SideEffects.handle(announce_undo)
  464. refute Activity.get_by_id(announce.id)
  465. end
  466. test "a reaction undo removes the reaction from the object", %{
  467. reaction_undo: reaction_undo,
  468. post: post
  469. } do
  470. {:ok, _reaction_undo, _} = SideEffects.handle(reaction_undo)
  471. object = Object.get_by_ap_id(post.data["object"])
  472. assert object.data["reaction_count"] == 0
  473. assert object.data["reactions"] == []
  474. end
  475. test "deletes the original reaction", %{reaction_undo: reaction_undo, reaction: reaction} do
  476. {:ok, _reaction_undo, _} = SideEffects.handle(reaction_undo)
  477. refute Activity.get_by_id(reaction.id)
  478. end
  479. test "a like undo removes the like from the object", %{like_undo: like_undo, post: post} do
  480. {:ok, _like_undo, _} = SideEffects.handle(like_undo)
  481. object = Object.get_by_ap_id(post.data["object"])
  482. assert object.data["like_count"] == 0
  483. assert object.data["likes"] == []
  484. end
  485. test "deletes the original like", %{like_undo: like_undo, like: like} do
  486. {:ok, _like_undo, _} = SideEffects.handle(like_undo)
  487. refute Activity.get_by_id(like.id)
  488. end
  489. end
  490. describe "like objects" do
  491. setup do
  492. poster = insert(:user)
  493. user = insert(:user)
  494. {:ok, post} = CommonAPI.post(poster, %{status: "hey"})
  495. {:ok, like_data, _meta} = Builder.like(user, post.object)
  496. {:ok, like, _meta} = ActivityPub.persist(like_data, local: true)
  497. %{like: like, user: user, poster: poster}
  498. end
  499. test "add the like to the original object", %{like: like, user: user} do
  500. {:ok, like, _} = SideEffects.handle(like)
  501. object = Object.get_by_ap_id(like.data["object"])
  502. assert object.data["like_count"] == 1
  503. assert user.ap_id in object.data["likes"]
  504. end
  505. test "creates a notification", %{like: like, poster: poster} do
  506. {:ok, like, _} = SideEffects.handle(like)
  507. assert Repo.get_by(Notification, user_id: poster.id, activity_id: like.id)
  508. end
  509. end
  510. describe "creation of ChatMessages" do
  511. test "notifies the recipient" do
  512. author = insert(:user, local: false)
  513. recipient = insert(:user, local: true)
  514. {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
  515. {:ok, create_activity_data, _meta} =
  516. Builder.create(author, chat_message_data["id"], [recipient.ap_id])
  517. {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
  518. {:ok, _create_activity, _meta} =
  519. SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
  520. assert Repo.get_by(Notification, user_id: recipient.id, activity_id: create_activity.id)
  521. end
  522. test "it streams the created ChatMessage" do
  523. author = insert(:user, local: true)
  524. recipient = insert(:user, local: true)
  525. {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
  526. {:ok, create_activity_data, _meta} =
  527. Builder.create(author, chat_message_data["id"], [recipient.ap_id])
  528. {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
  529. {:ok, _create_activity, meta} =
  530. SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
  531. assert [_, _] = meta[:streamables]
  532. end
  533. test "it creates a Chat and MessageReferences for the local users and bumps the unread count, except for the author" do
  534. author = insert(:user, local: true)
  535. recipient = insert(:user, local: true)
  536. {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
  537. {:ok, create_activity_data, _meta} =
  538. Builder.create(author, chat_message_data["id"], [recipient.ap_id])
  539. {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
  540. with_mocks([
  541. {
  542. Pleroma.Web.Streamer,
  543. [],
  544. [
  545. stream: fn _, _ -> nil end
  546. ]
  547. },
  548. {
  549. Pleroma.Web.Push,
  550. [],
  551. [
  552. send: fn _ -> nil end
  553. ]
  554. }
  555. ]) do
  556. {:ok, _create_activity, meta} =
  557. SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
  558. # The notification gets created
  559. assert [notification] = meta[:notifications]
  560. assert notification.activity_id == create_activity.id
  561. # But it is not sent out
  562. refute called(Pleroma.Web.Streamer.stream(["user", "user:notification"], notification))
  563. refute called(Pleroma.Web.Push.send(notification))
  564. # Same for the user chat stream
  565. assert [{topics, _}, _] = meta[:streamables]
  566. assert topics == ["user", "user:pleroma_chat"]
  567. refute called(Pleroma.Web.Streamer.stream(["user", "user:pleroma_chat"], :_))
  568. chat = Chat.get(author.id, recipient.ap_id)
  569. [cm_ref] = MessageReference.for_chat_query(chat) |> Repo.all()
  570. assert cm_ref.object.data["content"] == "hey"
  571. assert cm_ref.unread == false
  572. chat = Chat.get(recipient.id, author.ap_id)
  573. [cm_ref] = MessageReference.for_chat_query(chat) |> Repo.all()
  574. assert cm_ref.object.data["content"] == "hey"
  575. assert cm_ref.unread == true
  576. end
  577. end
  578. test "it creates a Chat for the local users and bumps the unread count" do
  579. author = insert(:user, local: false)
  580. recipient = insert(:user, local: true)
  581. {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
  582. {:ok, create_activity_data, _meta} =
  583. Builder.create(author, chat_message_data["id"], [recipient.ap_id])
  584. {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
  585. {:ok, _create_activity, _meta} =
  586. SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
  587. # An object is created
  588. assert Object.get_by_ap_id(chat_message_data["id"])
  589. # The remote user won't get a chat
  590. chat = Chat.get(author.id, recipient.ap_id)
  591. refute chat
  592. # The local user will get a chat
  593. chat = Chat.get(recipient.id, author.ap_id)
  594. assert chat
  595. author = insert(:user, local: true)
  596. recipient = insert(:user, local: true)
  597. {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
  598. {:ok, create_activity_data, _meta} =
  599. Builder.create(author, chat_message_data["id"], [recipient.ap_id])
  600. {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
  601. {:ok, _create_activity, _meta} =
  602. SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
  603. # Both users are local and get the chat
  604. chat = Chat.get(author.id, recipient.ap_id)
  605. assert chat
  606. chat = Chat.get(recipient.id, author.ap_id)
  607. assert chat
  608. end
  609. end
  610. describe "announce objects" do
  611. setup do
  612. poster = insert(:user)
  613. user = insert(:user)
  614. {:ok, post} = CommonAPI.post(poster, %{status: "hey"})
  615. {:ok, private_post} = CommonAPI.post(poster, %{status: "hey", visibility: "private"})
  616. {:ok, announce_data, _meta} = Builder.announce(user, post.object, public: true)
  617. {:ok, private_announce_data, _meta} =
  618. Builder.announce(user, private_post.object, public: false)
  619. {:ok, relay_announce_data, _meta} =
  620. Builder.announce(Pleroma.Web.ActivityPub.Relay.get_actor(), post.object, public: true)
  621. {:ok, announce, _meta} = ActivityPub.persist(announce_data, local: true)
  622. {:ok, private_announce, _meta} = ActivityPub.persist(private_announce_data, local: true)
  623. {:ok, relay_announce, _meta} = ActivityPub.persist(relay_announce_data, local: true)
  624. %{
  625. announce: announce,
  626. user: user,
  627. poster: poster,
  628. private_announce: private_announce,
  629. relay_announce: relay_announce
  630. }
  631. end
  632. test "adds the announce to the original object", %{announce: announce, user: user} do
  633. {:ok, announce, _} = SideEffects.handle(announce)
  634. object = Object.get_by_ap_id(announce.data["object"])
  635. assert object.data["announcement_count"] == 1
  636. assert user.ap_id in object.data["announcements"]
  637. end
  638. test "does not add the announce to the original object if the actor is a service actor", %{
  639. relay_announce: announce
  640. } do
  641. {:ok, announce, _} = SideEffects.handle(announce)
  642. object = Object.get_by_ap_id(announce.data["object"])
  643. assert object.data["announcement_count"] == nil
  644. end
  645. test "creates a notification", %{announce: announce, poster: poster} do
  646. {:ok, announce, _} = SideEffects.handle(announce)
  647. assert Repo.get_by(Notification, user_id: poster.id, activity_id: announce.id)
  648. end
  649. test "it streams out the announce", %{announce: announce} do
  650. with_mocks([
  651. {
  652. Pleroma.Web.Streamer,
  653. [],
  654. [
  655. stream: fn _, _ -> nil end
  656. ]
  657. },
  658. {
  659. Pleroma.Web.Push,
  660. [],
  661. [
  662. send: fn _ -> nil end
  663. ]
  664. }
  665. ]) do
  666. {:ok, announce, _} = SideEffects.handle(announce)
  667. assert called(Pleroma.Web.Streamer.stream(["user", "list"], announce))
  668. assert called(Pleroma.Web.Push.send(:_))
  669. end
  670. end
  671. end
  672. describe "removing a follower" do
  673. setup do
  674. user = insert(:user)
  675. followed = insert(:user)
  676. {:ok, _, _, follow_activity} = CommonAPI.follow(user, followed)
  677. {:ok, reject_data, []} = Builder.reject(followed, follow_activity)
  678. {:ok, reject, _meta} = ActivityPub.persist(reject_data, local: true)
  679. %{user: user, followed: followed, reject: reject}
  680. end
  681. test "", %{user: user, followed: followed, reject: reject} do
  682. assert User.following?(user, followed)
  683. assert Pleroma.FollowingRelationship.get(user, followed)
  684. {:ok, _, _} = SideEffects.handle(reject)
  685. refute User.following?(user, followed)
  686. refute Pleroma.FollowingRelationship.get(user, followed)
  687. assert User.get_follow_state(user, followed) == nil
  688. assert User.get_follow_state(user, followed, nil) == nil
  689. end
  690. end
  691. describe "removing a follower from remote" do
  692. setup do
  693. user = insert(:user)
  694. followed = insert(:user, local: false)
  695. # Mock a local-to-remote follow
  696. {:ok, follow_data, []} = Builder.follow(user, followed)
  697. follow_data =
  698. follow_data
  699. |> Map.put("state", "accept")
  700. {:ok, follow, _meta} = ActivityPub.persist(follow_data, local: true)
  701. {:ok, _, _} = SideEffects.handle(follow)
  702. # Mock a remote-to-local accept
  703. {:ok, accept_data, _} = Builder.accept(followed, follow)
  704. {:ok, accept, _} = ActivityPub.persist(accept_data, local: false)
  705. {:ok, _, _} = SideEffects.handle(accept)
  706. # Mock a remote-to-local reject
  707. {:ok, reject_data, []} = Builder.reject(followed, follow)
  708. {:ok, reject, _meta} = ActivityPub.persist(reject_data, local: false)
  709. %{user: user, followed: followed, reject: reject}
  710. end
  711. test "", %{user: user, followed: followed, reject: reject} do
  712. assert User.following?(user, followed)
  713. assert Pleroma.FollowingRelationship.get(user, followed)
  714. {:ok, _, _} = SideEffects.handle(reject)
  715. refute User.following?(user, followed)
  716. refute Pleroma.FollowingRelationship.get(user, followed)
  717. assert Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(user, followed).data["state"] ==
  718. "reject"
  719. assert User.get_follow_state(user, followed) == nil
  720. assert User.get_follow_state(user, followed, nil) == nil
  721. end
  722. end
  723. describe "Group actors" do
  724. setup do
  725. poster =
  726. insert(:user,
  727. local: false,
  728. nickname: "poster@example.com",
  729. ap_id: "https://example.com/users/poster"
  730. )
  731. group = insert(:user, actor_type: "Group")
  732. make_create = fn mentioned_users ->
  733. mentions = mentioned_users |> Enum.map(fn u -> "@#{u.nickname}" end) |> Enum.join(" ")
  734. {:ok, draft} = ActivityDraft.create(poster, %{status: "#{mentions} hey"})
  735. create_activity_data =
  736. Utils.make_create_data(draft.changes |> Map.put(:published, nil), %{})
  737. |> put_in(["object", "id"], "https://example.com/object")
  738. |> put_in(["id"], "https://example.com/activity")
  739. assert Enum.all?(mentioned_users, fn u -> u.ap_id in create_activity_data["to"] end)
  740. create_activity_data
  741. end
  742. %{poster: poster, group: group, make_create: make_create}
  743. end
  744. test "group should boost it", %{make_create: make_create, group: group} do
  745. create_activity_data = make_create.([group])
  746. {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
  747. {:ok, _create_activity, _meta} =
  748. SideEffects.handle(create_activity,
  749. local: false,
  750. object_data: create_activity_data["object"]
  751. )
  752. object = Object.normalize(create_activity, fetch: false)
  753. assert [announce] = get_announces_of_object(object)
  754. assert announce.actor == group.ap_id
  755. end
  756. test "remote group should not boost it", %{make_create: make_create, group: group} do
  757. remote_group =
  758. insert(:user, actor_type: "Group", local: false, nickname: "remotegroup@example.com")
  759. create_activity_data = make_create.([group, remote_group])
  760. {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
  761. {:ok, _create_activity, _meta} =
  762. SideEffects.handle(create_activity,
  763. local: false,
  764. object_data: create_activity_data["object"]
  765. )
  766. object = Object.normalize(create_activity, fetch: false)
  767. assert [announce] = get_announces_of_object(object)
  768. assert announce.actor == group.ap_id
  769. end
  770. test "group should not boost it if group is blocking poster", %{
  771. make_create: make_create,
  772. group: group,
  773. poster: poster
  774. } do
  775. {:ok, _} = CommonAPI.block(group, poster)
  776. create_activity_data = make_create.([group])
  777. {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
  778. {:ok, _create_activity, _meta} =
  779. SideEffects.handle(create_activity,
  780. local: false,
  781. object_data: create_activity_data["object"]
  782. )
  783. object = Object.normalize(create_activity, fetch: false)
  784. assert [] = get_announces_of_object(object)
  785. end
  786. end
  787. end