diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/pleroma/tag.ex | 35 | ||||
-rw-r--r-- | lib/pleroma/user.ex | 127 | ||||
-rw-r--r-- | lib/pleroma/user/query.ex | 4 | ||||
-rw-r--r-- | lib/pleroma/web/activity_pub/mrf/tag_policy.ex | 6 | ||||
-rw-r--r-- | lib/pleroma/web/admin_api/views/account_view.ex | 3 | ||||
-rw-r--r-- | lib/pleroma/web/mastodon_api/views/account_view.ex | 4 |
6 files changed, 125 insertions, 54 deletions
diff --git a/lib/pleroma/tag.ex b/lib/pleroma/tag.ex index 5185a907b..3b01f1119 100644 --- a/lib/pleroma/tag.ex +++ b/lib/pleroma/tag.ex @@ -22,11 +22,23 @@ defmodule Pleroma.Tag do @spec upsert(String.t()) :: {:ok, t()} | {:error, Ecto.Changeset.t()} def upsert(name) do %__MODULE__{} - |> Ecto.Changeset.change(name: name) + |> Ecto.Changeset.change(name: normalize_tag(name)) |> Ecto.Changeset.unique_constraint(:name) |> Repo.insert(on_conflict: :nothing, conflict_target: :name) end + @spec upsert_tags(list(String.t())) :: {integer(), nil | [term()]} + def upsert_tags(names) do + date = NaiveDateTime.utc_now() + + tags = + names + |> normalize_tags() + |> Enum.map(&%{name: &1, inserted_at: date, updated_at: date}) + + Repo.insert_all("tags", tags, on_conflict: :nothing, conflict_target: :name) + end + @spec list_tags() :: list(String.t()) def list_tags do from(u in __MODULE__, select: u.name) @@ -35,4 +47,25 @@ defmodule Pleroma.Tag do |> Enum.uniq() |> Enum.sort() end + + def get_tag_ids(tag_names) do + names = normalize_tags(tag_names) + + from( + u in __MODULE__, + select: u.id, + where: u.name in ^names + ) + |> Repo.all() + end + + def normalize_tags(tag_names) do + tag_names + |> List.wrap() + |> Enum.map(&normalize_tag/1) + end + + defp normalize_tag(tag_name) do + String.trim(String.downcase(tag_name)) + end end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index e4cb8e5c1..9396815e9 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1674,43 +1674,51 @@ defmodule Pleroma.User do def purge_user_changeset(user) do # "Right to be forgotten" # https://gdpr.eu/right-to-be-forgotten/ - change(user, %{ - bio: "", - raw_bio: nil, - email: nil, - name: nil, - password_hash: nil, - keys: nil, - public_key: nil, - avatar: %{}, - tags: [], - last_refreshed_at: nil, - last_digest_emailed_at: nil, - banner: %{}, - background: %{}, - note_count: 0, - follower_count: 0, - following_count: 0, - is_locked: false, - is_confirmed: true, - password_reset_pending: false, - is_approved: true, - registration_reason: nil, - confirmation_token: nil, - domain_blocks: [], - is_active: false, - ap_enabled: false, - is_moderator: false, - is_admin: false, - mastofe_settings: nil, - mascot: nil, - emoji: %{}, - pleroma_settings_store: %{}, - fields: [], - raw_fields: [], - is_discoverable: false, - also_known_as: [] - }) + + default_user_attrs = + Map.take( + %__MODULE__{}, + [ + :registration_reason, + :is_discoverable, + :mastofe_settings, + :email, + :background, + :is_approved, + :avatar, + :password_hash, + :public_key, + :mascot, + :is_confirmed, + :is_locked, + :ap_enabled, + :note_count, + :pleroma_settings_store, + :follower_count, + :bio, + :name, + :is_admin, + :is_moderator, + :also_known_as, + :keys, + :confirmation_token, + :banner, + :raw_fields, + :fields, + :password_reset_pending, + :domain_blocks, + :last_digest_emailed_at, + :raw_bio, + :last_refreshed_at, + :emoji, + :following_count + ] + ) + + user + |> Repo.preload([:tags]) + |> change(Map.merge(default_user_attrs, %{is_active: false})) + |> put_assoc(:tags, []) end def delete(users) when is_list(users) do @@ -2007,8 +2015,11 @@ defmodule Pleroma.User do def tag(nickname, tags) when is_binary(nickname), do: tag(get_by_nickname(nickname), tags) - def tag(%User{} = user, tags), - do: update_tags(user, Enum.uniq((user.tags || []) ++ normalize_tags(tags))) + def tag(%User{} = user, tags) do + tag_names = Pleroma.Tag.normalize_tags(tags) + Pleroma.Tag.upsert_tags(tag_names) + update_tags(user, tag_names) + end def untag(user_identifiers, tags) when is_list(user_identifiers) do Repo.transaction(fn -> @@ -2019,24 +2030,42 @@ defmodule Pleroma.User do def untag(nickname, tags) when is_binary(nickname), do: untag(get_by_nickname(nickname), tags) - def untag(%User{} = user, tags), - do: update_tags(user, (user.tags || []) -- normalize_tags(tags)) + def untag(%User{} = user, remove_tags) do + tag_ids = Pleroma.Tag.get_tag_ids(remove_tags) + {:ok, user_id} = FlakeId.Ecto.Type.dump(user.id) + + from( + ut in "users_tags", + where: ut.user_id == ^user_id, + where: ut.tag_id in ^tag_ids + ) + |> Repo.delete_all() + + preload_tags_and_set_cache(user) + end defp update_tags(%User{} = user, new_tags) do + {:ok, user_id} = FlakeId.Ecto.Type.dump(user.id) + + tags = + new_tags + |> Pleroma.Tag.normalize_tags() + |> Pleroma.Tag.get_tag_ids() + |> Enum.map(&%{user_id: user_id, tag_id: &1}) + + Repo.insert_all("users_tags", tags, on_conflict: :nothing) + preload_tags_and_set_cache(user) + end + + defp preload_tags_and_set_cache(user) do {:ok, updated_user} = user - |> change(%{tags: new_tags}) - |> update_and_set_cache() + |> Repo.preload([:tags], force: true) + |> set_cache() updated_user end - defp normalize_tags(tags) do - [tags] - |> List.flatten() - |> Enum.map(&String.downcase/1) - end - defp local_nickname_regex do if Config.get([:instance, :extended_nickname_format]) do @extended_local_nickname_regex diff --git a/lib/pleroma/user/query.ex b/lib/pleroma/user/query.ex index fa46545da..36e03466a 100644 --- a/lib/pleroma/user/query.ex +++ b/lib/pleroma/user/query.ex @@ -109,7 +109,9 @@ defmodule Pleroma.User.Query do end defp compose_query({:tags, tags}, query) when is_list(tags) and length(tags) > 0 do - where(query, [u], fragment("? && ?", u.tags, ^tags)) + query + |> join(:inner, [u], t in assoc(u, :tags), as: :tags) + |> where([tags: t], t.name in ^tags) end defp compose_query({:is_admin, bool}, query) do diff --git a/lib/pleroma/web/activity_pub/mrf/tag_policy.ex b/lib/pleroma/web/activity_pub/mrf/tag_policy.ex index 316ea0368..dc445add2 100644 --- a/lib/pleroma/web/activity_pub/mrf/tag_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/tag_policy.ex @@ -32,7 +32,11 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do ] end - defp get_tags(%User{tags: tags}) when is_list(tags), do: tags + defp get_tags(%User{} = user) do + {:ok, tags} = Pleroma.Repo.get_assoc(user, :tags) + Enum.map(tags, & &1.name) + end + defp get_tags(_), do: [] defp process_tag( diff --git a/lib/pleroma/web/admin_api/views/account_view.ex b/lib/pleroma/web/admin_api/views/account_view.ex index e053a9b67..ac8c952d9 100644 --- a/lib/pleroma/web/admin_api/views/account_view.ex +++ b/lib/pleroma/web/admin_api/views/account_view.ex @@ -66,6 +66,7 @@ defmodule Pleroma.Web.AdminAPI.AccountView do avatar = User.avatar_url(user) |> MediaProxy.url() display_name = Pleroma.HTML.strip_tags(user.name || user.nickname) user = User.sanitize_html(user, FastSanitize.Sanitizer.StripTags) + {:ok, user_tags} = Pleroma.Repo.get_assoc(user, :tags) %{ "id" => user.id, @@ -76,7 +77,7 @@ defmodule Pleroma.Web.AdminAPI.AccountView do "is_active" => user.is_active, "local" => user.local, "roles" => roles(user), - "tags" => user.tags || [], + "tags" => Enum.map(user_tags, & &1.name), "is_confirmed" => user.is_confirmed, "is_approved" => user.is_approved, "url" => user.uri || user.ap_id, diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index ac25aefdd..7e5a5d732 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -233,6 +233,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do nil end + {:ok, user_tags} = Pleroma.Repo.get_assoc(user, :tags) + %{ id: to_string(user.id), username: username_from_nickname(user.nickname), @@ -269,7 +271,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do ap_id: user.ap_id, also_known_as: user.also_known_as, is_confirmed: user.is_confirmed, - tags: user.tags, + tags: Enum.map(user_tags, & &1.name), hide_followers_count: user.hide_followers_count, hide_follows_count: user.hide_follows_count, hide_followers: user.hide_followers, |