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.

2495 lines
75KB

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