add inbound language test
[akkoma] / 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 params = validate_params(struct, params)
28
29 struct
30 |> cast(params, [:data, :starts_at, :ends_at, :rendered])
31 |> validate_required([:data])
32 end
33
34 defp validate_params(struct, params) do
35 base_data =
36 %{
37 "content" => "",
38 "all_day" => false
39 }
40 |> Map.merge((struct && struct.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 = change(%__MODULE__{}, params)
67
68 Repo.insert(changeset)
69 end
70
71 def update(announcement, params) do
72 changeset = change(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