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.

2387 lines
71KB

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