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.

2494 lines
74KB

  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. defmodule Pleroma.User do
  5. use Ecto.Schema
  6. import Ecto.Changeset
  7. import Ecto.Query
  8. import Ecto, only: [assoc: 2]
  9. alias Ecto.Multi
  10. alias Pleroma.Activity
  11. alias Pleroma.Config
  12. alias Pleroma.Conversation.Participation
  13. alias Pleroma.Delivery
  14. alias Pleroma.EctoType.ActivityPub.ObjectValidators
  15. alias Pleroma.Emoji
  16. alias Pleroma.FollowingRelationship
  17. alias Pleroma.Formatter
  18. alias Pleroma.HTML
  19. alias Pleroma.Keys
  20. alias Pleroma.MFA
  21. alias Pleroma.Notification
  22. alias Pleroma.Object
  23. alias Pleroma.Registration
  24. alias Pleroma.Repo
  25. alias Pleroma.User
  26. alias Pleroma.UserRelationship
  27. alias Pleroma.Web.ActivityPub.ActivityPub
  28. alias Pleroma.Web.ActivityPub.Builder
  29. alias Pleroma.Web.ActivityPub.Pipeline
  30. alias Pleroma.Web.ActivityPub.Utils
  31. alias Pleroma.Web.CommonAPI
  32. alias Pleroma.Web.CommonAPI.Utils, as: CommonUtils
  33. alias Pleroma.Web.Endpoint
  34. alias Pleroma.Web.OAuth
  35. alias Pleroma.Web.RelMe
  36. alias Pleroma.Workers.BackgroundWorker
  37. require Logger
  38. @type t :: %__MODULE__{}
  39. @type account_status ::
  40. :active
  41. | :deactivated
  42. | :password_reset_pending
  43. | :confirmation_pending
  44. | :approval_pending
  45. @primary_key {:id, FlakeId.Ecto.CompatType, autogenerate: true}
  46. # credo:disable-for-next-line Credo.Check.Readability.MaxLineLength
  47. @email_regex ~r/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/
  48. @strict_local_nickname_regex ~r/^[a-zA-Z\d]+$/
  49. @extended_local_nickname_regex ~r/^[a-zA-Z\d_-]+$/
  50. # AP ID user relationships (blocks, mutes etc.)
  51. # Format: [rel_type: [outgoing_rel: :outgoing_rel_target, incoming_rel: :incoming_rel_source]]
  52. @user_relationships_config [
  53. block: [
  54. blocker_blocks: :blocked_users,
  55. blockee_blocks: :blocker_users
  56. ],
  57. mute: [
  58. muter_mutes: :muted_users,
  59. mutee_mutes: :muter_users
  60. ],
  61. reblog_mute: [
  62. reblog_muter_mutes: :reblog_muted_users,
  63. reblog_mutee_mutes: :reblog_muter_users
  64. ],
  65. notification_mute: [
  66. notification_muter_mutes: :notification_muted_users,
  67. notification_mutee_mutes: :notification_muter_users
  68. ],
  69. # Note: `inverse_subscription` relationship is inverse: subscriber acts as relationship target
  70. inverse_subscription: [
  71. subscribee_subscriptions: :subscriber_users,
  72. subscriber_subscriptions: :subscribee_users
  73. ]
  74. ]
  75. @cachex Pleroma.Config.get([:cachex, :provider], Cachex)
  76. schema "users" do
  77. field(:bio, :string, default: "")
  78. field(:raw_bio, :string)
  79. field(:email, :string)
  80. field(:name, :string)
  81. field(:nickname, :string)
  82. field(:password_hash, :string)
  83. field(:password, :string, virtual: true)
  84. field(:password_confirmation, :string, virtual: true)
  85. field(:keys, :string)
  86. field(:public_key, :string)
  87. field(:ap_id, :string)
  88. field(:avatar, :map, default: %{})
  89. field(:local, :boolean, default: true)
  90. field(:follower_address, :string)
  91. field(:following_address, :string)
  92. field(:search_rank, :float, virtual: true)
  93. field(:search_type, :integer, virtual: true)
  94. field(:tags, {:array, :string}, default: [])
  95. field(:last_refreshed_at, :naive_datetime_usec)
  96. field(:last_digest_emailed_at, :naive_datetime)
  97. field(:banner, :map, default: %{})
  98. field(:background, :map, default: %{})
  99. field(:note_count, :integer, default: 0)
  100. field(:follower_count, :integer, default: 0)
  101. field(:following_count, :integer, default: 0)
  102. field(:is_locked, :boolean, default: false)
  103. field(:is_confirmed, :boolean, default: true)
  104. field(:password_reset_pending, :boolean, default: false)
  105. field(:is_approved, :boolean, default: true)
  106. field(:registration_reason, :string, default: nil)
  107. field(:confirmation_token, :string, default: nil)
  108. field(:default_scope, :string, default: "public")
  109. field(:domain_blocks, {:array, :string}, default: [])
  110. field(:is_active, :boolean, default: true)
  111. field(:no_rich_text, :boolean, default: false)
  112. field(:ap_enabled, :boolean, default: false)
  113. field(:is_moderator, :boolean, default: false)
  114. field(:is_admin, :boolean, default: false)
  115. field(:show_role, :boolean, default: true)
  116. field(:mastofe_settings, :map, default: nil)
  117. field(:uri, ObjectValidators.Uri, default: nil)
  118. field(:hide_followers_count, :boolean, default: false)
  119. field(:hide_follows_count, :boolean, default: false)
  120. field(:hide_followers, :boolean, default: false)
  121. field(:hide_follows, :boolean, default: false)
  122. field(:hide_favorites, :boolean, default: true)
  123. field(:pinned_activities, {:array, :string}, default: [])
  124. field(:email_notifications, :map, default: %{"digest" => false})
  125. field(:mascot, :map, default: nil)
  126. field(:emoji, :map, default: %{})
  127. field(:pleroma_settings_store, :map, default: %{})
  128. field(:fields, {:array, :map}, default: [])
  129. field(:raw_fields, {:array, :map}, default: [])
  130. field(:is_discoverable, :boolean, default: false)
  131. field(:invisible, :boolean, default: false)
  132. field(:allow_following_move, :boolean, default: true)
  133. field(:skip_thread_containment, :boolean, default: false)
  134. field(:actor_type, :string, default: "Person")
  135. field(:also_known_as, {:array, ObjectValidators.ObjectID}, default: [])
  136. field(:inbox, :string)
  137. field(:shared_inbox, :string)
  138. field(:accepts_chat_messages, :boolean, default: nil)
  139. field(:last_active_at, :naive_datetime)
  140. field(:disclose_client, :boolean, default: true)
  141. embeds_one(
  142. :notification_settings,
  143. Pleroma.User.NotificationSetting,
  144. on_replace: :update
  145. )
  146. has_many(:notifications, Notification)
  147. has_many(:registrations, Registration)
  148. has_many(:deliveries, Delivery)
  149. has_many(:outgoing_relationships, UserRelationship, foreign_key: :source_id)
  150. has_many(:incoming_relationships, UserRelationship, foreign_key: :target_id)
  151. for {relationship_type,
  152. [
  153. {outgoing_relation, outgoing_relation_target},
  154. {incoming_relation, incoming_relation_source}
  155. ]} <- @user_relationships_config do
  156. # Definitions of `has_many` relations: :blocker_blocks, :muter_mutes, :reblog_muter_mutes,
  157. # :notification_muter_mutes, :subscribee_subscriptions
  158. has_many(outgoing_relation, UserRelationship,
  159. foreign_key: :source_id,
  160. where: [relationship_type: relationship_type]
  161. )
  162. # Definitions of `has_many` relations: :blockee_blocks, :mutee_mutes, :reblog_mutee_mutes,
  163. # :notification_mutee_mutes, :subscriber_subscriptions
  164. has_many(incoming_relation, UserRelationship,
  165. foreign_key: :target_id,
  166. where: [relationship_type: relationship_type]
  167. )
  168. # Definitions of `has_many` relations: :blocked_users, :muted_users, :reblog_muted_users,
  169. # :notification_muted_users, :subscriber_users
  170. has_many(outgoing_relation_target, through: [outgoing_relation, :target])
  171. # Definitions of `has_many` relations: :blocker_users, :muter_users, :reblog_muter_users,
  172. # :notification_muter_users, :subscribee_users
  173. has_many(incoming_relation_source, through: [incoming_relation, :source])
  174. end
  175. # `:blocks` is deprecated (replaced with `blocked_users` relation)
  176. field(:blocks, {:array, :string}, default: [])
  177. # `:mutes` is deprecated (replaced with `muted_users` relation)
  178. field(:mutes, {:array, :string}, default: [])
  179. # `:muted_reblogs` is deprecated (replaced with `reblog_muted_users` relation)
  180. field(:muted_reblogs, {:array, :string}, default: [])
  181. # `:muted_notifications` is deprecated (replaced with `notification_muted_users` relation)
  182. field(:muted_notifications, {:array, :string}, default: [])
  183. # `:subscribers` is deprecated (replaced with `subscriber_users` relation)
  184. field(:subscribers, {:array, :string}, default: [])
  185. embeds_one(
  186. :multi_factor_authentication_settings,
  187. MFA.Settings,
  188. on_replace: :delete
  189. )
  190. timestamps()
  191. end
  192. for {_relationship_type, [{_outgoing_relation, outgoing_relation_target}, _]} <-
  193. @user_relationships_config do
  194. # `def blocked_users_relation/2`, `def muted_users_relation/2`,
  195. # `def reblog_muted_users_relation/2`, `def notification_muted_users/2`,
  196. # `def subscriber_users/2`
  197. def unquote(:"#{outgoing_relation_target}_relation")(user, restrict_deactivated? \\ false) do
  198. target_users_query = assoc(user, unquote(outgoing_relation_target))
  199. if restrict_deactivated? do
  200. target_users_query
  201. |> User.Query.build(%{deactivated: false})
  202. else
  203. target_users_query
  204. end
  205. end
  206. # `def blocked_users/2`, `def muted_users/2`, `def reblog_muted_users/2`,
  207. # `def notification_muted_users/2`, `def subscriber_users/2`
  208. def unquote(outgoing_relation_target)(user, restrict_deactivated? \\ false) do
  209. __MODULE__
  210. |> apply(unquote(:"#{outgoing_relation_target}_relation"), [
  211. user,
  212. restrict_deactivated?
  213. ])
  214. |> Repo.all()
  215. end
  216. # `def blocked_users_ap_ids/2`, `def muted_users_ap_ids/2`, `def reblog_muted_users_ap_ids/2`,
  217. # `def notification_muted_users_ap_ids/2`, `def subscriber_users_ap_ids/2`
  218. def unquote(:"#{outgoing_relation_target}_ap_ids")(user, restrict_deactivated? \\ false) do
  219. __MODULE__
  220. |> apply(unquote(:"#{outgoing_relation_target}_relation"), [
  221. user,
  222. restrict_deactivated?
  223. ])
  224. |> select([u], u.ap_id)
  225. |> Repo.all()
  226. end
  227. end
  228. def cached_blocked_users_ap_ids(user) do
  229. @cachex.fetch!(:user_cache, "blocked_users_ap_ids:#{user.ap_id}", fn _ ->
  230. blocked_users_ap_ids(user)
  231. end)
  232. end
  233. def cached_muted_users_ap_ids(user) do
  234. @cachex.fetch!(:user_cache, "muted_users_ap_ids:#{user.ap_id}", fn _ ->
  235. muted_users_ap_ids(user)
  236. end)
  237. end
  238. defdelegate following_count(user), to: FollowingRelationship
  239. defdelegate following(user), to: FollowingRelationship
  240. defdelegate following?(follower, followed), to: FollowingRelationship
  241. defdelegate following_ap_ids(user), to: FollowingRelationship
  242. defdelegate get_follow_requests(user), to: FollowingRelationship
  243. defdelegate search(query, opts \\ []), to: User.Search
  244. @doc """
  245. Dumps Flake Id to SQL-compatible format (16-byte UUID).
  246. E.g. "9pQtDGXuq4p3VlcJEm" -> <<0, 0, 1, 110, 179, 218, 42, 92, 213, 41, 44, 227, 95, 213, 0, 0>>
  247. """
  248. def binary_id(source_id) when is_binary(source_id) do
  249. with {:ok, dumped_id} <- FlakeId.Ecto.CompatType.dump(source_id) do
  250. dumped_id
  251. else
  252. _ -> source_id
  253. end
  254. end
  255. def binary_id(source_ids) when is_list(source_ids) do
  256. Enum.map(source_ids, &binary_id/1)
  257. end
  258. def binary_id(%User{} = user), do: binary_id(user.id)
  259. @doc "Returns status account"
  260. @spec account_status(User.t()) :: account_status()
  261. def account_status(%User{is_active: false}), do: :deactivated
  262. def account_status(%User{password_reset_pending: true}), do: :password_reset_pending
  263. def account_status(%User{local: true, is_approved: false}), do: :approval_pending
  264. def account_status(%User{local: true, is_confirmed: false}), do: :confirmation_pending
  265. def account_status(%User{}), do: :active
  266. @spec visible_for(User.t(), User.t() | nil) ::
  267. :visible
  268. | :invisible
  269. | :restricted_unauthenticated
  270. | :deactivated
  271. | :confirmation_pending
  272. def visible_for(user, for_user \\ nil)
  273. def visible_for(%User{invisible: true}, _), do: :invisible
  274. def visible_for(%User{id: user_id}, %User{id: user_id}), do: :visible
  275. def visible_for(%User{} = user, nil) do
  276. if restrict_unauthenticated?(user) do
  277. :restrict_unauthenticated
  278. else
  279. visible_account_status(user)
  280. end
  281. end
  282. def visible_for(%User{} = user, for_user) do
  283. if superuser?(for_user) do
  284. :visible
  285. else
  286. visible_account_status(user)
  287. end
  288. end
  289. def visible_for(_, _), do: :invisible
  290. defp restrict_unauthenticated?(%User{local: true}) do
  291. Config.restrict_unauthenticated_access?(:profiles, :local)
  292. end
  293. defp restrict_unauthenticated?(%User{local: _}) do
  294. Config.restrict_unauthenticated_access?(:profiles, :remote)
  295. end
  296. defp visible_account_status(user) do
  297. status = account_status(user)
  298. if status in [:active, :password_reset_pending] do
  299. :visible
  300. else
  301. status
  302. end
  303. end
  304. @spec superuser?(User.t()) :: boolean()
  305. def superuser?(%User{local: true, is_admin: true}), do: true
  306. def superuser?(%User{local: true, is_moderator: true}), do: true
  307. def superuser?(_), do: false
  308. @spec invisible?(User.t()) :: boolean()
  309. def invisible?(%User{invisible: true}), do: true
  310. def invisible?(_), do: false
  311. def avatar_url(user, options \\ []) do
  312. case user.avatar do
  313. %{"url" => [%{"href" => href} | _]} ->
  314. href
  315. _ ->
  316. unless options[:no_default] do
  317. Config.get([:assets, :default_user_avatar], "#{Endpoint.url()}/images/avi.png")
  318. end
  319. end
  320. end
  321. def banner_url(user, options \\ []) do
  322. case user.banner do
  323. %{"url" => [%{"href" => href} | _]} -> href
  324. _ -> !options[:no_default] && "#{Endpoint.url()}/images/banner.png"
  325. end
  326. end
  327. # Should probably be renamed or removed
  328. def ap_id(%User{nickname: nickname}), do: "#{Endpoint.url()}/users/#{nickname}"
  329. def ap_followers(%User{follower_address: fa}) when is_binary(fa), do: fa
  330. def ap_followers(%User{} = user), do: "#{ap_id(user)}/followers"
  331. @spec ap_following(User.t()) :: String.t()
  332. def ap_following(%User{following_address: fa}) when is_binary(fa), do: fa
  333. def ap_following(%User{} = user), do: "#{ap_id(user)}/following"
  334. defp truncate_fields_param(params) do
  335. if Map.has_key?(params, :fields) do
  336. Map.put(params, :fields, Enum.map(params[:fields], &truncate_field/1))
  337. else
  338. params
  339. end
  340. end
  341. defp truncate_if_exists(params, key, max_length) do
  342. if Map.has_key?(params, key) and is_binary(params[key]) do
  343. {value, _chopped} = String.split_at(params[key], max_length)
  344. Map.put(params, key, value)
  345. else
  346. params
  347. end
  348. end
  349. defp fix_follower_address(%{follower_address: _, following_address: _} = params), do: params
  350. defp fix_follower_address(%{nickname: nickname} = params),
  351. do: Map.put(params, :follower_address, ap_followers(%User{nickname: nickname}))
  352. defp fix_follower_address(params), do: params
  353. def remote_user_changeset(struct \\ %User{local: false}, params) do
  354. bio_limit = Config.get([:instance, :user_bio_length], 5000)
  355. name_limit = Config.get([:instance, :user_name_length], 100)
  356. name =
  357. case params[:name] do
  358. name when is_binary(name) and byte_size(name) > 0 -> name
  359. _ -> params[:nickname]
  360. end
  361. params =
  362. params
  363. |> Map.put(:name, name)
  364. |> Map.put_new(:last_refreshed_at, NaiveDateTime.utc_now())
  365. |> truncate_if_exists(:name, name_limit)
  366. |> truncate_if_exists(:bio, bio_limit)
  367. |> truncate_fields_param()
  368. |> fix_follower_address()
  369. struct
  370. |> cast(
  371. params,
  372. [
  373. :bio,
  374. :emoji,
  375. :ap_id,
  376. :inbox,
  377. :shared_inbox,
  378. :nickname,
  379. :public_key,
  380. :avatar,
  381. :ap_enabled,
  382. :banner,
  383. :is_locked,
  384. :last_refreshed_at,
  385. :uri,
  386. :follower_address,
  387. :following_address,
  388. :hide_followers,
  389. :hide_follows,
  390. :hide_followers_count,
  391. :hide_follows_count,
  392. :follower_count,
  393. :fields,
  394. :following_count,
  395. :is_discoverable,
  396. :invisible,
  397. :actor_type,
  398. :also_known_as,
  399. :accepts_chat_messages
  400. ]
  401. )
  402. |> cast(params, [:name], empty_values: [])
  403. |> validate_required([:ap_id])
  404. |> validate_required([:name], trim: false)
  405. |> unique_constraint(:nickname)
  406. |> validate_format(:nickname, @email_regex)
  407. |> validate_length(:bio, max: bio_limit)
  408. |> validate_length(:name, max: name_limit)
  409. |> validate_fields(true)
  410. |> validate_non_local()
  411. end
  412. defp validate_non_local(cng) do
  413. local? = get_field(cng, :local)
  414. if local? do
  415. cng
  416. |> add_error(:local, "User is local, can't update with this changeset.")
  417. else
  418. cng
  419. end
  420. end
  421. def update_changeset(struct, params \\ %{}) do
  422. bio_limit = Config.get([:instance, :user_bio_length], 5000)
  423. name_limit = Config.get([:instance, :user_name_length], 100)
  424. struct
  425. |> cast(
  426. params,
  427. [
  428. :bio,
  429. :raw_bio,
  430. :name,
  431. :emoji,
  432. :avatar,
  433. :public_key,
  434. :inbox,
  435. :shared_inbox,
  436. :is_locked,
  437. :no_rich_text,
  438. :default_scope,
  439. :banner,
  440. :hide_follows,
  441. :hide_followers,
  442. :hide_followers_count,
  443. :hide_follows_count,
  444. :hide_favorites,
  445. :allow_following_move,
  446. :also_known_as,
  447. :background,
  448. :show_role,
  449. :skip_thread_containment,
  450. :fields,
  451. :raw_fields,
  452. :pleroma_settings_store,
  453. :is_discoverable,
  454. :actor_type,
  455. :accepts_chat_messages,
  456. :disclose_client
  457. ]
  458. )
  459. |> unique_constraint(:nickname)
  460. |> validate_format(:nickname, local_nickname_regex())
  461. |> validate_length(:bio, max: bio_limit)
  462. |> validate_length(:name, min: 1, max: name_limit)
  463. |> validate_inclusion(:actor_type, ["Person", "Service"])
  464. |> put_fields()
  465. |> put_emoji()
  466. |> put_change_if_present(:bio, &{:ok, parse_bio(&1, struct)})
  467. |> put_change_if_present(:avatar, &put_upload(&1, :avatar))
  468. |> put_change_if_present(:banner, &put_upload(&1, :banner))
  469. |> put_change_if_present(:background, &put_upload(&1, :background))
  470. |> put_change_if_present(
  471. :pleroma_settings_store,
  472. &{:ok, Map.merge(struct.pleroma_settings_store, &1)}
  473. )
  474. |> validate_fields(false)
  475. end
  476. defp put_fields(changeset) do
  477. if raw_fields = get_change(changeset, :raw_fields) do
  478. raw_fields =
  479. raw_fields
  480. |> Enum.filter(fn %{"name" => n} -> n != "" end)
  481. fields =
  482. raw_fields
  483. |> Enum.map(fn f -> Map.update!(f, "value", &parse_fields(&1)) end)
  484. changeset
  485. |> put_change(:raw_fields, raw_fields)
  486. |> put_change(:fields, fields)
  487. else
  488. changeset
  489. end
  490. end
  491. defp parse_fields(value) do
  492. value
  493. |> Formatter.linkify(mentions_format: :full)
  494. |> elem(0)
  495. end
  496. defp put_emoji(changeset) do
  497. emojified_fields = [:bio, :name, :raw_fields]
  498. if Enum.any?(changeset.changes, fn {k, _} -> k in emojified_fields end) do
  499. bio = Emoji.Formatter.get_emoji_map(get_field(changeset, :bio))
  500. name = Emoji.Formatter.get_emoji_map(get_field(changeset, :name))
  501. emoji = Map.merge(bio, name)
  502. emoji =
  503. changeset
  504. |> get_field(:raw_fields)
  505. |> Enum.reduce(emoji, fn x, acc ->
  506. Map.merge(acc, Emoji.Formatter.get_emoji_map(x["name"] <> x["value"]))
  507. end)
  508. put_change(changeset, :emoji, emoji)
  509. else
  510. changeset
  511. end
  512. end
  513. defp put_change_if_present(changeset, map_field, value_function) do
  514. with {:ok, value} <- fetch_change(changeset, map_field),
  515. {:ok, new_value} <- value_function.(value) do
  516. put_change(changeset, map_field, new_value)
  517. else
  518. _ -> changeset
  519. end
  520. end
  521. defp put_upload(value, type) do
  522. with %Plug.Upload{} <- value,
  523. {:ok, object} <- ActivityPub.upload(value, type: type) do
  524. {:ok, object.data}
  525. end
  526. end
  527. def update_as_admin_changeset(struct, params) do
  528. struct
  529. |> update_changeset(params)
  530. |> cast(params, [:email])
  531. |> delete_change(:also_known_as)
  532. |> unique_constraint(:email)
  533. |> validate_format(:email, @email_regex)
  534. |> validate_inclusion(:actor_type, ["Person", "Service"])
  535. end
  536. @spec update_as_admin(User.t(), map()) :: {:ok, User.t()} | {:error, Changeset.t()}
  537. def update_as_admin(user, params) do
  538. params = Map.put(params, "password_confirmation", params["password"])
  539. changeset = update_as_admin_changeset(user, params)
  540. if params["password"] do
  541. reset_password(user, changeset, params)
  542. else
  543. User.update_and_set_cache(changeset)
  544. end
  545. end
  546. def password_update_changeset(struct, params) do
  547. struct
  548. |> cast(params, [:password, :password_confirmation])
  549. |> validate_required([:password, :password_confirmation])
  550. |> validate_confirmation(:password)
  551. |> put_password_hash()
  552. |> put_change(:password_reset_pending, false)
  553. end
  554. @spec reset_password(User.t(), map()) :: {:ok, User.t()} | {:error, Changeset.t()}
  555. def reset_password(%User{} = user, params) do
  556. reset_password(user, user, params)
  557. end
  558. def reset_password(%User{id: user_id} = user, struct, params) do
  559. multi =
  560. Multi.new()
  561. |> Multi.update(:user, password_update_changeset(struct, params))
  562. |> Multi.delete_all(:tokens, OAuth.Token.Query.get_by_user(user_id))
  563. |> Multi.delete_all(:auth, OAuth.Authorization.delete_by_user_query(user))
  564. case Repo.transaction(multi) do
  565. {:ok, %{user: user} = _} -> set_cache(user)
  566. {:error, _, changeset, _} -> {:error, changeset}
  567. end
  568. end
  569. def update_password_reset_pending(user, value) do
  570. user
  571. |> change()
  572. |> put_change(:password_reset_pending, value)
  573. |> update_and_set_cache()
  574. end
  575. def force_password_reset_async(user) do
  576. BackgroundWorker.enqueue("force_password_reset", %{"user_id" => user.id})
  577. end
  578. @spec force_password_reset(User.t()) :: {:ok, User.t()} | {:error, Ecto.Changeset.t()}
  579. def force_password_reset(user), do: update_password_reset_pending(user, true)
  580. # Used to auto-register LDAP accounts which won't have a password hash stored locally
  581. def register_changeset_ldap(struct, params = %{password: password})
  582. when is_nil(password) do
  583. params = Map.put_new(params, :accepts_chat_messages, true)
  584. params =
  585. if Map.has_key?(params, :email) do
  586. Map.put_new(params, :email, params[:email])
  587. else
  588. params
  589. end
  590. struct
  591. |> cast(params, [
  592. :name,
  593. :nickname,
  594. :email,
  595. :accepts_chat_messages
  596. ])
  597. |> validate_required([:name, :nickname])
  598. |> unique_constraint(:nickname)
  599. |> validate_exclusion(:nickname, Config.get([User, :restricted_nicknames]))
  600. |> validate_format(:nickname, local_nickname_regex())
  601. |> put_ap_id()
  602. |> unique_constraint(:ap_id)
  603. |> put_following_and_follower_address()
  604. end
  605. def register_changeset(struct, params \\ %{}, opts \\ []) do
  606. bio_limit = Config.get([:instance, :user_bio_length], 5000)
  607. name_limit = Config.get([:instance, :user_name_length], 100)
  608. reason_limit = Config.get([:instance, :registration_reason_length], 500)
  609. params = Map.put_new(params, :accepts_chat_messages, true)
  610. confirmed? =
  611. if is_nil(opts[:confirmed]) do
  612. !Config.get([:instance, :account_activation_required])
  613. else
  614. opts[:confirmed]
  615. end
  616. approved? =
  617. if is_nil(opts[:approved]) do
  618. !Config.get([:instance, :account_approval_required])
  619. else
  620. opts[:approved]
  621. end
  622. struct
  623. |> confirmation_changeset(set_confirmation: confirmed?)
  624. |> approval_changeset(set_approval: approved?)
  625. |> cast(params, [
  626. :bio,
  627. :raw_bio,
  628. :email,
  629. :name,
  630. :nickname,
  631. :password,
  632. :password_confirmation,
  633. :emoji,
  634. :accepts_chat_messages,
  635. :registration_reason
  636. ])
  637. |> validate_required([:name, :nickname, :password, :password_confirmation])
  638. |> validate_confirmation(:password)
  639. |> unique_constraint(:email)
  640. |> validate_format(:email, @email_regex)
  641. |> validate_change(:email, fn :email, email ->
  642. valid? =
  643. Config.get([User, :email_blacklist])
  644. |> Enum.all?(fn blacklisted_domain ->
  645. !String.ends_with?(email, ["@" <> blacklisted_domain, "." <> blacklisted_domain])
  646. end)
  647. if valid?, do: [], else: [email: "Invalid email"]
  648. end)
  649. |> unique_constraint(:nickname)
  650. |> validate_exclusion(:nickname, Config.get([User, :restricted_nicknames]))
  651. |> validate_format(:nickname, local_nickname_regex())
  652. |> validate_length(:bio, max: bio_limit)
  653. |> validate_length(:name, min: 1, max: name_limit)
  654. |> validate_length(:registration_reason, max: reason_limit)
  655. |> maybe_validate_required_email(opts[:external])
  656. |> put_password_hash
  657. |> put_ap_id()
  658. |> unique_constraint(:ap_id)
  659. |> put_following_and_follower_address()
  660. end
  661. def maybe_validate_required_email(changeset, true), do: changeset
  662. def maybe_validate_required_email(changeset, _) do
  663. if Config.get([:instance, :account_activation_required]) do
  664. validate_required(changeset, [:email])
  665. else
  666. changeset
  667. end
  668. end
  669. defp put_ap_id(changeset) do
  670. ap_id = ap_id(%User{nickname: get_field(changeset, :nickname)})
  671. put_change(changeset, :ap_id, ap_id)
  672. end
  673. defp put_following_and_follower_address(changeset) do
  674. followers = ap_followers(%User{nickname: get_field(changeset, :nickname)})
  675. changeset
  676. |> put_change(:follower_address, followers)
  677. end
  678. defp autofollow_users(user) do
  679. candidates = Config.get([:instance, :autofollowed_nicknames])
  680. autofollowed_users =
  681. User.Query.build(%{nickname: candidates, local: true, is_active: true})
  682. |> Repo.all()
  683. follow_all(user, autofollowed_users)
  684. end
  685. defp autofollowing_users(user) do
  686. candidates = Config.get([:instance, :autofollowing_nicknames])
  687. User.Query.build(%{nickname: candidates, local: true, deactivated: false})
  688. |> Repo.all()
  689. |> Enum.each(&follow(&1, user, :follow_accept))
  690. {:ok, :success}
  691. end
  692. @doc "Inserts provided changeset, performs post-registration actions (confirmation email sending etc.)"
  693. def register(%Ecto.Changeset{} = changeset) do
  694. with {:ok, user} <- Repo.insert(changeset) do
  695. post_register_action(user)
  696. end
  697. end
  698. def post_register_action(%User{is_confirmed: false} = user) do
  699. with {:ok, _} <- maybe_send_confirmation_email(user) do
  700. {:ok, user}
  701. end
  702. end
  703. def post_register_action(%User{is_approved: false} = user) do
  704. with {:ok, _} <- send_user_approval_email(user),
  705. {:ok, _} <- send_admin_approval_emails(user) do
  706. {:ok, user}
  707. end
  708. end
  709. def post_register_action(%User{is_approved: true, is_confirmed: true} = user) do
  710. with {:ok, user} <- autofollow_users(user),
  711. {:ok, _} <- autofollowing_users(user),
  712. {:ok, user} <- set_cache(user),
  713. {:ok, _} <- maybe_send_registration_email(user),
  714. {:ok, _} <- maybe_send_welcome_email(user),
  715. {:ok, _} <- maybe_send_welcome_message(user),
  716. {:ok, _} <- maybe_send_welcome_chat_message(user) do
  717. {:ok, user}
  718. end
  719. end
  720. defp send_user_approval_email(user) do
  721. user
  722. |> Pleroma.Emails.UserEmail.approval_pending_email()
  723. |> Pleroma.Emails.Mailer.deliver_async()
  724. {:ok, :enqueued}
  725. end
  726. defp send_admin_approval_emails(user) do
  727. all_superusers()
  728. |> Enum.filter(fn user -> not is_nil(user.email) end)
  729. |> Enum.each(fn superuser ->
  730. superuser
  731. |> Pleroma.Emails.AdminEmail.new_unapproved_registration(user)
  732. |> Pleroma.Emails.Mailer.deliver_async()
  733. end)
  734. {:ok, :enqueued}
  735. end
  736. defp maybe_send_welcome_message(user) do
  737. if User.WelcomeMessage.enabled?() do
  738. User.WelcomeMessage.post_message(user)
  739. {:ok, :enqueued}
  740. else
  741. {:ok, :noop}
  742. end
  743. end
  744. defp maybe_send_welcome_chat_message(user) do
  745. if User.WelcomeChatMessage.enabled?() do
  746. User.WelcomeChatMessage.post_message(user)
  747. {:ok, :enqueued}
  748. else
  749. {:ok, :noop}
  750. end
  751. end
  752. defp maybe_send_welcome_email(%User{email: email} = user) when is_binary(email) do
  753. if User.WelcomeEmail.enabled?() do
  754. User.WelcomeEmail.send_email(user)
  755. {:ok, :enqueued}
  756. else
  757. {:ok, :noop}
  758. end
  759. end
  760. defp maybe_send_welcome_email(_), do: {:ok, :noop}
  761. @spec maybe_send_confirmation_email(User.t()) :: {:ok, :enqueued | :noop}
  762. def maybe_send_confirmation_email(%User{is_confirmed: false, email: email} = user)
  763. when is_binary(email) do
  764. if Config.get([:instance, :account_activation_required]) do
  765. send_confirmation_email(user)
  766. {:ok, :enqueued}
  767. else
  768. {:ok, :noop}
  769. end
  770. end
  771. def maybe_send_confirmation_email(_), do: {:ok, :noop}
  772. @spec send_confirmation_email(Uset.t()) :: User.t()
  773. def send_confirmation_email(%User{} = user) do
  774. user
  775. |> Pleroma.Emails.UserEmail.account_confirmation_email()
  776. |> Pleroma.Emails.Mailer.deliver_async()
  777. user
  778. end
  779. @spec maybe_send_registration_email(User.t()) :: {:ok, :enqueued | :noop}
  780. defp maybe_send_registration_email(%User{email: email} = user) when is_binary(email) do
  781. with false <- User.WelcomeEmail.enabled?(),
  782. false <- Config.get([:instance, :account_activation_required], false),
  783. false <- Config.get([:instance, :account_approval_required], false) do
  784. user
  785. |> Pleroma.Emails.UserEmail.successful_registration_email()
  786. |> Pleroma.Emails.Mailer.deliver_async()
  787. {:ok, :enqueued}
  788. else
  789. _ ->
  790. {:ok, :noop}
  791. end
  792. end
  793. defp maybe_send_registration_email(_), do: {:ok, :noop}
  794. def needs_update?(%User{local: true}), do: false
  795. def needs_update?(%User{local: false, last_refreshed_at: nil}), do: true
  796. def needs_update?(%User{local: false} = user) do
  797. NaiveDateTime.diff(NaiveDateTime.utc_now(), user.last_refreshed_at) >= 86_400
  798. end
  799. def needs_update?(_), do: true
  800. @spec maybe_direct_follow(User.t(), User.t()) :: {:ok, User.t()} | {:error, String.t()}
  801. # "Locked" (self-locked) users demand explicit authorization of follow requests
  802. def maybe_direct_follow(%User{} = follower, %User{local: true, is_locked: true} = followed) do
  803. follow(follower, followed, :follow_pending)
  804. end
  805. def maybe_direct_follow(%User{} = follower, %User{local: true} = followed) do
  806. follow(follower, followed)
  807. end
  808. def maybe_direct_follow(%User{} = follower, %User{} = followed) do
  809. if not ap_enabled?(followed) do
  810. follow(follower, followed)
  811. else
  812. {:ok, follower, followed}
  813. end
  814. end
  815. @doc "A mass follow for local users. Respects blocks in both directions but does not create activities."
  816. @spec follow_all(User.t(), list(User.t())) :: {atom(), User.t()}
  817. def follow_all(follower, followeds) do
  818. followeds
  819. |> Enum.reject(fn followed -> blocks?(follower, followed) || blocks?(followed, follower) end)
  820. |> Enum.each(&follow(follower, &1, :follow_accept))
  821. set_cache(follower)
  822. end
  823. def follow(%User{} = follower, %User{} = followed, state \\ :follow_accept) do
  824. deny_follow_blocked = Config.get([:user, :deny_follow_blocked])
  825. cond do
  826. not followed.is_active ->
  827. {:error, "Could not follow user: #{followed.nickname} is deactivated."}
  828. deny_follow_blocked and blocks?(followed, follower) ->
  829. {:error, "Could not follow user: #{followed.nickname} blocked you."}
  830. true ->
  831. FollowingRelationship.follow(follower, followed, state)
  832. end
  833. end
  834. def unfollow(%User{ap_id: ap_id}, %User{ap_id: ap_id}) do
  835. {:error, "Not subscribed!"}
  836. end
  837. @spec unfollow(User.t(), User.t()) :: {:ok, User.t(), Activity.t()} | {:error, String.t()}
  838. def unfollow(%User{} = follower, %User{} = followed) do
  839. case do_unfollow(follower, followed) do
  840. {:ok, follower, followed} ->
  841. {:ok, follower, Utils.fetch_latest_follow(follower, followed)}
  842. error ->
  843. error
  844. end
  845. end
  846. @spec do_unfollow(User.t(), User.t()) :: {:ok, User.t(), User.t()} | {:error, String.t()}
  847. defp do_unfollow(%User{} = follower, %User{} = followed) do
  848. case get_follow_state(follower, followed) do
  849. state when state in [:follow_pending, :follow_accept] ->
  850. FollowingRelationship.unfollow(follower, followed)
  851. nil ->
  852. {:error, "Not subscribed!"}
  853. end
  854. end
  855. @doc "Returns follow state as Pleroma.FollowingRelationship.State value"
  856. def get_follow_state(%User{} = follower, %User{} = following) do
  857. following_relationship = FollowingRelationship.get(follower, following)
  858. get_follow_state(follower, following, following_relationship)
  859. end
  860. def get_follow_state(
  861. %User{} = follower,
  862. %User{} = following,
  863. following_relationship
  864. ) do
  865. case {following_relationship, following.local} do
  866. {nil, false} ->
  867. case Utils.fetch_latest_follow(follower, following) do
  868. %Activity{data: %{"state" => state}} when state in ["pending", "accept"] ->
  869. FollowingRelationship.state_to_enum(state)
  870. _ ->
  871. nil
  872. end
  873. {%{state: state}, _} ->
  874. state
  875. {nil, _} ->
  876. nil
  877. end
  878. end
  879. def locked?(%User{} = user) do
  880. user.is_locked || false
  881. end
  882. def get_by_id(id) do
  883. Repo.get_by(User, id: id)
  884. end
  885. def get_by_ap_id(ap_id) do
  886. Repo.get_by(User, ap_id: ap_id)
  887. end
  888. def get_all_by_ap_id(ap_ids) do
  889. from(u in __MODULE__,
  890. where: u.ap_id in ^ap_ids
  891. )
  892. |> Repo.all()
  893. end
  894. def get_all_by_ids(ids) do
  895. from(u in __MODULE__, where: u.id in ^ids)
  896. |> Repo.all()
  897. end
  898. # This is mostly an SPC migration fix. This guesses the user nickname by taking the last part
  899. # of the ap_id and the domain and tries to get that user
  900. def get_by_guessed_nickname(ap_id) do
  901. domain = URI.parse(ap_id).host
  902. name = List.last(String.split(ap_id, "/"))
  903. nickname = "#{name}@#{domain}"
  904. get_cached_by_nickname(nickname)
  905. end
  906. def set_cache({:ok, user}), do: set_cache(user)
  907. def set_cache({:error, err}), do: {:error, err}
  908. def set_cache(%User{} = user) do
  909. @cachex.put(:user_cache, "ap_id:#{user.ap_id}", user)
  910. @cachex.put(:user_cache, "nickname:#{user.nickname}", user)
  911. @cachex.put(:user_cache, "friends_ap_ids:#{user.nickname}", get_user_friends_ap_ids(user))
  912. {:ok, user}
  913. end
  914. def update_and_set_cache(struct, params) do
  915. struct
  916. |> update_changeset(params)
  917. |> update_and_set_cache()
  918. end
  919. def update_and_set_cache(changeset) do
  920. with {:ok, user} <- Repo.update(changeset, stale_error_field: :id) do
  921. set_cache(user)
  922. end
  923. end
  924. def get_user_friends_ap_ids(user) do
  925. from(u in User.get_friends_query(user), select: u.ap_id)
  926. |> Repo.all()
  927. end
  928. @spec get_cached_user_friends_ap_ids(User.t()) :: [String.t()]
  929. def get_cached_user_friends_ap_ids(user) do
  930. @cachex.fetch!(:user_cache, "friends_ap_ids:#{user.ap_id}", fn _ ->
  931. get_user_friends_ap_ids(user)
  932. end)
  933. end
  934. def invalidate_cache(user) do
  935. @cachex.del(:user_cache, "ap_id:#{user.ap_id}")
  936. @cachex.del(:user_cache, "nickname:#{user.nickname}")
  937. @cachex.del(:user_cache, "friends_ap_ids:#{user.ap_id}")
  938. @cachex.del(:user_cache, "blocked_users_ap_ids:#{user.ap_id}")
  939. @cachex.del(:user_cache, "muted_users_ap_ids:#{user.ap_id}")
  940. end
  941. @spec get_cached_by_ap_id(String.t()) :: User.t() | nil
  942. def get_cached_by_ap_id(ap_id) do
  943. key = "ap_id:#{ap_id}"
  944. with {:ok, nil} <- @cachex.get(:user_cache, key),
  945. user when not is_nil(user) <- get_by_ap_id(ap_id),
  946. {:ok, true} <- @cachex.put(:user_cache, key, user) do
  947. user
  948. else
  949. {:ok, user} -> user
  950. nil -> nil
  951. end
  952. end
  953. def get_cached_by_id(id) do
  954. key = "id:#{id}"
  955. ap_id =
  956. @cachex.fetch!(:user_cache, key, fn _ ->
  957. user = get_by_id(id)
  958. if user do
  959. @cachex.put(:user_cache, "ap_id:#{user.ap_id}", user)
  960. {:commit, user.ap_id}
  961. else
  962. {:ignore, ""}
  963. end
  964. end)
  965. get_cached_by_ap_id(ap_id)
  966. end
  967. def get_cached_by_nickname(nickname) do
  968. key = "nickname:#{nickname}"
  969. @cachex.fetch!(:user_cache, key, fn _ ->
  970. case get_or_fetch_by_nickname(nickname) do
  971. {:ok, user} -> {:commit, user}
  972. {:error, _error} -> {:ignore, nil}
  973. end
  974. end)
  975. end
  976. def get_cached_by_nickname_or_id(nickname_or_id, opts \\ []) do
  977. restrict_to_local = Config.get([:instance, :limit_to_local_content])
  978. cond do
  979. is_integer(nickname_or_id) or FlakeId.flake_id?(nickname_or_id) ->
  980. get_cached_by_id(nickname_or_id) || get_cached_by_nickname(nickname_or_id)
  981. restrict_to_local == false or not String.contains?(nickname_or_id, "@") ->
  982. get_cached_by_nickname(nickname_or_id)
  983. restrict_to_local == :unauthenticated and match?(%User{}, opts[:for]) ->
  984. get_cached_by_nickname(nickname_or_id)
  985. true ->
  986. nil
  987. end
  988. end
  989. @spec get_by_nickname(String.t()) :: User.t() | nil
  990. def get_by_nickname(nickname) do
  991. Repo.get_by(User, nickname: nickname) ||
  992. if Regex.match?(~r(@#{Pleroma.Web.Endpoint.host()})i, nickname) do
  993. Repo.get_by(User, nickname: local_nickname(nickname))
  994. end
  995. end
  996. def get_by_email(email), do: Repo.get_by(User, email: email)
  997. def get_by_nickname_or_email(nickname_or_email) do
  998. get_by_nickname(nickname_or_email) || get_by_email(nickname_or_email)
  999. end
  1000. def fetch_by_nickname(nickname), do: ActivityPub.make_user_from_nickname(nickname)
  1001. def get_or_fetch_by_nickname(nickname) do
  1002. with %User{} = user <- get_by_nickname(nickname) do
  1003. {:ok, user}
  1004. else
  1005. _e ->
  1006. with [_nick, _domain] <- String.split(nickname, "@"),
  1007. {:ok, user} <- fetch_by_nickname(nickname) do
  1008. {:ok, user}
  1009. else
  1010. _e -> {:error, "not found " <> nickname}
  1011. end
  1012. end
  1013. end
  1014. @spec get_followers_query(User.t(), pos_integer() | nil) :: Ecto.Query.t()
  1015. def get_followers_query(%User{} = user, nil) do
  1016. User.Query.build(%{followers: user, is_active: true})
  1017. end
  1018. def get_followers_query(%User{} = user, page) do
  1019. user
  1020. |> get_followers_query(nil)
  1021. |> User.Query.paginate(page, 20)
  1022. end
  1023. @spec get_followers_query(User.t()) :: Ecto.Query.t()
  1024. def get_followers_query(%User{} = user), do: get_followers_query(user, nil)
  1025. @spec get_followers(User.t(), pos_integer() | nil) :: {:ok, list(User.t())}
  1026. def get_followers(%User{} = user, page \\ nil) do
  1027. user
  1028. |> get_followers_query(page)
  1029. |> Repo.all()
  1030. end
  1031. @spec get_external_followers(User.t(), pos_integer() | nil) :: {:ok, list(User.t())}
  1032. def get_external_followers(%User{} = user, page \\ nil) do
  1033. user
  1034. |> get_followers_query(page)
  1035. |> User.Query.build(%{external: true})
  1036. |> Repo.all()
  1037. end
  1038. def get_followers_ids(%User{} = user, page \\ nil) do
  1039. user
  1040. |> get_followers_query(page)
  1041. |> select([u], u.id)
  1042. |> Repo.all()
  1043. end
  1044. @spec get_friends_query(User.t(), pos_integer() | nil) :: Ecto.Query.t()
  1045. def get_friends_query(%User{} = user, nil) do
  1046. User.Query.build(%{friends: user, deactivated: false})
  1047. end
  1048. def get_friends_query(%User{} = user, page) do
  1049. user
  1050. |> get_friends_query(nil)
  1051. |> User.Query.paginate(page, 20)
  1052. end
  1053. @spec get_friends_query(User.t()) :: Ecto.Query.t()
  1054. def get_friends_query(%User{} = user), do: get_friends_query(user, nil)
  1055. def get_friends(%User{} = user, page \\ nil) do
  1056. user
  1057. |> get_friends_query(page)
  1058. |> Repo.all()
  1059. end
  1060. def get_friends_ap_ids(%User{} = user) do
  1061. user
  1062. |> get_friends_query(nil)
  1063. |> select([u], u.ap_id)
  1064. |> Repo.all()
  1065. end
  1066. def get_friends_ids(%User{} = user, page \\ nil) do
  1067. user
  1068. |> get_friends_query(page)
  1069. |> select([u], u.id)
  1070. |> Repo.all()
  1071. end
  1072. def increase_note_count(%User{} = user) do
  1073. User
  1074. |> where(id: ^user.id)
  1075. |> update([u], inc: [note_count: 1])
  1076. |> select([u], u)
  1077. |> Repo.update_all([])
  1078. |> case do
  1079. {1, [user]} -> set_cache(user)
  1080. _ -> {:error, user}
  1081. end
  1082. end
  1083. def decrease_note_count(%User{} = user) do
  1084. User
  1085. |> where(id: ^user.id)
  1086. |> update([u],
  1087. set: [
  1088. note_count: fragment("greatest(0, note_count - 1)")
  1089. ]
  1090. )
  1091. |> select([u], u)
  1092. |> Repo.update_all([])
  1093. |> case do
  1094. {1, [user]} -> set_cache(user)
  1095. _ -> {:error, user}
  1096. end
  1097. end
  1098. def update_note_count(%User{} = user, note_count \\ nil) do
  1099. note_count =
  1100. note_count ||
  1101. from(
  1102. a in Object,
  1103. where: fragment("?->>'actor' = ? and ?->>'type' = 'Note'", a.data, ^user.ap_id, a.data),
  1104. select: count(a.id)
  1105. )
  1106. |> Repo.one()
  1107. user
  1108. |> cast(%{note_count: note_count}, [:note_count])
  1109. |> update_and_set_cache()
  1110. end
  1111. @spec maybe_fetch_follow_information(User.t()) :: User.t()
  1112. def maybe_fetch_follow_information(user) do
  1113. with {:ok, user} <- fetch_follow_information(user) do
  1114. user
  1115. else
  1116. e ->
  1117. Logger.error("Follower/Following counter update for #{user.ap_id} failed.\n#{inspect(e)}")
  1118. user
  1119. end
  1120. end
  1121. def fetch_follow_information(user) do
  1122. with {:ok, info} <- ActivityPub.fetch_follow_information_for_user(user) do
  1123. user
  1124. |> follow_information_changeset(info)
  1125. |> update_and_set_cache()
  1126. end
  1127. end
  1128. defp follow_information_changeset(user, params) do
  1129. user
  1130. |> cast(params, [
  1131. :hide_followers,
  1132. :hide_follows,
  1133. :follower_count,
  1134. :following_count,
  1135. :hide_followers_count,
  1136. :hide_follows_count
  1137. ])
  1138. end
  1139. @spec update_follower_count(User.t()) :: {:ok, User.t()}
  1140. def update_follower_count(%User{} = user) do
  1141. if user.local or !Config.get([:instance, :external_user_synchronization]) do
  1142. follower_count = FollowingRelationship.follower_count(user)
  1143. user
  1144. |> follow_information_changeset(%{follower_count: follower_count})
  1145. |> update_and_set_cache
  1146. else
  1147. {:ok, maybe_fetch_follow_information(user)}
  1148. end
  1149. end
  1150. @spec update_following_count(User.t()) :: {:ok, User.t()}
  1151. def update_following_count(%User{local: false} = user) do
  1152. if Config.get([:instance, :external_user_synchronization]) do
  1153. {:ok, maybe_fetch_follow_information(user)}
  1154. else
  1155. {:ok, user}
  1156. end
  1157. end
  1158. def update_following_count(%User{local: true} = user) do
  1159. following_count = FollowingRelationship.following_count(user)
  1160. user
  1161. |> follow_information_changeset(%{following_count: following_count})
  1162. |> update_and_set_cache()
  1163. end
  1164. @spec get_users_from_set([String.t()], keyword()) :: [User.t()]
  1165. def get_users_from_set(ap_ids, opts \\ []) do
  1166. local_only = Keyword.get(opts, :local_only, true)
  1167. criteria = %{ap_id: ap_ids, is_active: true}
  1168. criteria = if local_only, do: Map.put(criteria, :local, true), else: criteria
  1169. User.Query.build(criteria)
  1170. |> Repo.all()
  1171. end
  1172. @spec get_recipients_from_activity(Activity.t()) :: [User.t()]
  1173. def get_recipients_from_activity(%Activity{recipients: to, actor: actor}) do
  1174. to = [actor | to]
  1175. query = User.Query.build(%{recipients_from_activity: to, local: true, is_active: true})
  1176. query
  1177. |> Repo.all()
  1178. end
  1179. @spec mute(User.t(), User.t(), map()) ::
  1180. {:ok, list(UserRelationship.t())} | {:error, String.t()}
  1181. def mute(%User{} = muter, %User{} = mutee, params \\ %{}) do
  1182. notifications? = Map.get(params, :notifications, true)
  1183. expires_in = Map.get(params, :expires_in, 0)
  1184. with {:ok, user_mute} <- UserRelationship.create_mute(muter, mutee),
  1185. {:ok, user_notification_mute} <-
  1186. (notifications? && UserRelationship.create_notification_mute(muter, mutee)) ||
  1187. {:ok, nil} do
  1188. if expires_in > 0 do
  1189. Pleroma.Workers.MuteExpireWorker.enqueue(
  1190. "unmute_user",
  1191. %{"muter_id" => muter.id, "mutee_id" => mutee.id},
  1192. schedule_in: expires_in
  1193. )
  1194. end
  1195. @cachex.del(:user_cache, "muted_users_ap_ids:#{muter.ap_id}")
  1196. {:ok, Enum.filter([user_mute, user_notification_mute], & &1)}
  1197. end
  1198. end
  1199. def unmute(%User{} = muter, %User{} = mutee) do
  1200. with {:ok, user_mute} <- UserRelationship.delete_mute(muter, mutee),
  1201. {:ok, user_notification_mute} <-
  1202. UserRelationship.delete_notification_mute(muter, mutee) do
  1203. @cachex.del(:user_cache, "muted_users_ap_ids:#{muter.ap_id}")
  1204. {:ok, [user_mute, user_notification_mute]}
  1205. end
  1206. end
  1207. def unmute(muter_id, mutee_id) do
  1208. with {:muter, %User{} = muter} <- {:muter, User.get_by_id(muter_id)},
  1209. {:mutee, %User{} = mutee} <- {:mutee, User.get_by_id(mutee_id)} do
  1210. unmute(muter, mutee)
  1211. else
  1212. {who, result} = error ->
  1213. Logger.warn(
  1214. "User.unmute/2 failed. #{who}: #{result}, muter_id: #{muter_id}, mutee_id: #{mutee_id}"
  1215. )
  1216. {:error, error}
  1217. end
  1218. end
  1219. def subscribe(%User{} = subscriber, %User{} = target) do
  1220. deny_follow_blocked = Config.get([:user, :deny_follow_blocked])
  1221. if blocks?(target, subscriber) and deny_follow_blocked do
  1222. {:error, "Could not subscribe: #{target.nickname} is blocking you"}
  1223. else
  1224. # Note: the relationship is inverse: subscriber acts as relationship target
  1225. UserRelationship.create_inverse_subscription(target, subscriber)
  1226. end
  1227. end
  1228. def subscribe(%User{} = subscriber, %{ap_id: ap_id}) do
  1229. with %User{} = subscribee <- get_cached_by_ap_id(ap_id) do
  1230. subscribe(subscriber, subscribee)
  1231. end
  1232. end
  1233. def unsubscribe(%User{} = unsubscriber, %User{} = target) do
  1234. # Note: the relationship is inverse: subscriber acts as relationship target
  1235. UserRelationship.delete_inverse_subscription(target, unsubscriber)
  1236. end
  1237. def unsubscribe(%User{} = unsubscriber, %{ap_id: ap_id}) do
  1238. with %User{} = user <- get_cached_by_ap_id(ap_id) do
  1239. unsubscribe(unsubscriber, user)
  1240. end
  1241. end
  1242. def block(%User{} = blocker, %User{} = blocked) do
  1243. # sever any follow relationships to prevent leaks per activitypub (Pleroma issue #213)
  1244. blocker =
  1245. if following?(blocker, blocked) do
  1246. {:ok, blocker, _} = unfollow(blocker, blocked)
  1247. blocker
  1248. else
  1249. blocker
  1250. end
  1251. # clear any requested follows as well
  1252. blocked =
  1253. case CommonAPI.reject_follow_request(blocked, blocker) do
  1254. {:ok, %User{} = updated_blocked} -> updated_blocked
  1255. nil -> blocked
  1256. end
  1257. unsubscribe(blocked, blocker)
  1258. unfollowing_blocked = Config.get([:activitypub, :unfollow_blocked], true)
  1259. if unfollowing_blocked && following?(blocked, blocker), do: unfollow(blocked, blocker)
  1260. {:ok, blocker} = update_follower_count(blocker)
  1261. {:ok, blocker, _} = Participation.mark_all_as_read(blocker, blocked)
  1262. add_to_block(blocker, blocked)
  1263. end
  1264. # helper to handle the block given only an actor's AP id
  1265. def block(%User{} = blocker, %{ap_id: ap_id}) do
  1266. block(blocker, get_cached_by_ap_id(ap_id))
  1267. end
  1268. def unblock(%User{} = blocker, %User{} = blocked) do
  1269. remove_from_block(blocker, blocked)
  1270. end
  1271. # helper to handle the block given only an actor's AP id
  1272. def unblock(%User{} = blocker, %{ap_id: ap_id}) do
  1273. unblock(blocker, get_cached_by_ap_id(ap_id))
  1274. end
  1275. def mutes?(nil, _), do: false
  1276. def mutes?(%User{} = user, %User{} = target), do: mutes_user?(user, target)
  1277. def mutes_user?(%User{} = user, %User{} = target) do
  1278. UserRelationship.mute_exists?(user, target)
  1279. end
  1280. @spec muted_notifications?(User.t() | nil, User.t() | map()) :: boolean()
  1281. def muted_notifications?(nil, _), do: false
  1282. def muted_notifications?(%User{} = user, %User{} = target),
  1283. do: UserRelationship.notification_mute_exists?(user, target)
  1284. def blocks?(nil, _), do: false
  1285. def blocks?(%User{} = user, %User{} = target) do
  1286. blocks_user?(user, target) ||
  1287. (blocks_domain?(user, target) and not User.following?(user, target))
  1288. end
  1289. def blocks_user?(%User{} = user, %User{} = target) do
  1290. UserRelationship.block_exists?(user, target)
  1291. end
  1292. def blocks_user?(_, _), do: false
  1293. def blocks_domain?(%User{} = user, %User{} = target) do
  1294. domain_blocks = Pleroma.Web.ActivityPub.MRF.subdomains_regex(user.domain_blocks)
  1295. %{host: host} = URI.parse(target.ap_id)
  1296. Pleroma.Web.ActivityPub.MRF.subdomain_match?(domain_blocks, host)
  1297. end
  1298. def blocks_domain?(_, _), do: false
  1299. def subscribed_to?(%User{} = user, %User{} = target) do
  1300. # Note: the relationship is inverse: subscriber acts as relationship target
  1301. UserRelationship.inverse_subscription_exists?(target, user)
  1302. end
  1303. def subscribed_to?(%User{} = user, %{ap_id: ap_id}) do
  1304. with %User{} = target <- get_cached_by_ap_id(ap_id) do
  1305. subscribed_to?(user, target)
  1306. end
  1307. end
  1308. @doc """
  1309. Returns map of outgoing (blocked, muted etc.) relationships' user AP IDs by relation type.
  1310. E.g. `outgoing_relationships_ap_ids(user, [:block])` -> `%{block: ["https://some.site/users/userapid"]}`
  1311. """
  1312. @spec outgoing_relationships_ap_ids(User.t(), list(atom())) :: %{atom() => list(String.t())}
  1313. def outgoing_relationships_ap_ids(_user, []), do: %{}
  1314. def outgoing_relationships_ap_ids(nil, _relationship_types), do: %{}
  1315. def outgoing_relationships_ap_ids(%User{} = user, relationship_types)
  1316. when is_list(relationship_types) do
  1317. db_result =
  1318. user
  1319. |> assoc(:outgoing_relationships)
  1320. |> join(:inner, [user_rel], u in assoc(user_rel, :target))
  1321. |> where([user_rel, u], user_rel.relationship_type in ^relationship_types)
  1322. |> select([user_rel, u], [user_rel.relationship_type, fragment("array_agg(?)", u.ap_id)])
  1323. |> group_by([user_rel, u], user_rel.relationship_type)
  1324. |> Repo.all()
  1325. |> Enum.into(%{}, fn [k, v] -> {k, v} end)
  1326. Enum.into(
  1327. relationship_types,
  1328. %{},
  1329. fn rel_type -> {rel_type, db_result[rel_type] || []} end
  1330. )
  1331. end
  1332. def incoming_relationships_ungrouped_ap_ids(user, relationship_types, ap_ids \\ nil)
  1333. def incoming_relationships_ungrouped_ap_ids(_user, [], _ap_ids), do: []
  1334. def incoming_relationships_ungrouped_ap_ids(nil, _relationship_types, _ap_ids), do: []
  1335. def incoming_relationships_ungrouped_ap_ids(%User{} = user, relationship_types, ap_ids)
  1336. when is_list(relationship_types) do
  1337. user
  1338. |> assoc(:incoming_relationships)
  1339. |> join(:inner, [user_rel], u in assoc(user_rel, :source))
  1340. |> where([user_rel, u], user_rel.relationship_type in ^relationship_types)
  1341. |> maybe_filter_on_ap_id(ap_ids)
  1342. |> select([user_rel, u], u.ap_id)
  1343. |> distinct(true)
  1344. |> Repo.all()
  1345. end
  1346. defp maybe_filter_on_ap_id(query, ap_ids) when is_list(ap_ids) do
  1347. where(query, [user_rel, u], u.ap_id in ^ap_ids)
  1348. end
  1349. defp maybe_filter_on_ap_id(query, _ap_ids), do: query
  1350. def set_activation_async(user, status \\ true) do
  1351. BackgroundWorker.enqueue("user_activation", %{"user_id" => user.id, "status" => status})
  1352. end
  1353. @spec set_activation([User.t()], boolean()) :: {:ok, User.t()} | {:error, Changeset.t()}
  1354. def set_activation(users, status) when is_list(users) do
  1355. Repo.transaction(fn ->
  1356. for user <- users, do: set_activation(user, status)
  1357. end)
  1358. end
  1359. @spec set_activation(User.t(), boolean()) :: {:ok, User.t()} | {:error, Changeset.t()}
  1360. def set_activation(%User{} = user, status) do
  1361. with {:ok, user} <- set_activation_status(user, status) do
  1362. user
  1363. |> get_followers()
  1364. |> Enum.filter(& &1.local)
  1365. |> Enum.each(&set_cache(update_following_count(&1)))
  1366. # Only update local user counts, remote will be update during the next pull.
  1367. user
  1368. |> get_friends()
  1369. |> Enum.filter(& &1.local)
  1370. |> Enum.each(&do_unfollow(user, &1))
  1371. {:ok, user}
  1372. end
  1373. end
  1374. def approve(users) when is_list(users) do
  1375. Repo.transaction(fn ->
  1376. Enum.map(users, fn user ->
  1377. with {:ok, user} <- approve(user), do: user
  1378. end)
  1379. end)
  1380. end
  1381. def approve(%User{is_approved: false} = user) do
  1382. with chg <- change(user, is_approved: true),
  1383. {:ok, user} <- update_and_set_cache(chg) do
  1384. post_register_action(user)
  1385. {:ok, user}
  1386. end
  1387. end
  1388. def approve(%User{} = user), do: {:ok, user}
  1389. def confirm(users) when is_list(users) do
  1390. Repo.transaction(fn ->
  1391. Enum.map(users, fn user ->
  1392. with {:ok, user} <- confirm(user), do: user
  1393. end)
  1394. end)
  1395. end
  1396. def confirm(%User{is_confirmed: false} = user) do
  1397. with chg <- confirmation_changeset(user, set_confirmation: true),
  1398. {:ok, user} <- update_and_set_cache(chg) do
  1399. post_register_action(user)
  1400. {:ok, user}
  1401. end
  1402. end
  1403. def confirm(%User{} = user), do: {:ok, user}
  1404. def update_notification_settings(%User{} = user, settings) do
  1405. user
  1406. |> cast(%{notification_settings: settings}, [])
  1407. |> cast_embed(:notification_settings)
  1408. |> validate_required([:notification_settings])
  1409. |> update_and_set_cache()
  1410. end
  1411. @spec purge_user_changeset(User.t()) :: Changeset.t()
  1412. def purge_user_changeset(user) do
  1413. # "Right to be forgotten"
  1414. # https://gdpr.eu/right-to-be-forgotten/
  1415. change(user, %{
  1416. bio: "",
  1417. raw_bio: nil,
  1418. email: nil,
  1419. name: nil,
  1420. password_hash: nil,
  1421. keys: nil,
  1422. public_key: nil,
  1423. avatar: %{},
  1424. tags: [],
  1425. last_refreshed_at: nil,
  1426. last_digest_emailed_at: nil,
  1427. banner: %{},
  1428. background: %{},
  1429. note_count: 0,
  1430. follower_count: 0,
  1431. following_count: 0,
  1432. is_locked: false,
  1433. is_confirmed: true,
  1434. password_reset_pending: false,
  1435. is_approved: true,
  1436. registration_reason: nil,
  1437. confirmation_token: nil,
  1438. domain_blocks: [],
  1439. is_active: false,
  1440. ap_enabled: false,
  1441. is_moderator: false,
  1442. is_admin: false,
  1443. mastofe_settings: nil,
  1444. mascot: nil,
  1445. emoji: %{},
  1446. pleroma_settings_store: %{},
  1447. fields: [],
  1448. raw_fields: [],
  1449. is_discoverable: false,
  1450. also_known_as: []
  1451. })
  1452. end
  1453. def delete(users) when is_list(users) do
  1454. for user <- users, do: delete(user)
  1455. end
  1456. def delete(%User{} = user) do
  1457. BackgroundWorker.enqueue("delete_user", %{"user_id" => user.id})
  1458. end
  1459. defp delete_and_invalidate_cache(%User{} = user) do
  1460. invalidate_cache(user)
  1461. Repo.delete(user)
  1462. end
  1463. defp delete_or_deactivate(%User{local: false} = user), do: delete_and_invalidate_cache(user)
  1464. defp delete_or_deactivate(%User{local: true} = user) do
  1465. status = account_status(user)
  1466. case status do
  1467. :confirmation_pending ->
  1468. delete_and_invalidate_cache(user)
  1469. :approval_pending ->
  1470. delete_and_invalidate_cache(user)
  1471. _ ->
  1472. user
  1473. |> purge_user_changeset()
  1474. |> update_and_set_cache()
  1475. end
  1476. end
  1477. def perform(:force_password_reset, user), do: force_password_reset(user)
  1478. @spec perform(atom(), User.t()) :: {:ok, User.t()}
  1479. def perform(:delete, %User{} = user) do
  1480. # Remove all relationships
  1481. user
  1482. |> get_followers()
  1483. |> Enum.each(fn follower ->
  1484. ActivityPub.unfollow(follower, user)
  1485. unfollow(follower, user)
  1486. end)
  1487. user
  1488. |> get_friends()
  1489. |> Enum.each(fn followed ->
  1490. ActivityPub.unfollow(user, followed)
  1491. unfollow(user, followed)
  1492. end)
  1493. delete_user_activities(user)
  1494. delete_notifications_from_user_activities(user)
  1495. delete_outgoing_pending_follow_requests(user)
  1496. delete_or_deactivate(user)
  1497. end
  1498. def perform(:set_activation_async, user, status), do: set_activation(user, status)
  1499. @spec external_users_query() :: Ecto.Query.t()
  1500. def external_users_query do
  1501. User.Query.build(%{
  1502. external: true,
  1503. active: true,
  1504. order_by: :id
  1505. })
  1506. end
  1507. @spec external_users(keyword()) :: [User.t()]
  1508. def external_users(opts \\ []) do
  1509. query =
  1510. external_users_query()
  1511. |> select([u], struct(u, [:id, :ap_id]))
  1512. query =
  1513. if opts[:max_id],
  1514. do: where(query, [u], u.id > ^opts[:max_id]),
  1515. else: query
  1516. query =
  1517. if opts[:limit],
  1518. do: limit(query, ^opts[:limit]),
  1519. else: query
  1520. Repo.all(query)
  1521. end
  1522. def delete_notifications_from_user_activities(%User{ap_id: ap_id}) do
  1523. Notification
  1524. |> join(:inner, [n], activity in assoc(n, :activity))
  1525. |> where([n, a], fragment("? = ?", a.actor, ^ap_id))
  1526. |> Repo.delete_all()
  1527. end
  1528. def delete_user_activities(%User{ap_id: ap_id} = user) do
  1529. ap_id
  1530. |> Activity.Queries.by_actor()
  1531. |> Repo.chunk_stream(50, :batches)
  1532. |> Stream.each(fn activities ->
  1533. Enum.each(activities, fn activity -> delete_activity(activity, user) end)
  1534. end)
  1535. |> Stream.run()
  1536. end
  1537. defp delete_activity(%{data: %{"type" => "Create", "object" => object}} = activity, user) do
  1538. with {_, %Object{}} <- {:find_object, Object.get_by_ap_id(object)},
  1539. {:ok, delete_data, _} <- Builder.delete(user, object) do
  1540. Pipeline.common_pipeline(delete_data, local: user.local)
  1541. else
  1542. {:find_object, nil} ->
  1543. # We have the create activity, but not the object, it was probably pruned.
  1544. # Insert a tombstone and try again
  1545. with {:ok, tombstone_data, _} <- Builder.tombstone(user.ap_id, object),
  1546. {:ok, _tombstone} <- Object.create(tombstone_data) do
  1547. delete_activity(activity, user)
  1548. end
  1549. e ->
  1550. Logger.error("Could not delete #{object} created by #{activity.data["ap_id"]}")
  1551. Logger.error("Error: #{inspect(e)}")
  1552. end
  1553. end
  1554. defp delete_activity(%{data: %{"type" => type}} = activity, user)
  1555. when type in ["Like", "Announce"] do
  1556. {:ok, undo, _} = Builder.undo(user, activity)
  1557. Pipeline.common_pipeline(undo, local: user.local)
  1558. end
  1559. defp delete_activity(_activity, _user), do: "Doing nothing"
  1560. defp delete_outgoing_pending_follow_requests(user) do
  1561. user
  1562. |> FollowingRelationship.outgoing_pending_follow_requests_query()
  1563. |> Repo.delete_all()
  1564. end
  1565. def html_filter_policy(%User{no_rich_text: true}) do
  1566. Pleroma.HTML.Scrubber.TwitterText
  1567. end
  1568. def html_filter_policy(_), do: Config.get([:markup, :scrub_policy])
  1569. def fetch_by_ap_id(ap_id), do: ActivityPub.make_user_from_ap_id(ap_id)
  1570. def get_or_fetch_by_ap_id(ap_id) do
  1571. cached_user = get_cached_by_ap_id(ap_id)
  1572. maybe_fetched_user = needs_update?(cached_user) && fetch_by_ap_id(ap_id)
  1573. case {cached_user, maybe_fetched_user} do
  1574. {_, {:ok, %User{} = user}} ->
  1575. {:ok, user}
  1576. {%User{} = user, _} ->
  1577. {:ok, user}
  1578. _ ->
  1579. {:error, :not_found}
  1580. end
  1581. end
  1582. @doc """
  1583. Creates an internal service actor by URI if missing.
  1584. Optionally takes nickname for addressing.
  1585. """
  1586. @spec get_or_create_service_actor_by_ap_id(String.t(), String.t()) :: User.t() | nil
  1587. def get_or_create_service_actor_by_ap_id(uri, nickname) do
  1588. {_, user} =
  1589. case get_cached_by_ap_id(uri) do
  1590. nil ->
  1591. with {:error, %{errors: errors}} <- create_service_actor(uri, nickname) do
  1592. Logger.error("Cannot create service actor: #{uri}/.\n#{inspect(errors)}")
  1593. {:error, nil}
  1594. end
  1595. %User{invisible: false} = user ->
  1596. set_invisible(user)
  1597. user ->
  1598. {:ok, user}
  1599. end
  1600. user
  1601. end
  1602. @spec set_invisible(User.t()) :: {:ok, User.t()}
  1603. defp set_invisible(user) do
  1604. user
  1605. |> change(%{invisible: true})
  1606. |> update_and_set_cache()
  1607. end
  1608. @spec create_service_actor(String.t(), String.t()) ::
  1609. {:ok, User.t()} | {:error, Ecto.Changeset.t()}
  1610. defp create_service_actor(uri, nickname) do
  1611. %User{
  1612. invisible: true,
  1613. local: true,
  1614. ap_id: uri,
  1615. nickname: nickname,
  1616. follower_address: uri <> "/followers"
  1617. }
  1618. |> change
  1619. |> unique_constraint(:nickname)
  1620. |> Repo.insert()
  1621. |> set_cache()
  1622. end
  1623. def public_key(%{public_key: public_key_pem}) when is_binary(public_key_pem) do
  1624. key =
  1625. public_key_pem
  1626. |> :public_key.pem_decode()
  1627. |> hd()
  1628. |> :public_key.pem_entry_decode()
  1629. {:ok, key}
  1630. end
  1631. def public_key(_), do: {:error, "key not found"}
  1632. def get_public_key_for_ap_id(ap_id) do
  1633. with {:ok, %User{} = user} <- get_or_fetch_by_ap_id(ap_id),
  1634. {:ok, public_key} <- public_key(user) do
  1635. {:ok, public_key}
  1636. else
  1637. _ -> :error
  1638. end
  1639. end
  1640. def ap_enabled?(%User{local: true}), do: true
  1641. def ap_enabled?(%User{ap_enabled: ap_enabled}), do: ap_enabled
  1642. def ap_enabled?(_), do: false
  1643. @doc "Gets or fetch a user by uri or nickname."
  1644. @spec get_or_fetch(String.t()) :: {:ok, User.t()} | {:error, String.t()}
  1645. def get_or_fetch("http" <> _host = uri), do: get_or_fetch_by_ap_id(uri)
  1646. def get_or_fetch(nickname), do: get_or_fetch_by_nickname(nickname)
  1647. # wait a period of time and return newest version of the User structs
  1648. # this is because we have synchronous follow APIs and need to simulate them
  1649. # with an async handshake
  1650. def wait_and_refresh(_, %User{local: true} = a, %User{local: true} = b) do
  1651. with %User{} = a <- get_cached_by_id(a.id),
  1652. %User{} = b <- get_cached_by_id(b.id) do
  1653. {:ok, a, b}
  1654. else
  1655. nil -> :error
  1656. end
  1657. end
  1658. def wait_and_refresh(timeout, %User{} = a, %User{} = b) do
  1659. with :ok <- :timer.sleep(timeout),
  1660. %User{} = a <- get_cached_by_id(a.id),
  1661. %User{} = b <- get_cached_by_id(b.id) do
  1662. {:ok, a, b}
  1663. else
  1664. nil -> :error
  1665. end
  1666. end
  1667. def parse_bio(bio) when is_binary(bio) and bio != "" do
  1668. bio
  1669. |> CommonUtils.format_input("text/plain", mentions_format: :full)
  1670. |> elem(0)
  1671. end
  1672. def parse_bio(_), do: ""
  1673. def parse_bio(bio, user) when is_binary(bio) and bio != "" do
  1674. # TODO: get profile URLs other than user.ap_id
  1675. profile_urls = [user.ap_id]
  1676. bio
  1677. |> CommonUtils.format_input("text/plain",
  1678. mentions_format: :full,
  1679. rel: &RelMe.maybe_put_rel_me(&1, profile_urls)
  1680. )
  1681. |> elem(0)
  1682. end
  1683. def parse_bio(_, _), do: ""
  1684. def tag(user_identifiers, tags) when is_list(user_identifiers) do
  1685. Repo.transaction(fn ->
  1686. for user_identifier <- user_identifiers, do: tag(user_identifier, tags)
  1687. end)
  1688. end
  1689. def tag(nickname, tags) when is_binary(nickname),
  1690. do: tag(get_by_nickname(nickname), tags)
  1691. def tag(%User{} = user, tags),
  1692. do: update_tags(user, Enum.uniq((user.tags || []) ++ normalize_tags(tags)))
  1693. def untag(user_identifiers, tags) when is_list(user_identifiers) do
  1694. Repo.transaction(fn ->
  1695. for user_identifier <- user_identifiers, do: untag(user_identifier, tags)
  1696. end)
  1697. end
  1698. def untag(nickname, tags) when is_binary(nickname),
  1699. do: untag(get_by_nickname(nickname), tags)
  1700. def untag(%User{} = user, tags),
  1701. do: update_tags(user, (user.tags || []) -- normalize_tags(tags))
  1702. defp update_tags(%User{} = user, new_tags) do
  1703. {:ok, updated_user} =
  1704. user
  1705. |> change(%{tags: new_tags})
  1706. |> update_and_set_cache()
  1707. updated_user
  1708. end
  1709. defp normalize_tags(tags) do
  1710. [tags]
  1711. |> List.flatten()
  1712. |> Enum.map(&String.downcase/1)
  1713. end
  1714. defp local_nickname_regex do
  1715. if Config.get([:instance, :extended_nickname_format]) do
  1716. @extended_local_nickname_regex
  1717. else
  1718. @strict_local_nickname_regex
  1719. end
  1720. end
  1721. def local_nickname(nickname_or_mention) do
  1722. nickname_or_mention
  1723. |> full_nickname()
  1724. |> String.split("@")
  1725. |> hd()
  1726. end
  1727. def full_nickname(%User{} = user) do
  1728. if String.contains?(user.nickname, "@") do
  1729. user.nickname
  1730. else
  1731. %{host: host} = URI.parse(user.ap_id)
  1732. user.nickname <> "@" <> host
  1733. end
  1734. end
  1735. def full_nickname(nickname_or_mention),
  1736. do: String.trim_leading(nickname_or_mention, "@")
  1737. def error_user(ap_id) do
  1738. %User{
  1739. name: ap_id,
  1740. ap_id: ap_id,
  1741. nickname: "erroruser@example.com",
  1742. inserted_at: NaiveDateTime.utc_now()
  1743. }
  1744. end
  1745. @spec all_superusers() :: [User.t()]
  1746. def all_superusers do
  1747. User.Query.build(%{super_users: true, local: true, is_active: true})
  1748. |> Repo.all()
  1749. end
  1750. def muting_reblogs?(%User{} = user, %User{} = target) do
  1751. UserRelationship.reblog_mute_exists?(user, target)
  1752. end
  1753. def showing_reblogs?(%User{} = user, %User{} = target) do
  1754. not muting_reblogs?(user, target)
  1755. end
  1756. @doc """
  1757. The function returns a query to get users with no activity for given interval of days.
  1758. Inactive users are those who didn't read any notification, or had any activity where
  1759. the user is the activity's actor, during `inactivity_threshold` days.
  1760. Deactivated users will not appear in this list.
  1761. ## Examples
  1762. iex> Pleroma.User.list_inactive_users()
  1763. %Ecto.Query{}
  1764. """
  1765. @spec list_inactive_users_query(integer()) :: Ecto.Query.t()
  1766. def list_inactive_users_query(inactivity_threshold \\ 7) do
  1767. negative_inactivity_threshold = -inactivity_threshold
  1768. now = NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
  1769. # Subqueries are not supported in `where` clauses, join gets too complicated.
  1770. has_read_notifications =
  1771. from(n in Pleroma.Notification,
  1772. where: n.seen == true,
  1773. group_by: n.id,
  1774. having: max(n.updated_at) > datetime_add(^now, ^negative_inactivity_threshold, "day"),
  1775. select: n.user_id
  1776. )
  1777. |> Pleroma.Repo.all()
  1778. from(u in Pleroma.User,
  1779. left_join: a in Pleroma.Activity,
  1780. on: u.ap_id == a.actor,
  1781. where: not is_nil(u.nickname),
  1782. where: u.is_active == ^true,
  1783. where: u.id not in ^has_read_notifications,
  1784. group_by: u.id,
  1785. having:
  1786. max(a.inserted_at) < datetime_add(^now, ^negative_inactivity_threshold, "day") or
  1787. is_nil(max(a.inserted_at))
  1788. )
  1789. end
  1790. @doc """
  1791. Enable or disable email notifications for user
  1792. ## Examples
  1793. iex> Pleroma.User.switch_email_notifications(Pleroma.User{email_notifications: %{"digest" => false}}, "digest", true)
  1794. Pleroma.User{email_notifications: %{"digest" => true}}
  1795. iex> Pleroma.User.switch_email_notifications(Pleroma.User{email_notifications: %{"digest" => true}}, "digest", false)
  1796. Pleroma.User{email_notifications: %{"digest" => false}}
  1797. """
  1798. @spec switch_email_notifications(t(), String.t(), boolean()) ::
  1799. {:ok, t()} | {:error, Ecto.Changeset.t()}
  1800. def switch_email_notifications(user, type, status) do
  1801. User.update_email_notifications(user, %{type => status})
  1802. end
  1803. @doc """
  1804. Set `last_digest_emailed_at` value for the user to current time
  1805. """
  1806. @spec touch_last_digest_emailed_at(t()) :: t()
  1807. def touch_last_digest_emailed_at(user) do
  1808. now = NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
  1809. {:ok, updated_user} =
  1810. user
  1811. |> change(%{last_digest_emailed_at: now})
  1812. |> update_and_set_cache()
  1813. updated_user
  1814. end
  1815. @spec set_confirmation(User.t(), boolean()) :: {:ok, User.t()} | {:error, Changeset.t()}
  1816. def set_confirmation(%User{} = user, bool) do
  1817. user
  1818. |> confirmation_changeset(set_confirmation: bool)
  1819. |> update_and_set_cache()
  1820. end
  1821. def get_mascot(%{mascot: %{} = mascot}) when not is_nil(mascot) do
  1822. mascot
  1823. end
  1824. def get_mascot(%{mascot: mascot}) when is_nil(mascot) do
  1825. # use instance-default
  1826. config = Config.get([:assets, :mascots])
  1827. default_mascot = Config.get([:assets, :default_mascot])
  1828. mascot = Keyword.get(config, default_mascot)
  1829. %{
  1830. "id" => "default-mascot",
  1831. "url" => mascot[:url],
  1832. "preview_url" => mascot[:url],
  1833. "pleroma" => %{
  1834. "mime_type" => mascot[:mime_type]
  1835. }
  1836. }
  1837. end
  1838. def ensure_keys_present(%{keys: keys} = user) when not is_nil(keys), do: {:ok, user}
  1839. def ensure_keys_present(%User{} = user) do
  1840. with {:ok, pem} <- Keys.generate_rsa_pem() do
  1841. user
  1842. |> cast(%{keys: pem}, [:keys])
  1843. |> validate_required([:keys])
  1844. |> update_and_set_cache()
  1845. end
  1846. end
  1847. def get_ap_ids_by_nicknames(nicknames) do
  1848. from(u in User,
  1849. where: u.nickname in ^nicknames,
  1850. select: u.ap_id
  1851. )
  1852. |> Repo.all()
  1853. end
  1854. defp put_password_hash(
  1855. %Ecto.Changeset{valid?: true, changes: %{password: password}} = changeset
  1856. ) do
  1857. change(changeset, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password))
  1858. end
  1859. defp put_password_hash(changeset), do: changeset
  1860. def is_internal_user?(%User{nickname: nil}), do: true
  1861. def is_internal_user?(%User{local: true, nickname: "internal." <> _}), do: true
  1862. def is_internal_user?(_), do: false
  1863. # A hack because user delete activities have a fake id for whatever reason
  1864. # TODO: Get rid of this
  1865. def get_delivered_users_by_object_id("pleroma:fake_object_id"), do: []
  1866. def get_delivered_users_by_object_id(object_id) do
  1867. from(u in User,
  1868. inner_join: delivery in assoc(u, :deliveries),
  1869. where: delivery.object_id == ^object_id
  1870. )
  1871. |> Repo.all()
  1872. end
  1873. def change_email(user, email) do
  1874. user
  1875. |> cast(%{email: email}, [:email])
  1876. |> validate_required([:email])
  1877. |> unique_constraint(:email)
  1878. |> validate_format(:email, @email_regex)
  1879. |> update_and_set_cache()
  1880. end
  1881. # Internal function; public one is `deactivate/2`
  1882. defp set_activation_status(user, status) do
  1883. user
  1884. |> cast(%{is_active: status}, [:is_active])
  1885. |> update_and_set_cache()
  1886. end
  1887. def update_banner(user, banner) do
  1888. user
  1889. |> cast(%{banner: banner}, [:banner])
  1890. |> update_and_set_cache()
  1891. end
  1892. def update_background(user, background) do
  1893. user
  1894. |> cast(%{background: background}, [:background])
  1895. |> update_and_set_cache()
  1896. end
  1897. def roles(%{is_moderator: is_moderator, is_admin: is_admin}) do
  1898. %{
  1899. admin: is_admin,
  1900. moderator: is_moderator
  1901. }
  1902. end
  1903. def validate_fields(changeset, remote? \\ false) do
  1904. limit_name = if remote?, do: :max_remote_account_fields, else: :max_account_fields
  1905. limit = Config.get([:instance, limit_name], 0)
  1906. changeset
  1907. |> validate_length(:fields, max: limit)
  1908. |> validate_change(:fields, fn :fields, fields ->
  1909. if Enum.all?(fields, &valid_field?/1) do
  1910. []
  1911. else
  1912. [fields: "invalid"]
  1913. end
  1914. end)
  1915. end
  1916. defp valid_field?(%{"name" => name, "value" => value}) do
  1917. name_limit = Config.get([:instance, :account_field_name_length], 255)
  1918. value_limit = Config.get([:instance, :account_field_value_length], 255)
  1919. is_binary(name) && is_binary(value) && String.length(name) <= name_limit &&
  1920. String.length(value) <= value_limit
  1921. end
  1922. defp valid_field?(_), do: false
  1923. defp truncate_field(%{"name" => name, "value" => value}) do
  1924. {name, _chopped} =
  1925. String.split_at(name, Config.get([:instance, :account_field_name_length], 255))
  1926. {value, _chopped} =
  1927. String.split_at(value, Config.get([:instance, :account_field_value_length], 255))
  1928. %{"name" => name, "value" => value}
  1929. end
  1930. def admin_api_update(user, params) do
  1931. user
  1932. |> cast(params, [
  1933. :is_moderator,
  1934. :is_admin,
  1935. :show_role
  1936. ])
  1937. |> update_and_set_cache()
  1938. end
  1939. @doc "Signs user out of all applications"
  1940. def global_sign_out(user) do
  1941. OAuth.Authorization.delete_user_authorizations(user)
  1942. OAuth.Token.delete_user_tokens(user)
  1943. end
  1944. def mascot_update(user, url) do
  1945. user
  1946. |> cast(%{mascot: url}, [:mascot])
  1947. |> validate_required([:mascot])
  1948. |> update_and_set_cache()
  1949. end
  1950. def mastodon_settings_update(user, settings) do
  1951. user
  1952. |> cast(%{mastofe_settings: settings}, [:mastofe_settings])
  1953. |> validate_required([:mastofe_settings])
  1954. |> update_and_set_cache()
  1955. end
  1956. @spec confirmation_changeset(User.t(), keyword()) :: Changeset.t()
  1957. def confirmation_changeset(user, set_confirmation: confirmed?) do
  1958. params =
  1959. if confirmed? do
  1960. %{
  1961. is_confirmed: true,
  1962. confirmation_token: nil
  1963. }
  1964. else
  1965. %{
  1966. is_confirmed: false,
  1967. confirmation_token: :crypto.strong_rand_bytes(32) |> Base.url_encode64()
  1968. }
  1969. end
  1970. cast(user, params, [:is_confirmed, :confirmation_token])
  1971. end
  1972. @spec approval_changeset(User.t(), keyword()) :: Changeset.t()
  1973. def approval_changeset(user, set_approval: approved?) do
  1974. cast(user, %{is_approved: approved?}, [:is_approved])
  1975. end
  1976. def add_pinnned_activity(user, %Pleroma.Activity{id: id}) do
  1977. if id not in user.pinned_activities do
  1978. max_pinned_statuses = Config.get([:instance, :max_pinned_statuses], 0)
  1979. params = %{pinned_activities: user.pinned_activities ++ [id]}
  1980. # if pinned activity was scheduled for deletion, we remove job
  1981. if expiration = Pleroma.Workers.PurgeExpiredActivity.get_expiration(id) do
  1982. Oban.cancel_job(expiration.id)
  1983. end
  1984. user
  1985. |> cast(params, [:pinned_activities])
  1986. |> validate_length(:pinned_activities,
  1987. max: max_pinned_statuses,
  1988. message: "You have already pinned the maximum number of statuses"
  1989. )
  1990. else
  1991. change(user)
  1992. end
  1993. |> update_and_set_cache()
  1994. end
  1995. def remove_pinnned_activity(user, %Pleroma.Activity{id: id, data: data}) do
  1996. params = %{pinned_activities: List.delete(user.pinned_activities, id)}
  1997. # if pinned activity was scheduled for deletion, we reschedule it for deletion
  1998. if data["expires_at"] do
  1999. # MRF.ActivityExpirationPolicy used UTC timestamps for expires_at in original implementation
  2000. {:ok, expires_at} =
  2001. data["expires_at"] |> Pleroma.EctoType.ActivityPub.ObjectValidators.DateTime.cast()
  2002. Pleroma.Workers.PurgeExpiredActivity.enqueue(%{
  2003. activity_id: id,
  2004. expires_at: expires_at
  2005. })
  2006. end
  2007. user
  2008. |> cast(params, [:pinned_activities])
  2009. |> update_and_set_cache()
  2010. end
  2011. def update_email_notifications(user, settings) do
  2012. email_notifications =
  2013. user.email_notifications
  2014. |> Map.merge(settings)
  2015. |> Map.take(["digest"])
  2016. params = %{email_notifications: email_notifications}
  2017. fields = [:email_notifications]
  2018. user
  2019. |> cast(params, fields)
  2020. |> validate_required(fields)
  2021. |> update_and_set_cache()
  2022. end
  2023. defp set_domain_blocks(user, domain_blocks) do
  2024. params = %{domain_blocks: domain_blocks}
  2025. user
  2026. |> cast(params, [:domain_blocks])
  2027. |> validate_required([:domain_blocks])
  2028. |> update_and_set_cache()
  2029. end
  2030. def block_domain(user, domain_blocked) do
  2031. set_domain_blocks(user, Enum.uniq([domain_blocked | user.domain_blocks]))
  2032. end
  2033. def unblock_domain(user, domain_blocked) do
  2034. set_domain_blocks(user, List.delete(user.domain_blocks, domain_blocked))
  2035. end
  2036. @spec add_to_block(User.t(), User.t()) ::
  2037. {:ok, UserRelationship.t()} | {:error, Ecto.Changeset.t()}
  2038. defp add_to_block(%User{} = user, %User{} = blocked) do
  2039. with {:ok, relationship} <- UserRelationship.create_block(user, blocked) do
  2040. @cachex.del(:user_cache, "blocked_users_ap_ids:#{user.ap_id}")
  2041. {:ok, relationship}
  2042. end
  2043. end
  2044. @spec add_to_block(User.t(), User.t()) ::
  2045. {:ok, UserRelationship.t()} | {:ok, nil} | {:error, Ecto.Changeset.t()}
  2046. defp remove_from_block(%User{} = user, %User{} = blocked) do
  2047. with {:ok, relationship} <- UserRelationship.delete_block(user, blocked) do
  2048. @cachex.del(:user_cache, "blocked_users_ap_ids:#{user.ap_id}")
  2049. {:ok, relationship}
  2050. end
  2051. end
  2052. def set_invisible(user, invisible) do
  2053. params = %{invisible: invisible}
  2054. user
  2055. |> cast(params, [:invisible])
  2056. |> validate_required([:invisible])
  2057. |> update_and_set_cache()
  2058. end
  2059. def sanitize_html(%User{} = user) do
  2060. sanitize_html(user, nil)
  2061. end
  2062. # User data that mastodon isn't filtering (treated as plaintext):
  2063. # - field name
  2064. # - display name
  2065. def sanitize_html(%User{} = user, filter) do
  2066. fields =
  2067. Enum.map(user.fields, fn %{"name" => name, "value" => value} ->
  2068. %{
  2069. "name" => name,
  2070. "value" => HTML.filter_tags(value, Pleroma.HTML.Scrubber.LinksOnly)
  2071. }
  2072. end)
  2073. user
  2074. |> Map.put(:bio, HTML.filter_tags(user.bio, filter))
  2075. |> Map.put(:fields, fields)
  2076. end
  2077. def get_host(%User{ap_id: ap_id} = _user) do
  2078. URI.parse(ap_id).host
  2079. end
  2080. def update_last_active_at(%__MODULE__{local: true} = user) do
  2081. user
  2082. |> cast(%{last_active_at: NaiveDateTime.utc_now()}, [:last_active_at])
  2083. |> update_and_set_cache()
  2084. end
  2085. def active_user_count(weeks \\ 4) do
  2086. active_after = Timex.shift(NaiveDateTime.utc_now(), weeks: -weeks)
  2087. __MODULE__
  2088. |> where([u], u.last_active_at >= ^active_after)
  2089. |> where([u], u.local == true)
  2090. |> Repo.aggregate(:count)
  2091. end
  2092. end