total rebase
[anni] / lib / pleroma / announcement.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Announcement do
6   use Ecto.Schema
7
8   import Ecto.Changeset, only: [cast: 3, validate_required: 2]
9   import Ecto.Query
10
11   alias Pleroma.AnnouncementReadRelationship
12   alias Pleroma.Repo
13
14   @type t :: %__MODULE__{}
15   @primary_key {:id, FlakeId.Ecto.CompatType, autogenerate: true}
16
17   schema "announcements" do
18     field(:data, :map)
19     field(:starts_at, :utc_datetime)
20     field(:ends_at, :utc_datetime)
21     field(:rendered, :map)
22
23     timestamps(type: :utc_datetime)
24   end
25
26   @doc "Generates changeset for %Pleroma.Announcement{}"
27   @spec changeset(%__MODULE__{}, map()) :: %Ecto.Changeset{}
28   def changeset(announcement \\ %__MODULE__{}, params \\ %{data: %{}}) do
29     announcement
30     |> cast(validate_params(announcement, params), [:data, :starts_at, :ends_at, :rendered])
31     |> validate_required([:data])
32   end
33
34   defp validate_params(announcement, params) do
35     base_data =
36       %{
37         "content" => "",
38         "all_day" => false
39       }
40       |> Map.merge((announcement && announcement.data) || %{})
41
42     merged_data =
43       Map.merge(base_data, params.data)
44       |> Map.take(["content", "all_day"])
45
46     params
47     |> Map.merge(%{data: merged_data})
48     |> add_rendered_properties()
49   end
50
51   def add_rendered_properties(params) do
52     {content_html, _, _} =
53       Pleroma.Web.CommonAPI.Utils.format_input(params.data["content"], "text/plain",
54         mentions_format: :full
55       )
56
57     rendered = %{
58       "content" => content_html
59     }
60
61     params
62     |> Map.put(:rendered, rendered)
63   end
64
65   def add(params) do
66     changeset = changeset(%__MODULE__{}, params)
67
68     Repo.insert(changeset)
69   end
70
71   def update(announcement, params) do
72     changeset = changeset(announcement, params)
73
74     Repo.update(changeset)
75   end
76
77   def list_all do
78     __MODULE__
79     |> Repo.all()
80   end
81
82   def list_paginated(%{limit: limited_number, offset: offset_number}) do
83     __MODULE__
84     |> limit(^limited_number)
85     |> offset(^offset_number)
86     |> Repo.all()
87   end
88
89   def get_by_id(id) do
90     Repo.get_by(__MODULE__, id: id)
91   end
92
93   def delete_by_id(id) do
94     with announcement when not is_nil(announcement) <- get_by_id(id),
95          {:ok, _} <- Repo.delete(announcement) do
96       :ok
97     else
98       _ ->
99         :error
100     end
101   end
102
103   def read_by?(announcement, user) do
104     AnnouncementReadRelationship.exists?(user, announcement)
105   end
106
107   def mark_read_by(announcement, user) do
108     AnnouncementReadRelationship.mark_read(user, announcement)
109   end
110
111   def render_json(announcement, opts \\ []) do
112     extra_params =
113       case Keyword.fetch(opts, :for) do
114         {:ok, user} when not is_nil(user) ->
115           %{read: read_by?(announcement, user)}
116
117         _ ->
118           %{}
119       end
120
121     admin_extra_params =
122       case Keyword.fetch(opts, :admin) do
123         {:ok, true} ->
124           %{pleroma: %{raw_content: announcement.data["content"]}}
125
126         _ ->
127           %{}
128       end
129
130     base = %{
131       id: announcement.id,
132       content: announcement.rendered["content"],
133       starts_at: announcement.starts_at,
134       ends_at: announcement.ends_at,
135       all_day: announcement.data["all_day"],
136       published_at: announcement.inserted_at,
137       updated_at: announcement.updated_at,
138       mentions: [],
139       statuses: [],
140       tags: [],
141       emojis: [],
142       reactions: []
143     }
144
145     base
146     |> Map.merge(extra_params)
147     |> Map.merge(admin_extra_params)
148   end
149
150   # "visible" means:
151   # starts_at < time < ends_at
152   def list_all_visible_when(time) do
153     __MODULE__
154     |> where([a], is_nil(a.starts_at) or a.starts_at < ^time)
155     |> where([a], is_nil(a.ends_at) or a.ends_at > ^time)
156     |> Repo.all()
157   end
158
159   def list_all_visible do
160     list_all_visible_when(DateTime.now("Etc/UTC") |> elem(1))
161   end
162 end