total rebase
[anni] / lib / pleroma / bookmark_folder.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2024 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.BookmarkFolder do
6   use Ecto.Schema
7
8   import Ecto.Changeset
9   import Ecto.Query
10
11   alias Pleroma.BookmarkFolder
12   alias Pleroma.Emoji
13   alias Pleroma.Repo
14   alias Pleroma.User
15
16   @type t :: %__MODULE__{}
17   @primary_key {:id, FlakeId.Ecto.CompatType, autogenerate: true}
18
19   schema "bookmark_folders" do
20     field(:name, :string)
21     field(:emoji, :string)
22
23     belongs_to(:user, User, type: FlakeId.Ecto.CompatType)
24
25     timestamps()
26   end
27
28   def get_by_id(id), do: Repo.get_by(BookmarkFolder, id: id)
29
30   def create(user_id, name, emoji \\ nil) do
31     %BookmarkFolder{}
32     |> cast(
33       %{
34         user_id: user_id,
35         name: name,
36         emoji: emoji
37       },
38       [:user_id, :name, :emoji]
39     )
40     |> validate_required([:user_id, :name])
41     |> fix_emoji()
42     |> validate_emoji()
43     |> unique_constraint([:user_id, :name])
44     |> Repo.insert()
45   end
46
47   def update(folder_id, name, emoji \\ nil) do
48     get_by_id(folder_id)
49     |> cast(
50       %{
51         name: name,
52         emoji: emoji
53       },
54       [:name, :emoji]
55     )
56     |> fix_emoji()
57     |> validate_emoji()
58     |> unique_constraint([:user_id, :name])
59     |> Repo.update()
60   end
61
62   defp fix_emoji(changeset) do
63     with {:emoji_field, emoji} when is_binary(emoji) <-
64            {:emoji_field, get_field(changeset, :emoji)},
65          {:fixed_emoji, emoji} <-
66            {:fixed_emoji,
67             emoji
68             |> Pleroma.Emoji.fully_qualify_emoji()
69             |> Pleroma.Emoji.maybe_quote()} do
70       put_change(changeset, :emoji, emoji)
71     else
72       {:emoji_field, _} -> changeset
73     end
74   end
75
76   defp validate_emoji(changeset) do
77     validate_change(changeset, :emoji, fn
78       :emoji, nil ->
79         []
80
81       :emoji, emoji ->
82         if Emoji.unicode?(emoji) or valid_local_custom_emoji?(emoji) do
83           []
84         else
85           [emoji: "Invalid emoji"]
86         end
87     end)
88   end
89
90   defp valid_local_custom_emoji?(emoji) do
91     with %{file: _path} <- Emoji.get(emoji) do
92       true
93     else
94       _ -> false
95     end
96   end
97
98   def delete(folder_id) do
99     BookmarkFolder
100     |> Repo.get_by(id: folder_id)
101     |> Repo.delete()
102   end
103
104   def for_user(user_id) do
105     BookmarkFolder
106     |> where(user_id: ^user_id)
107     |> Repo.all()
108   end
109
110   def belongs_to_user?(folder_id, user_id) do
111     BookmarkFolder
112     |> where(id: ^folder_id, user_id: ^user_id)
113     |> Repo.exists?()
114   end
115 end