First
[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   def change(struct, params \\ %{}) do
27     struct
28     |> cast(validate_params(struct, params), [:data, :starts_at, :ends_at, :rendered])
29     |> validate_required([:data])
30   end
31
32   defp validate_params(struct, params) do
33     base_data =
34       %{
35         "content" => "",
36         "all_day" => false
37       }
38       |> Map.merge((struct && struct.data) || %{})
39
40     merged_data =
41       Map.merge(base_data, params.data)
42       |> Map.take(["content", "all_day"])
43
44     params
45     |> Map.merge(%{data: merged_data})
46     |> add_rendered_properties()
47   end
48
49   def add_rendered_properties(params) do
50     {content_html, _, _} =
51       Pleroma.Web.CommonAPI.Utils.format_input(params.data["content"], "text/plain",
52         mentions_format: :full
53       )
54
55     rendered = %{
56       "content" => content_html
57     }
58
59     params
60     |> Map.put(:rendered, rendered)
61   end
62
63   def add(params) do
64     changeset = change(%__MODULE__{}, params)
65
66     Repo.insert(changeset)
67   end
68
69   def update(announcement, params) do
70     changeset = change(announcement, params)
71
72     Repo.update(changeset)
73   end
74
75   def list_all do
76     __MODULE__
77     |> Repo.all()
78   end
79
80   def list_paginated(%{limit: limited_number, offset: offset_number}) do
81     __MODULE__
82     |> limit(^limited_number)
83     |> offset(^offset_number)
84     |> Repo.all()
85   end
86
87   def get_by_id(id) do
88     Repo.get_by(__MODULE__, id: id)
89   end
90
91   def delete_by_id(id) do
92     with announcement when not is_nil(announcement) <- get_by_id(id),
93          {:ok, _} <- Repo.delete(announcement) do
94       :ok
95     else
96       _ ->
97         :error
98     end
99   end
100
101   def read_by?(announcement, user) do
102     AnnouncementReadRelationship.exists?(user, announcement)
103   end
104
105   def mark_read_by(announcement, user) do
106     AnnouncementReadRelationship.mark_read(user, announcement)
107   end
108
109   def render_json(announcement, opts \\ []) do
110     extra_params =
111       case Keyword.fetch(opts, :for) do
112         {:ok, user} when not is_nil(user) ->
113           %{read: read_by?(announcement, user)}
114
115         _ ->
116           %{}
117       end
118
119     admin_extra_params =
120       case Keyword.fetch(opts, :admin) do
121         {:ok, true} ->
122           %{pleroma: %{raw_content: announcement.data["content"]}}
123
124         _ ->
125           %{}
126       end
127
128     base = %{
129       id: announcement.id,
130       content: announcement.rendered["content"],
131       starts_at: announcement.starts_at,
132       ends_at: announcement.ends_at,
133       all_day: announcement.data["all_day"],
134       published_at: announcement.inserted_at,
135       updated_at: announcement.updated_at,
136       mentions: [],
137       statuses: [],
138       tags: [],
139       emojis: [],
140       reactions: []
141     }
142
143     base
144     |> Map.merge(extra_params)
145     |> Map.merge(admin_extra_params)
146   end
147
148   # "visible" means:
149   # starts_at < time < ends_at
150   def list_all_visible_when(time) do
151     __MODULE__
152     |> where([a], is_nil(a.starts_at) or a.starts_at < ^time)
153     |> where([a], is_nil(a.ends_at) or a.ends_at > ^time)
154     |> Repo.all()
155   end
156
157   def list_all_visible do
158     list_all_visible_when(DateTime.now("Etc/UTC") |> elem(1))
159   end
160 end