Fork of Pleroma with site-specific changes and feature branches https://git.pleroma.social/pleroma/pleroma
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

1461 строка
43KB

  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. defmodule Pleroma.Web.ActivityPub.ActivityPub do
  5. alias Pleroma.Activity
  6. alias Pleroma.Activity.Ir.Topics
  7. alias Pleroma.Config
  8. alias Pleroma.Constants
  9. alias Pleroma.Conversation
  10. alias Pleroma.Conversation.Participation
  11. alias Pleroma.Filter
  12. alias Pleroma.Maps
  13. alias Pleroma.Notification
  14. alias Pleroma.Object
  15. alias Pleroma.Object.Containment
  16. alias Pleroma.Object.Fetcher
  17. alias Pleroma.Pagination
  18. alias Pleroma.Repo
  19. alias Pleroma.Upload
  20. alias Pleroma.User
  21. alias Pleroma.Web.ActivityPub.MRF
  22. alias Pleroma.Web.ActivityPub.Transmogrifier
  23. alias Pleroma.Web.Streamer
  24. alias Pleroma.Web.WebFinger
  25. alias Pleroma.Workers.BackgroundWorker
  26. import Ecto.Query
  27. import Pleroma.Web.ActivityPub.Utils
  28. import Pleroma.Web.ActivityPub.Visibility
  29. require Logger
  30. require Pleroma.Constants
  31. defp get_recipients(%{"type" => "Create"} = data) do
  32. to = Map.get(data, "to", [])
  33. cc = Map.get(data, "cc", [])
  34. bcc = Map.get(data, "bcc", [])
  35. actor = Map.get(data, "actor", [])
  36. recipients = [to, cc, bcc, [actor]] |> Enum.concat() |> Enum.uniq()
  37. {recipients, to, cc}
  38. end
  39. defp get_recipients(data) do
  40. to = Map.get(data, "to", [])
  41. cc = Map.get(data, "cc", [])
  42. bcc = Map.get(data, "bcc", [])
  43. recipients = Enum.concat([to, cc, bcc])
  44. {recipients, to, cc}
  45. end
  46. defp check_actor_is_active(nil), do: true
  47. defp check_actor_is_active(actor) when is_binary(actor) do
  48. case User.get_cached_by_ap_id(actor) do
  49. %User{deactivated: deactivated} -> not deactivated
  50. _ -> false
  51. end
  52. end
  53. defp check_remote_limit(%{"object" => %{"content" => content}}) when not is_nil(content) do
  54. limit = Config.get([:instance, :remote_limit])
  55. String.length(content) <= limit
  56. end
  57. defp check_remote_limit(_), do: true
  58. def increase_note_count_if_public(actor, object) do
  59. if is_public?(object), do: User.increase_note_count(actor), else: {:ok, actor}
  60. end
  61. def decrease_note_count_if_public(actor, object) do
  62. if is_public?(object), do: User.decrease_note_count(actor), else: {:ok, actor}
  63. end
  64. defp increase_replies_count_if_reply(%{
  65. "object" => %{"inReplyTo" => reply_ap_id} = object,
  66. "type" => "Create"
  67. }) do
  68. if is_public?(object) do
  69. Object.increase_replies_count(reply_ap_id)
  70. end
  71. end
  72. defp increase_replies_count_if_reply(_create_data), do: :noop
  73. @object_types ~w[ChatMessage Question Answer Audio Video Event Article]
  74. @spec persist(map(), keyword()) :: {:ok, Activity.t() | Object.t()}
  75. def persist(%{"type" => type} = object, meta) when type in @object_types do
  76. with {:ok, object} <- Object.create(object) do
  77. {:ok, object, meta}
  78. end
  79. end
  80. def persist(object, meta) do
  81. with local <- Keyword.fetch!(meta, :local),
  82. {recipients, _, _} <- get_recipients(object),
  83. {:ok, activity} <-
  84. Repo.insert(%Activity{
  85. data: object,
  86. local: local,
  87. recipients: recipients,
  88. actor: object["actor"]
  89. }),
  90. # TODO: add tests for expired activities, when Note type will be supported in new pipeline
  91. {:ok, _} <- maybe_create_activity_expiration(activity) do
  92. {:ok, activity, meta}
  93. end
  94. end
  95. @spec insert(map(), boolean(), boolean(), boolean()) :: {:ok, Activity.t()} | {:error, any()}
  96. def insert(map, local \\ true, fake \\ false, bypass_actor_check \\ false) when is_map(map) do
  97. with nil <- Activity.normalize(map),
  98. map <- lazy_put_activity_defaults(map, fake),
  99. {_, true} <- {:actor_check, bypass_actor_check || check_actor_is_active(map["actor"])},
  100. {_, true} <- {:remote_limit_pass, check_remote_limit(map)},
  101. {:ok, map} <- MRF.filter(map),
  102. {recipients, _, _} = get_recipients(map),
  103. {:fake, false, map, recipients} <- {:fake, fake, map, recipients},
  104. {:containment, :ok} <- {:containment, Containment.contain_child(map)},
  105. {:ok, map, object} <- insert_full_object(map),
  106. {:ok, activity} <- insert_activity_with_expiration(map, local, recipients) do
  107. # Splice in the child object if we have one.
  108. activity = Maps.put_if_present(activity, :object, object)
  109. BackgroundWorker.enqueue("fetch_data_for_activity", %{"activity_id" => activity.id})
  110. {:ok, activity}
  111. else
  112. %Activity{} = activity ->
  113. {:ok, activity}
  114. {:actor_check, _} ->
  115. {:error, false}
  116. {:containment, _} = error ->
  117. error
  118. {:error, _} = error ->
  119. error
  120. {:fake, true, map, recipients} ->
  121. activity = %Activity{
  122. data: map,
  123. local: local,
  124. actor: map["actor"],
  125. recipients: recipients,
  126. id: "pleroma:fakeid"
  127. }
  128. Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
  129. {:ok, activity}
  130. {:remote_limit_pass, _} ->
  131. {:error, :remote_limit}
  132. {:reject, _} = e ->
  133. {:error, e}
  134. end
  135. end
  136. defp insert_activity_with_expiration(data, local, recipients) do
  137. struct = %Activity{
  138. data: data,
  139. local: local,
  140. actor: data["actor"],
  141. recipients: recipients
  142. }
  143. with {:ok, activity} <- Repo.insert(struct) do
  144. maybe_create_activity_expiration(activity)
  145. end
  146. end
  147. def notify_and_stream(activity) do
  148. Notification.create_notifications(activity)
  149. conversation = create_or_bump_conversation(activity, activity.actor)
  150. participations = get_participations(conversation)
  151. stream_out(activity)
  152. stream_out_participations(participations)
  153. end
  154. defp maybe_create_activity_expiration(
  155. %{data: %{"expires_at" => %DateTime{} = expires_at}} = activity
  156. ) do
  157. with {:ok, _job} <-
  158. Pleroma.Workers.PurgeExpiredActivity.enqueue(%{
  159. activity_id: activity.id,
  160. expires_at: expires_at
  161. }) do
  162. {:ok, activity}
  163. end
  164. end
  165. defp maybe_create_activity_expiration(activity), do: {:ok, activity}
  166. defp create_or_bump_conversation(activity, actor) do
  167. with {:ok, conversation} <- Conversation.create_or_bump_for(activity),
  168. %User{} = user <- User.get_cached_by_ap_id(actor) do
  169. Participation.mark_as_read(user, conversation)
  170. {:ok, conversation}
  171. end
  172. end
  173. defp get_participations({:ok, conversation}) do
  174. conversation
  175. |> Repo.preload(:participations, force: true)
  176. |> Map.get(:participations)
  177. end
  178. defp get_participations(_), do: []
  179. def stream_out_participations(participations) do
  180. participations =
  181. participations
  182. |> Repo.preload(:user)
  183. Streamer.stream("participation", participations)
  184. end
  185. def stream_out_participations(%Object{data: %{"context" => context}}, user) do
  186. with %Conversation{} = conversation <- Conversation.get_for_ap_id(context) do
  187. conversation = Repo.preload(conversation, :participations)
  188. last_activity_id =
  189. fetch_latest_direct_activity_id_for_context(conversation.ap_id, %{
  190. user: user,
  191. blocking_user: user
  192. })
  193. if last_activity_id do
  194. stream_out_participations(conversation.participations)
  195. end
  196. end
  197. end
  198. def stream_out_participations(_, _), do: :noop
  199. def stream_out(%Activity{data: %{"type" => data_type}} = activity)
  200. when data_type in ["Create", "Announce", "Delete"] do
  201. activity
  202. |> Topics.get_activity_topics()
  203. |> Streamer.stream(activity)
  204. end
  205. def stream_out(_activity) do
  206. :noop
  207. end
  208. @spec create(map(), boolean()) :: {:ok, Activity.t()} | {:error, any()}
  209. def create(params, fake \\ false) do
  210. with {:ok, result} <- Repo.transaction(fn -> do_create(params, fake) end) do
  211. result
  212. end
  213. end
  214. defp do_create(%{to: to, actor: actor, context: context, object: object} = params, fake) do
  215. additional = params[:additional] || %{}
  216. # only accept false as false value
  217. local = !(params[:local] == false)
  218. published = params[:published]
  219. quick_insert? = Config.get([:env]) == :benchmark
  220. create_data =
  221. make_create_data(
  222. %{to: to, actor: actor, published: published, context: context, object: object},
  223. additional
  224. )
  225. with {:ok, activity} <- insert(create_data, local, fake),
  226. {:fake, false, activity} <- {:fake, fake, activity},
  227. _ <- increase_replies_count_if_reply(create_data),
  228. {:quick_insert, false, activity} <- {:quick_insert, quick_insert?, activity},
  229. {:ok, _actor} <- increase_note_count_if_public(actor, activity),
  230. _ <- notify_and_stream(activity),
  231. :ok <- maybe_federate(activity) do
  232. {:ok, activity}
  233. else
  234. {:quick_insert, true, activity} ->
  235. {:ok, activity}
  236. {:fake, true, activity} ->
  237. {:ok, activity}
  238. {:error, message} ->
  239. Repo.rollback(message)
  240. end
  241. end
  242. @spec listen(map()) :: {:ok, Activity.t()} | {:error, any()}
  243. def listen(%{to: to, actor: actor, context: context, object: object} = params) do
  244. additional = params[:additional] || %{}
  245. # only accept false as false value
  246. local = !(params[:local] == false)
  247. published = params[:published]
  248. listen_data =
  249. make_listen_data(
  250. %{to: to, actor: actor, published: published, context: context, object: object},
  251. additional
  252. )
  253. with {:ok, activity} <- insert(listen_data, local),
  254. _ <- notify_and_stream(activity),
  255. :ok <- maybe_federate(activity) do
  256. {:ok, activity}
  257. end
  258. end
  259. @spec unfollow(User.t(), User.t(), String.t() | nil, boolean()) ::
  260. {:ok, Activity.t()} | nil | {:error, any()}
  261. def unfollow(follower, followed, activity_id \\ nil, local \\ true) do
  262. with {:ok, result} <-
  263. Repo.transaction(fn -> do_unfollow(follower, followed, activity_id, local) end) do
  264. result
  265. end
  266. end
  267. defp do_unfollow(follower, followed, activity_id, local) do
  268. with %Activity{} = follow_activity <- fetch_latest_follow(follower, followed),
  269. {:ok, follow_activity} <- update_follow_state(follow_activity, "cancelled"),
  270. unfollow_data <- make_unfollow_data(follower, followed, follow_activity, activity_id),
  271. {:ok, activity} <- insert(unfollow_data, local),
  272. _ <- notify_and_stream(activity),
  273. :ok <- maybe_federate(activity) do
  274. {:ok, activity}
  275. else
  276. nil -> nil
  277. {:error, error} -> Repo.rollback(error)
  278. end
  279. end
  280. @spec flag(map()) :: {:ok, Activity.t()} | {:error, any()}
  281. def flag(
  282. %{
  283. actor: actor,
  284. context: _context,
  285. account: account,
  286. statuses: statuses,
  287. content: content
  288. } = params
  289. ) do
  290. # only accept false as false value
  291. local = !(params[:local] == false)
  292. forward = !(params[:forward] == false)
  293. additional = params[:additional] || %{}
  294. additional =
  295. if forward do
  296. Map.merge(additional, %{"to" => [], "cc" => [account.ap_id]})
  297. else
  298. Map.merge(additional, %{"to" => [], "cc" => []})
  299. end
  300. with flag_data <- make_flag_data(params, additional),
  301. {:ok, activity} <- insert(flag_data, local),
  302. {:ok, stripped_activity} <- strip_report_status_data(activity),
  303. _ <- notify_and_stream(activity),
  304. :ok <- maybe_federate(stripped_activity) do
  305. User.all_superusers()
  306. |> Enum.filter(fn user -> not is_nil(user.email) end)
  307. |> Enum.each(fn superuser ->
  308. superuser
  309. |> Pleroma.Emails.AdminEmail.report(actor, account, statuses, content)
  310. |> Pleroma.Emails.Mailer.deliver_async()
  311. end)
  312. {:ok, activity}
  313. end
  314. end
  315. @spec move(User.t(), User.t(), boolean()) :: {:ok, Activity.t()} | {:error, any()}
  316. def move(%User{} = origin, %User{} = target, local \\ true) do
  317. params = %{
  318. "type" => "Move",
  319. "actor" => origin.ap_id,
  320. "object" => origin.ap_id,
  321. "target" => target.ap_id
  322. }
  323. with true <- origin.ap_id in target.also_known_as,
  324. {:ok, activity} <- insert(params, local),
  325. _ <- notify_and_stream(activity) do
  326. maybe_federate(activity)
  327. BackgroundWorker.enqueue("move_following", %{
  328. "origin_id" => origin.id,
  329. "target_id" => target.id
  330. })
  331. {:ok, activity}
  332. else
  333. false -> {:error, "Target account must have the origin in `alsoKnownAs`"}
  334. err -> err
  335. end
  336. end
  337. def fetch_activities_for_context_query(context, opts) do
  338. public = [Constants.as_public()]
  339. recipients =
  340. if opts[:user],
  341. do: [opts[:user].ap_id | User.following(opts[:user])] ++ public,
  342. else: public
  343. from(activity in Activity)
  344. |> maybe_preload_objects(opts)
  345. |> maybe_preload_bookmarks(opts)
  346. |> maybe_set_thread_muted_field(opts)
  347. |> restrict_blocked(opts)
  348. |> restrict_recipients(recipients, opts[:user])
  349. |> restrict_filtered(opts)
  350. |> where(
  351. [activity],
  352. fragment(
  353. "?->>'type' = ? and ?->>'context' = ?",
  354. activity.data,
  355. "Create",
  356. activity.data,
  357. ^context
  358. )
  359. )
  360. |> exclude_poll_votes(opts)
  361. |> exclude_id(opts)
  362. |> order_by([activity], desc: activity.id)
  363. end
  364. @spec fetch_activities_for_context(String.t(), keyword() | map()) :: [Activity.t()]
  365. def fetch_activities_for_context(context, opts \\ %{}) do
  366. context
  367. |> fetch_activities_for_context_query(opts)
  368. |> Repo.all()
  369. end
  370. @spec fetch_latest_direct_activity_id_for_context(String.t(), keyword() | map()) ::
  371. FlakeId.Ecto.CompatType.t() | nil
  372. def fetch_latest_direct_activity_id_for_context(context, opts \\ %{}) do
  373. context
  374. |> fetch_activities_for_context_query(Map.merge(%{skip_preload: true}, opts))
  375. |> restrict_visibility(%{visibility: "direct"})
  376. |> limit(1)
  377. |> select([a], a.id)
  378. |> Repo.one()
  379. end
  380. @spec fetch_public_or_unlisted_activities(map(), Pagination.type()) :: [Activity.t()]
  381. def fetch_public_or_unlisted_activities(opts \\ %{}, pagination \\ :keyset) do
  382. opts = Map.delete(opts, :user)
  383. [Constants.as_public()]
  384. |> fetch_activities_query(opts)
  385. |> restrict_unlisted(opts)
  386. |> Pagination.fetch_paginated(opts, pagination)
  387. end
  388. @spec fetch_public_activities(map(), Pagination.type()) :: [Activity.t()]
  389. def fetch_public_activities(opts \\ %{}, pagination \\ :keyset) do
  390. opts
  391. |> Map.put(:restrict_unlisted, true)
  392. |> fetch_public_or_unlisted_activities(pagination)
  393. end
  394. @valid_visibilities ~w[direct unlisted public private]
  395. defp restrict_visibility(query, %{visibility: visibility})
  396. when is_list(visibility) do
  397. if Enum.all?(visibility, &(&1 in @valid_visibilities)) do
  398. from(
  399. a in query,
  400. where:
  401. fragment(
  402. "activity_visibility(?, ?, ?) = ANY (?)",
  403. a.actor,
  404. a.recipients,
  405. a.data,
  406. ^visibility
  407. )
  408. )
  409. else
  410. Logger.error("Could not restrict visibility to #{visibility}")
  411. end
  412. end
  413. defp restrict_visibility(query, %{visibility: visibility})
  414. when visibility in @valid_visibilities do
  415. from(
  416. a in query,
  417. where:
  418. fragment("activity_visibility(?, ?, ?) = ?", a.actor, a.recipients, a.data, ^visibility)
  419. )
  420. end
  421. defp restrict_visibility(_query, %{visibility: visibility})
  422. when visibility not in @valid_visibilities do
  423. Logger.error("Could not restrict visibility to #{visibility}")
  424. end
  425. defp restrict_visibility(query, _visibility), do: query
  426. defp exclude_visibility(query, %{exclude_visibilities: visibility})
  427. when is_list(visibility) do
  428. if Enum.all?(visibility, &(&1 in @valid_visibilities)) do
  429. from(
  430. a in query,
  431. where:
  432. not fragment(
  433. "activity_visibility(?, ?, ?) = ANY (?)",
  434. a.actor,
  435. a.recipients,
  436. a.data,
  437. ^visibility
  438. )
  439. )
  440. else
  441. Logger.error("Could not exclude visibility to #{visibility}")
  442. query
  443. end
  444. end
  445. defp exclude_visibility(query, %{exclude_visibilities: visibility})
  446. when visibility in @valid_visibilities do
  447. from(
  448. a in query,
  449. where:
  450. not fragment(
  451. "activity_visibility(?, ?, ?) = ?",
  452. a.actor,
  453. a.recipients,
  454. a.data,
  455. ^visibility
  456. )
  457. )
  458. end
  459. defp exclude_visibility(query, %{exclude_visibilities: visibility})
  460. when visibility not in [nil | @valid_visibilities] do
  461. Logger.error("Could not exclude visibility to #{visibility}")
  462. query
  463. end
  464. defp exclude_visibility(query, _visibility), do: query
  465. defp restrict_thread_visibility(query, _, %{skip_thread_containment: true} = _),
  466. do: query
  467. defp restrict_thread_visibility(query, %{user: %User{skip_thread_containment: true}}, _),
  468. do: query
  469. defp restrict_thread_visibility(query, %{user: %User{ap_id: ap_id}}, _) do
  470. from(
  471. a in query,
  472. where: fragment("thread_visibility(?, (?)->>'id') = true", ^ap_id, a.data)
  473. )
  474. end
  475. defp restrict_thread_visibility(query, _, _), do: query
  476. def fetch_user_abstract_activities(user, reading_user, params \\ %{}) do
  477. params =
  478. params
  479. |> Map.put(:user, reading_user)
  480. |> Map.put(:actor_id, user.ap_id)
  481. %{
  482. godmode: params[:godmode],
  483. reading_user: reading_user
  484. }
  485. |> user_activities_recipients()
  486. |> fetch_activities(params)
  487. |> Enum.reverse()
  488. end
  489. def fetch_user_activities(user, reading_user, params \\ %{}) do
  490. params =
  491. params
  492. |> Map.put(:type, ["Create", "Announce"])
  493. |> Map.put(:user, reading_user)
  494. |> Map.put(:actor_id, user.ap_id)
  495. |> Map.put(:pinned_activity_ids, user.pinned_activities)
  496. params =
  497. if User.blocks?(reading_user, user) do
  498. params
  499. else
  500. params
  501. |> Map.put(:blocking_user, reading_user)
  502. |> Map.put(:muting_user, reading_user)
  503. end
  504. %{
  505. godmode: params[:godmode],
  506. reading_user: reading_user
  507. }
  508. |> user_activities_recipients()
  509. |> fetch_activities(params)
  510. |> Enum.reverse()
  511. end
  512. def fetch_statuses(reading_user, params) do
  513. params = Map.put(params, :type, ["Create", "Announce"])
  514. %{
  515. godmode: params[:godmode],
  516. reading_user: reading_user
  517. }
  518. |> user_activities_recipients()
  519. |> fetch_activities(params, :offset)
  520. |> Enum.reverse()
  521. end
  522. defp user_activities_recipients(%{godmode: true}), do: []
  523. defp user_activities_recipients(%{reading_user: reading_user}) do
  524. if reading_user do
  525. [Constants.as_public(), reading_user.ap_id | User.following(reading_user)]
  526. else
  527. [Constants.as_public()]
  528. end
  529. end
  530. defp restrict_announce_object_actor(_query, %{announce_filtering_user: _, skip_preload: true}) do
  531. raise "Can't use the child object without preloading!"
  532. end
  533. defp restrict_announce_object_actor(query, %{announce_filtering_user: %{ap_id: actor}}) do
  534. from(
  535. [activity, object] in query,
  536. where:
  537. fragment(
  538. "?->>'type' != ? or ?->>'actor' != ?",
  539. activity.data,
  540. "Announce",
  541. object.data,
  542. ^actor
  543. )
  544. )
  545. end
  546. defp restrict_announce_object_actor(query, _), do: query
  547. defp restrict_since(query, %{since_id: ""}), do: query
  548. defp restrict_since(query, %{since_id: since_id}) do
  549. from(activity in query, where: activity.id > ^since_id)
  550. end
  551. defp restrict_since(query, _), do: query
  552. defp restrict_tag_reject(_query, %{tag_reject: _tag_reject, skip_preload: true}) do
  553. raise "Can't use the child object without preloading!"
  554. end
  555. defp restrict_tag_reject(query, %{tag_reject: [_ | _] = tag_reject}) do
  556. from(
  557. [_activity, object] in query,
  558. where: fragment("not (?)->'tag' \\?| (?)", object.data, ^tag_reject)
  559. )
  560. end
  561. defp restrict_tag_reject(query, _), do: query
  562. defp restrict_tag_all(_query, %{tag_all: _tag_all, skip_preload: true}) do
  563. raise "Can't use the child object without preloading!"
  564. end
  565. defp restrict_tag_all(query, %{tag_all: [_ | _] = tag_all}) do
  566. from(
  567. [_activity, object] in query,
  568. where: fragment("(?)->'tag' \\?& (?)", object.data, ^tag_all)
  569. )
  570. end
  571. defp restrict_tag_all(query, _), do: query
  572. defp restrict_tag(_query, %{tag: _tag, skip_preload: true}) do
  573. raise "Can't use the child object without preloading!"
  574. end
  575. defp restrict_tag(query, %{tag: tag}) when is_list(tag) do
  576. from(
  577. [_activity, object] in query,
  578. where: fragment("(?)->'tag' \\?| (?)", object.data, ^tag)
  579. )
  580. end
  581. defp restrict_tag(query, %{tag: tag}) when is_binary(tag) do
  582. from(
  583. [_activity, object] in query,
  584. where: fragment("(?)->'tag' \\? (?)", object.data, ^tag)
  585. )
  586. end
  587. defp restrict_tag(query, _), do: query
  588. defp restrict_recipients(query, [], _user), do: query
  589. defp restrict_recipients(query, recipients, nil) do
  590. from(activity in query, where: fragment("? && ?", ^recipients, activity.recipients))
  591. end
  592. defp restrict_recipients(query, recipients, user) do
  593. from(
  594. activity in query,
  595. where: fragment("? && ?", ^recipients, activity.recipients),
  596. or_where: activity.actor == ^user.ap_id
  597. )
  598. end
  599. defp restrict_local(query, %{local_only: true}) do
  600. from(activity in query, where: activity.local == true)
  601. end
  602. defp restrict_local(query, _), do: query
  603. defp restrict_actor(query, %{actor_id: actor_id}) do
  604. from(activity in query, where: activity.actor == ^actor_id)
  605. end
  606. defp restrict_actor(query, _), do: query
  607. defp restrict_type(query, %{type: type}) when is_binary(type) do
  608. from(activity in query, where: fragment("?->>'type' = ?", activity.data, ^type))
  609. end
  610. defp restrict_type(query, %{type: type}) do
  611. from(activity in query, where: fragment("?->>'type' = ANY(?)", activity.data, ^type))
  612. end
  613. defp restrict_type(query, _), do: query
  614. defp restrict_state(query, %{state: state}) do
  615. from(activity in query, where: fragment("?->>'state' = ?", activity.data, ^state))
  616. end
  617. defp restrict_state(query, _), do: query
  618. defp restrict_favorited_by(query, %{favorited_by: ap_id}) do
  619. from(
  620. [_activity, object] in query,
  621. where: fragment("(?)->'likes' \\? (?)", object.data, ^ap_id)
  622. )
  623. end
  624. defp restrict_favorited_by(query, _), do: query
  625. defp restrict_media(_query, %{only_media: _val, skip_preload: true}) do
  626. raise "Can't use the child object without preloading!"
  627. end
  628. defp restrict_media(query, %{only_media: true}) do
  629. from(
  630. [activity, object] in query,
  631. where: fragment("(?)->>'type' = ?", activity.data, "Create"),
  632. where: fragment("not (?)->'attachment' = (?)", object.data, ^[])
  633. )
  634. end
  635. defp restrict_media(query, _), do: query
  636. defp restrict_replies(query, %{exclude_replies: true}) do
  637. from(
  638. [_activity, object] in query,
  639. where: fragment("?->>'inReplyTo' is null", object.data)
  640. )
  641. end
  642. defp restrict_replies(query, %{
  643. reply_filtering_user: %User{} = user,
  644. reply_visibility: "self"
  645. }) do
  646. from(
  647. [activity, object] in query,
  648. where:
  649. fragment(
  650. "?->>'inReplyTo' is null OR ? = ANY(?)",
  651. object.data,
  652. ^user.ap_id,
  653. activity.recipients
  654. )
  655. )
  656. end
  657. defp restrict_replies(query, %{
  658. reply_filtering_user: %User{} = user,
  659. reply_visibility: "following"
  660. }) do
  661. from(
  662. [activity, object] in query,
  663. where:
  664. fragment(
  665. """
  666. ?->>'type' != 'Create' -- This isn't a Create
  667. OR ?->>'inReplyTo' is null -- this isn't a reply
  668. OR ? && array_remove(?, ?) -- The recipient is us or one of our friends,
  669. -- unless they are the author (because authors
  670. -- are also part of the recipients). This leads
  671. -- to a bug that self-replies by friends won't
  672. -- show up.
  673. OR ? = ? -- The actor is us
  674. """,
  675. activity.data,
  676. object.data,
  677. ^[user.ap_id | User.get_cached_user_friends_ap_ids(user)],
  678. activity.recipients,
  679. activity.actor,
  680. activity.actor,
  681. ^user.ap_id
  682. )
  683. )
  684. end
  685. defp restrict_replies(query, _), do: query
  686. defp restrict_reblogs(query, %{exclude_reblogs: true}) do
  687. from(activity in query, where: fragment("?->>'type' != 'Announce'", activity.data))
  688. end
  689. defp restrict_reblogs(query, _), do: query
  690. defp restrict_muted(query, %{with_muted: true}), do: query
  691. defp restrict_muted(query, %{muting_user: %User{} = user} = opts) do
  692. mutes = opts[:muted_users_ap_ids] || User.muted_users_ap_ids(user)
  693. query =
  694. from([activity] in query,
  695. where: fragment("not (? = ANY(?))", activity.actor, ^mutes),
  696. where:
  697. fragment(
  698. "not (?->'to' \\?| ?) or ? = ?",
  699. activity.data,
  700. ^mutes,
  701. activity.actor,
  702. ^user.ap_id
  703. )
  704. )
  705. unless opts[:skip_preload] do
  706. from([thread_mute: tm] in query, where: is_nil(tm.user_id))
  707. else
  708. query
  709. end
  710. end
  711. defp restrict_muted(query, _), do: query
  712. defp restrict_blocked(query, %{blocking_user: %User{} = user} = opts) do
  713. blocked_ap_ids = opts[:blocked_users_ap_ids] || User.blocked_users_ap_ids(user)
  714. domain_blocks = user.domain_blocks || []
  715. following_ap_ids = User.get_friends_ap_ids(user)
  716. query =
  717. if has_named_binding?(query, :object), do: query, else: Activity.with_joined_object(query)
  718. from(
  719. [activity, object: o] in query,
  720. where: fragment("not (? = ANY(?))", activity.actor, ^blocked_ap_ids),
  721. where:
  722. fragment(
  723. "((not (? && ?)) or ? = ?)",
  724. activity.recipients,
  725. ^blocked_ap_ids,
  726. activity.actor,
  727. ^user.ap_id
  728. ),
  729. where:
  730. fragment(
  731. "recipients_contain_blocked_domains(?, ?) = false",
  732. activity.recipients,
  733. ^domain_blocks
  734. ),
  735. where:
  736. fragment(
  737. "not (?->>'type' = 'Announce' and ?->'to' \\?| ?)",
  738. activity.data,
  739. activity.data,
  740. ^blocked_ap_ids
  741. ),
  742. where:
  743. fragment(
  744. "(not (split_part(?, '/', 3) = ANY(?))) or ? = ANY(?)",
  745. activity.actor,
  746. ^domain_blocks,
  747. activity.actor,
  748. ^following_ap_ids
  749. ),
  750. where:
  751. fragment(
  752. "(not (split_part(?->>'actor', '/', 3) = ANY(?))) or (?->>'actor') = ANY(?)",
  753. o.data,
  754. ^domain_blocks,
  755. o.data,
  756. ^following_ap_ids
  757. )
  758. )
  759. end
  760. defp restrict_blocked(query, _), do: query
  761. defp restrict_unlisted(query, %{restrict_unlisted: true}) do
  762. from(
  763. activity in query,
  764. where:
  765. fragment(
  766. "not (coalesce(?->'cc', '{}'::jsonb) \\?| ?)",
  767. activity.data,
  768. ^[Constants.as_public()]
  769. )
  770. )
  771. end
  772. defp restrict_unlisted(query, _), do: query
  773. defp restrict_pinned(query, %{pinned: true, pinned_activity_ids: ids}) do
  774. from(activity in query, where: activity.id in ^ids)
  775. end
  776. defp restrict_pinned(query, _), do: query
  777. defp restrict_muted_reblogs(query, %{muting_user: %User{} = user} = opts) do
  778. muted_reblogs = opts[:reblog_muted_users_ap_ids] || User.reblog_muted_users_ap_ids(user)
  779. from(
  780. activity in query,
  781. where:
  782. fragment(
  783. "not ( ?->>'type' = 'Announce' and ? = ANY(?))",
  784. activity.data,
  785. activity.actor,
  786. ^muted_reblogs
  787. )
  788. )
  789. end
  790. defp restrict_muted_reblogs(query, _), do: query
  791. defp restrict_instance(query, %{instance: instance}) when is_binary(instance) do
  792. from(
  793. activity in query,
  794. where: fragment("split_part(actor::text, '/'::text, 3) = ?", ^instance)
  795. )
  796. end
  797. defp restrict_instance(query, _), do: query
  798. defp restrict_filtered(query, %{user: %User{} = user}) do
  799. case Filter.compose_regex(user) do
  800. nil ->
  801. query
  802. regex ->
  803. from([activity, object] in query,
  804. where:
  805. fragment("not(?->>'content' ~* ?)", object.data, ^regex) or
  806. activity.actor == ^user.ap_id
  807. )
  808. end
  809. end
  810. defp restrict_filtered(query, %{blocking_user: %User{} = user}) do
  811. restrict_filtered(query, %{user: user})
  812. end
  813. defp restrict_filtered(query, _), do: query
  814. defp exclude_poll_votes(query, %{include_poll_votes: true}), do: query
  815. defp exclude_poll_votes(query, _) do
  816. if has_named_binding?(query, :object) do
  817. from([activity, object: o] in query,
  818. where: fragment("not(?->>'type' = ?)", o.data, "Answer")
  819. )
  820. else
  821. query
  822. end
  823. end
  824. defp exclude_chat_messages(query, %{include_chat_messages: true}), do: query
  825. defp exclude_chat_messages(query, _) do
  826. if has_named_binding?(query, :object) do
  827. from([activity, object: o] in query,
  828. where: fragment("not(?->>'type' = ?)", o.data, "ChatMessage")
  829. )
  830. else
  831. query
  832. end
  833. end
  834. defp exclude_invisible_actors(query, %{invisible_actors: true}), do: query
  835. defp exclude_invisible_actors(query, _opts) do
  836. invisible_ap_ids =
  837. User.Query.build(%{invisible: true, select: [:ap_id]})
  838. |> Repo.all()
  839. |> Enum.map(fn %{ap_id: ap_id} -> ap_id end)
  840. from([activity] in query, where: activity.actor not in ^invisible_ap_ids)
  841. end
  842. defp exclude_id(query, %{exclude_id: id}) when is_binary(id) do
  843. from(activity in query, where: activity.id != ^id)
  844. end
  845. defp exclude_id(query, _), do: query
  846. defp maybe_preload_objects(query, %{skip_preload: true}), do: query
  847. defp maybe_preload_objects(query, _) do
  848. query
  849. |> Activity.with_preloaded_object()
  850. end
  851. defp maybe_preload_bookmarks(query, %{skip_preload: true}), do: query
  852. defp maybe_preload_bookmarks(query, opts) do
  853. query
  854. |> Activity.with_preloaded_bookmark(opts[:user])
  855. end
  856. defp maybe_preload_report_notes(query, %{preload_report_notes: true}) do
  857. query
  858. |> Activity.with_preloaded_report_notes()
  859. end
  860. defp maybe_preload_report_notes(query, _), do: query
  861. defp maybe_set_thread_muted_field(query, %{skip_preload: true}), do: query
  862. defp maybe_set_thread_muted_field(query, opts) do
  863. query
  864. |> Activity.with_set_thread_muted_field(opts[:muting_user] || opts[:user])
  865. end
  866. defp maybe_order(query, %{order: :desc}) do
  867. query
  868. |> order_by(desc: :id)
  869. end
  870. defp maybe_order(query, %{order: :asc}) do
  871. query
  872. |> order_by(asc: :id)
  873. end
  874. defp maybe_order(query, _), do: query
  875. defp fetch_activities_query_ap_ids_ops(opts) do
  876. source_user = opts[:muting_user]
  877. ap_id_relationships = if source_user, do: [:mute, :reblog_mute], else: []
  878. ap_id_relationships =
  879. if opts[:blocking_user] && opts[:blocking_user] == source_user do
  880. [:block | ap_id_relationships]
  881. else
  882. ap_id_relationships
  883. end
  884. preloaded_ap_ids = User.outgoing_relationships_ap_ids(source_user, ap_id_relationships)
  885. restrict_blocked_opts = Map.merge(%{blocked_users_ap_ids: preloaded_ap_ids[:block]}, opts)
  886. restrict_muted_opts = Map.merge(%{muted_users_ap_ids: preloaded_ap_ids[:mute]}, opts)
  887. restrict_muted_reblogs_opts =
  888. Map.merge(%{reblog_muted_users_ap_ids: preloaded_ap_ids[:reblog_mute]}, opts)
  889. {restrict_blocked_opts, restrict_muted_opts, restrict_muted_reblogs_opts}
  890. end
  891. def fetch_activities_query(recipients, opts \\ %{}) do
  892. {restrict_blocked_opts, restrict_muted_opts, restrict_muted_reblogs_opts} =
  893. fetch_activities_query_ap_ids_ops(opts)
  894. config = %{
  895. skip_thread_containment: Config.get([:instance, :skip_thread_containment])
  896. }
  897. Activity
  898. |> maybe_preload_objects(opts)
  899. |> maybe_preload_bookmarks(opts)
  900. |> maybe_preload_report_notes(opts)
  901. |> maybe_set_thread_muted_field(opts)
  902. |> maybe_order(opts)
  903. |> restrict_recipients(recipients, opts[:user])
  904. |> restrict_replies(opts)
  905. |> restrict_tag(opts)
  906. |> restrict_tag_reject(opts)
  907. |> restrict_tag_all(opts)
  908. |> restrict_since(opts)
  909. |> restrict_local(opts)
  910. |> restrict_actor(opts)
  911. |> restrict_type(opts)
  912. |> restrict_state(opts)
  913. |> restrict_favorited_by(opts)
  914. |> restrict_blocked(restrict_blocked_opts)
  915. |> restrict_muted(restrict_muted_opts)
  916. |> restrict_filtered(opts)
  917. |> restrict_media(opts)
  918. |> restrict_visibility(opts)
  919. |> restrict_thread_visibility(opts, config)
  920. |> restrict_reblogs(opts)
  921. |> restrict_pinned(opts)
  922. |> restrict_muted_reblogs(restrict_muted_reblogs_opts)
  923. |> restrict_instance(opts)
  924. |> restrict_announce_object_actor(opts)
  925. |> restrict_filtered(opts)
  926. |> Activity.restrict_deactivated_users()
  927. |> exclude_poll_votes(opts)
  928. |> exclude_chat_messages(opts)
  929. |> exclude_invisible_actors(opts)
  930. |> exclude_visibility(opts)
  931. end
  932. def fetch_activities(recipients, opts \\ %{}, pagination \\ :keyset) do
  933. list_memberships = Pleroma.List.memberships(opts[:user])
  934. fetch_activities_query(recipients ++ list_memberships, opts)
  935. |> Pagination.fetch_paginated(opts, pagination)
  936. |> Enum.reverse()
  937. |> maybe_update_cc(list_memberships, opts[:user])
  938. end
  939. @doc """
  940. Fetch favorites activities of user with order by sort adds to favorites
  941. """
  942. @spec fetch_favourites(User.t(), map(), Pagination.type()) :: list(Activity.t())
  943. def fetch_favourites(user, params \\ %{}, pagination \\ :keyset) do
  944. user.ap_id
  945. |> Activity.Queries.by_actor()
  946. |> Activity.Queries.by_type("Like")
  947. |> Activity.with_joined_object()
  948. |> Object.with_joined_activity()
  949. |> select([like, object, activity], %{activity | object: object, pagination_id: like.id})
  950. |> order_by([like, _, _], desc_nulls_last: like.id)
  951. |> Pagination.fetch_paginated(
  952. Map.merge(params, %{skip_order: true}),
  953. pagination
  954. )
  955. end
  956. defp maybe_update_cc(activities, [_ | _] = list_memberships, %User{ap_id: user_ap_id}) do
  957. Enum.map(activities, fn
  958. %{data: %{"bcc" => [_ | _] = bcc}} = activity ->
  959. if Enum.any?(bcc, &(&1 in list_memberships)) do
  960. update_in(activity.data["cc"], &[user_ap_id | &1])
  961. else
  962. activity
  963. end
  964. activity ->
  965. activity
  966. end)
  967. end
  968. defp maybe_update_cc(activities, _, _), do: activities
  969. defp fetch_activities_bounded_query(query, recipients, recipients_with_public) do
  970. from(activity in query,
  971. where:
  972. fragment("? && ?", activity.recipients, ^recipients) or
  973. (fragment("? && ?", activity.recipients, ^recipients_with_public) and
  974. ^Constants.as_public() in activity.recipients)
  975. )
  976. end
  977. def fetch_activities_bounded(
  978. recipients,
  979. recipients_with_public,
  980. opts \\ %{},
  981. pagination \\ :keyset
  982. ) do
  983. fetch_activities_query([], opts)
  984. |> fetch_activities_bounded_query(recipients, recipients_with_public)
  985. |> Pagination.fetch_paginated(opts, pagination)
  986. |> Enum.reverse()
  987. end
  988. @spec upload(Upload.source(), keyword()) :: {:ok, Object.t()} | {:error, any()}
  989. def upload(file, opts \\ []) do
  990. with {:ok, data} <- Upload.store(file, opts) do
  991. obj_data = Maps.put_if_present(data, "actor", opts[:actor])
  992. Repo.insert(%Object{data: obj_data})
  993. end
  994. end
  995. @spec get_actor_url(any()) :: binary() | nil
  996. defp get_actor_url(url) when is_binary(url), do: url
  997. defp get_actor_url(%{"href" => href}) when is_binary(href), do: href
  998. defp get_actor_url(url) when is_list(url) do
  999. url
  1000. |> List.first()
  1001. |> get_actor_url()
  1002. end
  1003. defp get_actor_url(_url), do: nil
  1004. defp object_to_user_data(data) do
  1005. avatar =
  1006. data["icon"]["url"] &&
  1007. %{
  1008. "type" => "Image",
  1009. "url" => [%{"href" => data["icon"]["url"]}]
  1010. }
  1011. banner =
  1012. data["image"]["url"] &&
  1013. %{
  1014. "type" => "Image",
  1015. "url" => [%{"href" => data["image"]["url"]}]
  1016. }
  1017. fields =
  1018. data
  1019. |> Map.get("attachment", [])
  1020. |> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end)
  1021. |> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end)
  1022. emojis =
  1023. data
  1024. |> Map.get("tag", [])
  1025. |> Enum.filter(fn
  1026. %{"type" => "Emoji"} -> true
  1027. _ -> false
  1028. end)
  1029. |> Map.new(fn %{"icon" => %{"url" => url}, "name" => name} ->
  1030. {String.trim(name, ":"), url}
  1031. end)
  1032. is_locked = data["manuallyApprovesFollowers"] || false
  1033. capabilities = data["capabilities"] || %{}
  1034. accepts_chat_messages = capabilities["acceptsChatMessages"]
  1035. data = Transmogrifier.maybe_fix_user_object(data)
  1036. is_discoverable = data["discoverable"] || false
  1037. invisible = data["invisible"] || false
  1038. actor_type = data["type"] || "Person"
  1039. public_key =
  1040. if is_map(data["publicKey"]) && is_binary(data["publicKey"]["publicKeyPem"]) do
  1041. data["publicKey"]["publicKeyPem"]
  1042. else
  1043. nil
  1044. end
  1045. shared_inbox =
  1046. if is_map(data["endpoints"]) && is_binary(data["endpoints"]["sharedInbox"]) do
  1047. data["endpoints"]["sharedInbox"]
  1048. else
  1049. nil
  1050. end
  1051. user_data = %{
  1052. ap_id: data["id"],
  1053. uri: get_actor_url(data["url"]),
  1054. ap_enabled: true,
  1055. banner: banner,
  1056. fields: fields,
  1057. emoji: emojis,
  1058. is_locked: is_locked,
  1059. is_discoverable: is_discoverable,
  1060. invisible: invisible,
  1061. avatar: avatar,
  1062. name: data["name"],
  1063. follower_address: data["followers"],
  1064. following_address: data["following"],
  1065. bio: data["summary"] || "",
  1066. actor_type: actor_type,
  1067. also_known_as: Map.get(data, "alsoKnownAs", []),
  1068. public_key: public_key,
  1069. inbox: data["inbox"],
  1070. shared_inbox: shared_inbox,
  1071. accepts_chat_messages: accepts_chat_messages
  1072. }
  1073. # nickname can be nil because of virtual actors
  1074. if data["preferredUsername"] do
  1075. Map.put(
  1076. user_data,
  1077. :nickname,
  1078. "#{data["preferredUsername"]}@#{URI.parse(data["id"]).host}"
  1079. )
  1080. else
  1081. Map.put(user_data, :nickname, nil)
  1082. end
  1083. end
  1084. def fetch_follow_information_for_user(user) do
  1085. with {:ok, following_data} <-
  1086. Fetcher.fetch_and_contain_remote_object_from_id(user.following_address),
  1087. {:ok, hide_follows} <- collection_private(following_data),
  1088. {:ok, followers_data} <-
  1089. Fetcher.fetch_and_contain_remote_object_from_id(user.follower_address),
  1090. {:ok, hide_followers} <- collection_private(followers_data) do
  1091. {:ok,
  1092. %{
  1093. hide_follows: hide_follows,
  1094. follower_count: normalize_counter(followers_data["totalItems"]),
  1095. following_count: normalize_counter(following_data["totalItems"]),
  1096. hide_followers: hide_followers
  1097. }}
  1098. else
  1099. {:error, _} = e -> e
  1100. e -> {:error, e}
  1101. end
  1102. end
  1103. defp normalize_counter(counter) when is_integer(counter), do: counter
  1104. defp normalize_counter(_), do: 0
  1105. def maybe_update_follow_information(user_data) do
  1106. with {:enabled, true} <- {:enabled, Config.get([:instance, :external_user_synchronization])},
  1107. {_, true} <- {:user_type_check, user_data[:type] in ["Person", "Service"]},
  1108. {_, true} <-
  1109. {:collections_available,
  1110. !!(user_data[:following_address] && user_data[:follower_address])},
  1111. {:ok, info} <-
  1112. fetch_follow_information_for_user(user_data) do
  1113. info = Map.merge(user_data[:info] || %{}, info)
  1114. user_data
  1115. |> Map.put(:info, info)
  1116. else
  1117. {:user_type_check, false} ->
  1118. user_data
  1119. {:collections_available, false} ->
  1120. user_data
  1121. {:enabled, false} ->
  1122. user_data
  1123. e ->
  1124. Logger.error(
  1125. "Follower/Following counter update for #{user_data.ap_id} failed.\n" <> inspect(e)
  1126. )
  1127. user_data
  1128. end
  1129. end
  1130. defp collection_private(%{"first" => %{"type" => type}})
  1131. when type in ["CollectionPage", "OrderedCollectionPage"],
  1132. do: {:ok, false}
  1133. defp collection_private(%{"first" => first}) do
  1134. with {:ok, %{"type" => type}} when type in ["CollectionPage", "OrderedCollectionPage"] <-
  1135. Fetcher.fetch_and_contain_remote_object_from_id(first) do
  1136. {:ok, false}
  1137. else
  1138. {:error, {:ok, %{status: code}}} when code in [401, 403] -> {:ok, true}
  1139. {:error, _} = e -> e
  1140. e -> {:error, e}
  1141. end
  1142. end
  1143. defp collection_private(_data), do: {:ok, true}
  1144. def user_data_from_user_object(data) do
  1145. with {:ok, data} <- MRF.filter(data) do
  1146. {:ok, object_to_user_data(data)}
  1147. else
  1148. e -> {:error, e}
  1149. end
  1150. end
  1151. def fetch_and_prepare_user_from_ap_id(ap_id) do
  1152. with {:ok, data} <- Fetcher.fetch_and_contain_remote_object_from_id(ap_id),
  1153. {:ok, data} <- user_data_from_user_object(data) do
  1154. {:ok, maybe_update_follow_information(data)}
  1155. else
  1156. # If this has been deleted, only log a debug and not an error
  1157. {:error, "Object has been deleted" = e} ->
  1158. Logger.debug("Could not decode user at fetch #{ap_id}, #{inspect(e)}")
  1159. {:error, e}
  1160. {:error, {:reject, reason} = e} ->
  1161. Logger.info("Rejected user #{ap_id}: #{inspect(reason)}")
  1162. {:error, e}
  1163. {:error, e} ->
  1164. Logger.error("Could not decode user at fetch #{ap_id}, #{inspect(e)}")
  1165. {:error, e}
  1166. end
  1167. end
  1168. def maybe_handle_clashing_nickname(data) do
  1169. with nickname when is_binary(nickname) <- data[:nickname],
  1170. %User{} = old_user <- User.get_by_nickname(nickname),
  1171. {_, false} <- {:ap_id_comparison, data[:ap_id] == old_user.ap_id} do
  1172. Logger.info(
  1173. "Found an old user for #{nickname}, the old ap id is #{old_user.ap_id}, new one is #{
  1174. data[:ap_id]
  1175. }, renaming."
  1176. )
  1177. old_user
  1178. |> User.remote_user_changeset(%{nickname: "#{old_user.id}.#{old_user.nickname}"})
  1179. |> User.update_and_set_cache()
  1180. else
  1181. {:ap_id_comparison, true} ->
  1182. Logger.info(
  1183. "Found an old user for #{data[:nickname]}, but the ap id #{data[:ap_id]} is the same as the new user. Race condition? Not changing anything."
  1184. )
  1185. _ ->
  1186. nil
  1187. end
  1188. end
  1189. def make_user_from_ap_id(ap_id) do
  1190. user = User.get_cached_by_ap_id(ap_id)
  1191. if user && !User.ap_enabled?(user) do
  1192. Transmogrifier.upgrade_user_from_ap_id(ap_id)
  1193. else
  1194. with {:ok, data} <- fetch_and_prepare_user_from_ap_id(ap_id) do
  1195. if user do
  1196. user
  1197. |> User.remote_user_changeset(data)
  1198. |> User.update_and_set_cache()
  1199. else
  1200. maybe_handle_clashing_nickname(data)
  1201. data
  1202. |> User.remote_user_changeset()
  1203. |> Repo.insert()
  1204. |> User.set_cache()
  1205. end
  1206. end
  1207. end
  1208. end
  1209. def make_user_from_nickname(nickname) do
  1210. with {:ok, %{"ap_id" => ap_id}} when not is_nil(ap_id) <- WebFinger.finger(nickname) do
  1211. make_user_from_ap_id(ap_id)
  1212. else
  1213. _e -> {:error, "No AP id in WebFinger"}
  1214. end
  1215. end
  1216. # filter out broken threads
  1217. defp contain_broken_threads(%Activity{} = activity, %User{} = user) do
  1218. entire_thread_visible_for_user?(activity, user)
  1219. end
  1220. # do post-processing on a specific activity
  1221. def contain_activity(%Activity{} = activity, %User{} = user) do
  1222. contain_broken_threads(activity, user)
  1223. end
  1224. def fetch_direct_messages_query do
  1225. Activity
  1226. |> restrict_type(%{type: "Create"})
  1227. |> restrict_visibility(%{visibility: "direct"})
  1228. |> order_by([activity], asc: activity.id)
  1229. end
  1230. end