aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/pleroma/hashtag.ex58
-rw-r--r--lib/pleroma/object.ex37
2 files changed, 85 insertions, 10 deletions
diff --git a/lib/pleroma/hashtag.ex b/lib/pleroma/hashtag.ex
new file mode 100644
index 000000000..b05927563
--- /dev/null
+++ b/lib/pleroma/hashtag.ex
@@ -0,0 +1,58 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Hashtag do
+ use Ecto.Schema
+
+ import Ecto.Changeset
+
+ alias Pleroma.Hashtag
+ alias Pleroma.Repo
+
+ @derive {Jason.Encoder, only: [:data]}
+
+ schema "hashtags" do
+ field(:name, :string)
+ field(:data, :map, default: %{})
+
+ many_to_many(:objects, Pleroma.Object, join_through: "hashtags_objects", on_replace: :delete)
+
+ timestamps()
+ end
+
+ def get_by_name(name) do
+ Repo.get_by(Hashtag, name: name)
+ end
+
+ def get_or_create_by_name(name) when is_bitstring(name) do
+ with %Hashtag{} = hashtag <- get_by_name(name) do
+ {:ok, hashtag}
+ else
+ _ ->
+ %Hashtag{}
+ |> changeset(%{name: name})
+ |> Repo.insert()
+ end
+ end
+
+ def get_or_create_by_names(names) when is_list(names) do
+ Enum.reduce_while(names, {:ok, []}, fn name, {:ok, list} ->
+ case get_or_create_by_name(name) do
+ {:ok, %Hashtag{} = hashtag} ->
+ {:cont, {:ok, list ++ [hashtag]}}
+
+ error ->
+ {:halt, error}
+ end
+ end)
+ end
+
+ def changeset(%Hashtag{} = struct, params) do
+ struct
+ |> cast(params, [:name, :data])
+ |> update_change(:name, &String.downcase/1)
+ |> validate_required([:name])
+ |> unique_constraint(:name)
+ end
+end
diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex
index 2088c7656..357a3b504 100644
--- a/lib/pleroma/object.ex
+++ b/lib/pleroma/object.ex
@@ -10,6 +10,7 @@ defmodule Pleroma.Object do
alias Pleroma.Activity
alias Pleroma.Config
+ alias Pleroma.Hashtag
alias Pleroma.Object
alias Pleroma.Object.Fetcher
alias Pleroma.ObjectTombstone
@@ -26,6 +27,8 @@ defmodule Pleroma.Object do
schema "objects" do
field(:data, :map)
+ many_to_many(:hashtags, Hashtag, join_through: "hashtags_objects", on_replace: :delete)
+
timestamps()
end
@@ -53,17 +56,31 @@ defmodule Pleroma.Object do
end
def change(struct, params \\ %{}) do
- changeset =
- struct
- |> cast(params, [:data])
- |> validate_required([:data])
- |> unique_constraint(:ap_id, name: :objects_unique_apid_index)
-
- if hashtags_changed?(struct, get_change(changeset, :data)) do
- # TODO: modify assoc once it's introduced
- changeset
+ struct
+ |> cast(params, [:data])
+ |> validate_required([:data])
+ |> unique_constraint(:ap_id, name: :objects_unique_apid_index)
+ |> maybe_handle_hashtags_change(struct)
+ end
+
+ defp maybe_handle_hashtags_change(changeset, struct) do
+ with data_hashtags_change = get_change(changeset, :data),
+ true <- hashtags_changed?(struct, data_hashtags_change),
+ {:ok, hashtag_records} <-
+ data_hashtags_change
+ |> object_data_hashtags()
+ |> Hashtag.get_or_create_by_names() do
+ put_assoc(changeset, :hashtags, hashtag_records)
else
- changeset
+ false ->
+ changeset
+
+ {:error, hashtag_changeset} ->
+ failed_hashtag = get_field(hashtag_changeset, :name)
+
+ validate_change(changeset, :data, fn _, _ ->
+ [data: "error referencing hashtag: #{failed_hashtag}"]
+ end)
end
end