Skip to content

Commit 5df53eb

Browse files
zoldarapata
authored andcommitted
Replace ad-hoc plug with checks on Annotations API level and clean up API
1 parent e8eb66f commit 5df53eb

2 files changed

Lines changed: 82 additions & 59 deletions

File tree

lib/plausible/annotations/annotations.ex

Lines changed: 82 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,17 @@ defmodule Plausible.Annotations do
1818

1919
@max_annotations 500
2020

21+
@spec roles_with_personal_annotations() :: [atom()]
22+
def roles_with_personal_annotations(), do: @roles_with_personal_annotations
23+
24+
@spec roles_with_maybe_site_annotations() :: [atom()]
25+
def roles_with_maybe_site_annotations(), do: @roles_with_maybe_site_annotations
26+
27+
@spec site_annotations_available?(Plausible.Site.t()) :: boolean()
28+
def site_annotations_available?(site),
29+
# this feature is bundled with SiteSegments
30+
do: Plausible.Billing.Feature.SiteSegments.check_availability(site.team) == :ok
31+
2132
@spec get_all_for_site(Plausible.Site.t(), atom(), User.t() | nil, DateTimeRange.t()) ::
2233
{:error, error_not_enough_permissions()} | {:ok, list(Annotation.t())}
2334
def get_all_for_site(site, site_role, user, range_in_site_tz) do
@@ -67,36 +78,13 @@ defmodule Plausible.Annotations do
6778
end
6879
end
6980

70-
defp filter_by_range(query, range_in_site_tz) do
71-
# Minute granularity annotations are stored for the particular UTC moment they're for,
72-
# so they must be in the range of the UTC query period.
73-
minute_granularity_range =
74-
range_in_site_tz |> DateTimeRange.to_timezone("Etc/UTC")
75-
76-
# Date granularity annotations are stored for the UTC midnight of the date they're for,
77-
# so the range for querying these must reflect that.
78-
[date_granularity_range_first, date_granularity_range_last] =
79-
[range_in_site_tz.first, range_in_site_tz.last]
80-
|> Enum.map(fn utc_datetime ->
81-
utc_datetime |> DateTime.to_date() |> Annotation.serialize_date_granularity_datetime()
82-
end)
83-
84-
from(annotation in query,
85-
where:
86-
(annotation.granularity == :minute and
87-
annotation.datetime >= ^minute_granularity_range.first and
88-
annotation.datetime <= ^minute_granularity_range.last) or
89-
(annotation.granularity == :date and
90-
annotation.datetime >=
91-
^date_granularity_range_first and
92-
annotation.datetime <=
93-
^date_granularity_range_last)
94-
)
95-
end
96-
97-
@spec get_one(User.t(), Plausible.Site.t(), atom(), pos_integer() | nil) ::
81+
@spec get_one(User.t() | nil, Plausible.Site.t(), atom(), pos_integer() | nil) ::
9882
{:ok, Annotation.t()}
9983
| {:error, error_not_enough_permissions() | error_annotation_not_found()}
84+
def get_one(nil, _site, _site_role, _annotation_id) do
85+
{:error, :not_enough_permissions}
86+
end
87+
10088
def get_one(user, site, site_role, annotation_id) do
10189
if site_role in roles_with_personal_annotations() do
10290
case do_get_one(user, site, annotation_id) do
@@ -108,12 +96,16 @@ defmodule Plausible.Annotations do
10896
end
10997
end
11098

111-
@spec insert_one(User.t(), Plausible.Site.t(), atom(), map()) ::
99+
@spec insert_one(User.t() | nil, Plausible.Site.t(), atom(), map()) ::
112100
{:ok, Annotation.t()}
113101
| {:error,
114102
error_not_enough_permissions()
115103
| error_invalid_annotation()
116104
| error_annotation_limit_reached()}
105+
def insert_one(nil, _site, _site_role, _params) do
106+
{:error, :not_enough_permissions}
107+
end
108+
117109
def insert_one(user, site, site_role, params) do
118110
changeset = Annotation.create_changeset(params, site, user)
119111
annotation_type = Ecto.Changeset.get_field(changeset, :type)
@@ -130,12 +122,16 @@ defmodule Plausible.Annotations do
130122
end
131123
end
132124

133-
@spec update_one(User.t(), Plausible.Site.t(), atom(), pos_integer(), map()) ::
125+
@spec update_one(User.t() | nil, Plausible.Site.t(), atom(), pos_integer(), map()) ::
134126
{:ok, Annotation.t()}
135127
| {:error,
136128
error_not_enough_permissions()
137129
| error_invalid_annotation()
138130
| error_annotation_not_found()}
131+
def update_one(nil, _site, _site_role, _annotation_id, _params) do
132+
{:error, :not_enough_permissions}
133+
end
134+
139135
def update_one(user, site, site_role, annotation_id, params) do
140136
with {:ok, annotation} <- get_one(user, site, site_role, annotation_id),
141137
changeset = Annotation.update_changeset(annotation, params, user),
@@ -152,6 +148,31 @@ defmodule Plausible.Annotations do
152148
end
153149
end
154150

