Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update goal in segment #5027

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions lib/plausible/goals/goals.ex
Original file line number Diff line number Diff line change
Expand Up @@ -56,16 +56,20 @@ defmodule Plausible.Goals do
{:ok, Goal.t()} | {:error, Ecto.Changeset.t()} | {:error, :upgrade_required}
def update(goal, params) do
changeset = Goal.changeset(goal, params)
site = Repo.preload(goal, :site).site

with :ok <- maybe_check_feature_access(site, changeset),
{:ok, goal} <- Repo.update(changeset) do
on_ee do
{:ok, Repo.preload(goal, :funnels)}
else
{:ok, goal}
Repo.transaction(fn ->
ukutaht marked this conversation as resolved.
Show resolved Hide resolved
site = Repo.preload(goal, :site).site

with :ok <- maybe_check_feature_access(site, changeset),
{:ok, updated_goal} <- Repo.update(changeset),
:ok <- Plausible.Segments.update_goal_in_segments(site, goal, updated_goal) do
on_ee do
{:ok, Repo.preload(updated_goal, :funnels)}
else
{:ok, updated_goal}
end
end
end
end)
end

def find_or_create(
Expand Down
44 changes: 44 additions & 0 deletions lib/plausible/segments/segments.ex
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,50 @@ defmodule Plausible.Segments do
end
end

def update_goal_in_segments(
%Plausible.Site{} = site,
%Plausible.Goal{} = stale_goal,
%Plausible.Goal{} = updated_goal
) do
goal_filter_regex =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This requires inline commentary so the reader won't have to wonder what are we trying to achieve here

~s(.*?\\["is",\s*"event:goal",\s*\\[.*?"#{Regex.escape(stale_goal.display_name)}".*?\\]\\].*?)
apata marked this conversation as resolved.
Show resolved Hide resolved

IO.inspect(stale_goal)
apata marked this conversation as resolved.
Show resolved Hide resolved
ukutaht marked this conversation as resolved.
Show resolved Hide resolved

segments_to_update =
from(
s in Segment,
where: s.site_id == ^site.id,
where: fragment("?['filters']::text ~ ?", s.segment_data, ^goal_filter_regex)
)

stale_goal_name = stale_goal.display_name

for segment <- Repo.all(segments_to_update) do
updated_filters =
Plausible.Stats.Filters.transform_filters(segment.segment_data["filters"], fn
["is", "event:goal", clauses] ->
new_clauses =
Enum.map(clauses, fn
^stale_goal_name -> updated_goal.display_name
clause -> clause
end)

[["is", "event:goal", new_clauses]]

_ ->
nil
end)

updated_segment_data = Map.put(segment.segment_data, "filters", updated_filters)

Segment.changeset(segment, %{segment_data: updated_segment_data})
|> Repo.update!()
end

:ok
end

def delete_one(user_id, %Plausible.Site{} = site, site_role, segment_id) do
with {:ok, segment} <- get_one(user_id, site, site_role, segment_id) do
cond do
Expand Down
31 changes: 31 additions & 0 deletions test/plausible/goals_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@
assert [currency: {"is invalid", _}] = changeset.errors
end

test "update/2 updates a goal" do

Check failure on line 111 in test/plausible/goals_test.exs

View workflow job for this annotation

GitHub Actions / Build and test (ce_test, postgres:16)

test update/2 updates a goal (Plausible.GoalsTest)
site = new_site()
{:ok, goal1} = Goals.create(site, %{"page_path" => "/foo bar "})
{:ok, goal2} = Goals.update(goal1, %{"page_path" => "/", "display_name" => "Homepage"})
Expand All @@ -117,6 +117,37 @@
assert goal2.display_name == "Homepage"
end

test "update/2 also updates any segments the goal is a part of" do
ukutaht marked this conversation as resolved.
Show resolved Hide resolved
user = new_user()
site = new_site(owner: user)
{:ok, goal1} = Goals.create(site, %{"event_name" => "Signup"})
{:ok, _goal2} = Goals.create(site, %{"event_name" => "Signup from nav"})

{:ok, segment} =
Plausible.Segments.insert_one(user.id, site, :editor, %{
"type" => "site",
"segment_data" => %{
"filters" => [
["is", "event:page", ["/blog"]],
["is", "event:goal", ["Signup from nav", "Signup"]],
["is", "event:props:variant", ["A"]]
]
},
"name" => "Segment name"
})
ukutaht marked this conversation as resolved.
Show resolved Hide resolved

Goals.update(goal1, %{"display_name" => "SIGNUP"})
updated_segment = Repo.reload!(segment)

assert updated_segment.segment_data == %{
"filters" => [
["is", "event:page", ["/blog"]],
["is", "event:goal", ["Signup from nav", "SIGNUP"]],
["is", "event:props:variant", ["A"]]
]
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: Noticed that we also override segment updated_at.

If that's intentional, it would be good to assert it here as well, with something like segment.updated_at < updated_segment.updated_at.

Alternatively, we may want to not override updated_at on these automatic updates. May be confusing when the message in the UI (Last updated at <stamp> by <name>) doesn't match with their usual online time.

Or we could also just rephrase it in the UI: Last updated at <stamp>, belongs to <name> or similar.

end

@tag :ee_only
test "list_revenue_goals/1 lists event_names and currencies for each revenue goal" do
site = new_site()
Expand Down
Loading