Added Hashtag entity and objects-hashtags association with auto-sync with `data.tag...
[akkoma] / lib / pleroma / hashtag.ex
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
5 defmodule Pleroma.Hashtag do
6 use Ecto.Schema
7
8 import Ecto.Changeset
9
10 alias Pleroma.Hashtag
11 alias Pleroma.Repo
12
13 @derive {Jason.Encoder, only: [:data]}
14
15 schema "hashtags" do
16 field(:name, :string)
17 field(:data, :map, default: %{})
18
19 many_to_many(:objects, Pleroma.Object, join_through: "hashtags_objects", on_replace: :delete)
20
21 timestamps()
22 end
23
24 def get_by_name(name) do
25 Repo.get_by(Hashtag, name: name)
26 end
27
28 def get_or_create_by_name(name) when is_bitstring(name) do
29 with %Hashtag{} = hashtag <- get_by_name(name) do
30 {:ok, hashtag}
31 else
32 _ ->
33 %Hashtag{}
34 |> changeset(%{name: name})
35 |> Repo.insert()
36 end
37 end
38
39 def get_or_create_by_names(names) when is_list(names) do
40 Enum.reduce_while(names, {:ok, []}, fn name, {:ok, list} ->
41 case get_or_create_by_name(name) do
42 {:ok, %Hashtag{} = hashtag} ->
43 {:cont, {:ok, list ++ [hashtag]}}
44
45 error ->
46 {:halt, error}
47 end
48 end)
49 end
50
51 def changeset(%Hashtag{} = struct, params) do
52 struct
53 |> cast(params, [:name, :data])
54 |> update_change(:name, &String.downcase/1)
55 |> validate_required([:name])
56 |> unique_constraint(:name)
57 end
58 end