151+
@spec delete_one(User.t() | nil, Plausible.Site.t(), atom(), pos_integer()) ::
152+
{:ok, Annotation.t()}
153+
| {:error,
154+
error_not_enough_permissions()
155+
| error_annotation_not_found()}
156+
def delete_one(nil, _site, _site_role, _annotation_id) do
157+
{:error, :not_enough_permissions}
158+
end
159+
160+
def delete_one(user, site, site_role, annotation_id) do
161+
with {:ok, annotation} <- get_one(user, site, site_role, annotation_id) do
162+
cond do
163+
annotation.type == :site and site_role in roles_with_maybe_site_annotations() ->
164+
{:ok, do_delete_one(annotation)}
165+
166+
annotation.type == :personal and site_role in roles_with_personal_annotations() ->
167+
{:ok, do_delete_one(annotation)}
168+
169+
true ->
170+
{:error, :not_enough_permissions}
171+
end
172+
end
173+
end
174+
175+
@spec after_user_removed_from_site(Plausible.Site.t(), User.t()) :: :ok
155176
def after_user_removed_from_site(site, user) do
156177
Repo.delete_all(
157178
from(annotation in Annotation,
@@ -170,8 +191,11 @@ defmodule Plausible.Annotations do
170191
),
171192
[]
172193
)
194+
195+
:ok
173196
end
174197

198+
@spec after_user_removed_from_team(Plausible.Teams.Team.t(), User.t()) :: :ok
175199
def after_user_removed_from_team(team, user) do
176200
team_sites_q =
177201
from(
@@ -199,8 +223,11 @@ defmodule Plausible.Annotations do
199223
),
200224
[]
201225
)
226+
227+
:ok
202228
end
203229

230+
@spec user_removed(User.t()) :: :ok
204231
def user_removed(user) do
205232
Repo.delete_all(
206233
from(annotation in Annotation,
@@ -211,24 +238,37 @@ defmodule Plausible.Annotations do
211238
)
212239

213240
# Site annotations are set to owner=null via ON DELETE SET NULL
241+
242+
:ok
214243
end
215244

216-
def delete_one(user, %Plausible.Site{} = site, site_role, annotation_id) do
217-
with {:ok, annotation} <- get_one(user, site, site_role, annotation_id) do
218-
cond do
219-
annotation.type == :site and site_role in roles_with_maybe_site_annotations() ->
220-
{:ok, do_delete_one(annotation)}
245+
defp filter_by_range(query, range_in_site_tz) do
246+
# Minute granularity annotations are stored for the particular UTC moment they're for,
247+
# so they must be in the range of the UTC query period.
248+
minute_granularity_range =
249+
range_in_site_tz |> DateTimeRange.to_timezone("Etc/UTC")
221250

222-
annotation.type == :personal and site_role in roles_with_personal_annotations() ->
223-
{:ok, do_delete_one(annotation)}
251+
# Date granularity annotations are stored for the UTC midnight of the date they're for,
252+
# so the range for querying these must reflect that.
253+
[date_granularity_range_first, date_granularity_range_last] =
254+
[range_in_site_tz.first, range_in_site_tz.last]
255+
|> Enum.map(fn utc_datetime ->
256+
utc_datetime |> DateTime.to_date() |> Annotation.serialize_date_granularity_datetime()
257+
end)
224258

225-
true ->
226-
{:error, :not_enough_permissions}
227-
end
228-
end
259+
from(annotation in query,
260+
where:
261+
(annotation.granularity == :minute and
262+
annotation.datetime >= ^minute_granularity_range.first and
263+
annotation.datetime <= ^minute_granularity_range.last) or
264+
(annotation.granularity == :date and
265+
annotation.datetime >=
266+
^date_granularity_range_first and
267+
annotation.datetime <=
268+
^date_granularity_range_last)
269+
)
229270
end
230271

231-
@spec do_get_one(User.t(), Plausible.Site.t(), pos_integer() | nil) :: Annotation.t() | nil
232272
defp do_get_one(user, site, annotation_id)
233273

234274
defp do_get_one(_user, _site, nil) do
@@ -297,11 +337,4 @@ defmodule Plausible.Annotations do
297337
)
298338
|> Repo.aggregate(:count, :id)
299339
end
300-
301-
def roles_with_personal_annotations(), do: @roles_with_personal_annotations
302-
def roles_with_maybe_site_annotations(), do: @roles_with_maybe_site_annotations
303-
304-
def site_annotations_available?(%Plausible.Site{} = site),
305-
# this feature is bundled with SiteSegments
306-
do: Plausible.Billing.Feature.SiteSegments.check_availability(site.team) == :ok
307340
end

lib/plausible_web/controllers/api/internal/annotations_controller.ex

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ defmodule PlausibleWeb.Api.Internal.AnnotationsController do
1010
alias Plausible.Stats.{ApiQueryParser, QueryPeriod}
1111
alias PlausibleWeb.Api.Helpers, as: H
1212

13-
plug :require_user when action not in [:index]
14-
1513
def index(conn, params) do
1614
user = conn.assigns.current_user
1715
site = conn.assigns.site
@@ -146,12 +144,4 @@ defmodule PlausibleWeb.Api.Internal.AnnotationsController do
146144
defp annotation_not_found(%Plug.Conn{} = conn, annotation_id_param) do
147145
H.not_found(conn, "Annotation not found with ID #{inspect(annotation_id_param)}")
148146
end
149-
150-
defp require_user(conn, _opts) do
151-
if conn.assigns.current_user do
152-
conn
153-
else
154-
H.bad_request(conn, "Invalid request")
155-
end
156-
end
157147
end

0 commit comments

Comments
 (0)