Allow user to cancel ongoing import

This commit is contained in:
Uku Taht 2022-03-23 11:58:36 +02:00
parent 0f58d56c11
commit 51cd24bcaf
7 changed files with 115 additions and 9 deletions

View File

@ -307,8 +307,6 @@ defmodule Plausible.Google.Api do
{:ok, nil}
{:error, error} ->
Plausible.ClickhouseRepo.clear_imported_stats_for(site.domain)
Sentry.capture_message("Error saving Google analytics data", extra: error)
{:error, error["error"]["message"]}
end

View File

@ -23,6 +23,14 @@ defmodule Plausible.Stats.Clickhouse do
end
end
def imported_pageview_count(site) do
Plausible.ClickhouseRepo.one(
from i in "imported_visitors",
where: i.site_id == ^site.id,
select: sum(i.pageviews)
)
end
def usage_breakdown(domains) do
range =
Date.range(

View File

@ -170,12 +170,20 @@ defmodule PlausibleWeb.SiteController do
def settings_general(conn, _params) do
site =
conn.assigns[:site]
|> Repo.preload([:custom_domain, :google_auth])
|> Repo.preload([:custom_domain])
imported_pageviews =
if site.imported_data do
Plausible.Stats.Clickhouse.imported_pageview_count(site)
else
0
end
conn
|> assign(:skip_plausible_tracking, true)
|> render("settings_general.html",
site: site,
imported_pageviews: imported_pageviews,
changeset: Plausible.Site.changeset(site, %{}),
layout: {PlausibleWeb.LayoutView, "site_settings.html"}
)
@ -712,6 +720,14 @@ defmodule PlausibleWeb.SiteController do
cond do
site.imported_data ->
Oban.cancel_all_jobs(
from(j in Oban.Job,
where:
j.queue == "google_analytics_imports" and
fragment("(? ->> 'site_id')::int", j.args) == ^site.id
)
)
Plausible.Imported.forget(site)
site
@ -719,7 +735,7 @@ defmodule PlausibleWeb.SiteController do
|> Repo.update!()
conn
|> put_flash(:success, "Imported data has been forgotten")
|> put_flash(:success, "Imported data has been cleared")
|> redirect(to: Routes.site_path(conn, :settings_general, site.domain))
true ->

View File

@ -59,23 +59,36 @@
<%= if Keyword.get(Application.get_env(:plausible, :google), :client_id) do %>
<%= cond do %>
<% @site.imported_data && @site.imported_data.status == "importing" -> %>
<div class="py-2"></div>
<div class="text-sm">We are importing data from <%= @site.imported_data.source %> in the background... You will receive an email when it's completed</div>
<li class="py-4 flex items-center justify-between space-x-4">
<div class="flex flex-col">
<p class="text-sm leading-5 font-medium text-gray-900 dark:text-gray-100">
Import from <%= @site.imported_data.source %>
<svg class="animate-spin -mr-1 ml-1 h-4 w-4 inline text-indigo-600" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
</p>
<p class="text-sm leading-5 text-gray-500 dark:text-gray-200">
From <%= PlausibleWeb.EmailView.date_format(@site.imported_data.start_date) %> to <%= PlausibleWeb.EmailView.date_format(@site.imported_data.end_date) %>
</p>
</div>
<%= link("Cancel import", to: "/#{URI.encode_www_form(@site.domain)}/settings/forget-imported", method: :delete, class: "inline-block mt-4 px-4 py-2 border border-gray-300 dark:border-gray-500 text-sm leading-5 font-medium rounded-md text-red-700 bg-white dark:bg-gray-800 hover:text-red-500 dark:hover:text-red-400 focus:outline-none focus:border-blue-300 focus:ring active:text-red-800 active:bg-gray-50 transition ease-in-out duration-150") %>
</li>
<% @site.imported_data && @site.imported_data.status == "ok" -> %>
<li class="py-4 flex items-center justify-between space-x-4">
<div class="flex flex-col">
<p class="text-sm leading-5 font-medium text-gray-900 dark:text-gray-100">
Import from <%= @site.imported_data.source %>
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 inline -mt-1 text-green-600" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<svg class="h-4 w-4 inline ml-1 -mt-1 text-green-600" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
</svg>
</p>
<p class="text-sm leading-5 text-gray-500 dark:text-gray-200">
<%= PlausibleWeb.EmailView.date_format(@site.imported_data.start_date) %> - <%= PlausibleWeb.EmailView.date_format(@site.imported_data.end_date) %>
From <%= PlausibleWeb.EmailView.date_format(@site.imported_data.start_date) %> to <%= PlausibleWeb.EmailView.date_format(@site.imported_data.end_date) %>
</p>
</div>
<%= link("Clear imported stats", to: "/#{URI.encode_www_form(@site.domain)}/settings/forget-imported", method: :delete, class: "inline-block mt-4 px-4 py-2 border border-gray-300 dark:border-gray-500 text-sm leading-5 font-medium rounded-md text-red-700 bg-white dark:bg-gray-800 hover:text-red-500 dark:hover:text-red-400 focus:outline-none focus:border-blue-300 focus:ring active:text-red-800 active:bg-gray-50 transition ease-in-out duration-150") %>
<%= link("Clear " <> PlausibleWeb.StatsView.large_number_format(@imported_pageviews) <> " imported pageviews", to: "/#{URI.encode_www_form(@site.domain)}/settings/forget-imported", method: :delete, class: "inline-block mt-4 px-4 py-2 border border-gray-300 dark:border-gray-500 text-sm leading-5 font-medium rounded-md text-red-700 bg-white dark:bg-gray-800 hover:text-red-500 dark:hover:text-red-400 focus:outline-none focus:border-blue-300 focus:ring active:text-red-800 active:bg-gray-50 transition ease-in-out duration-150") %>
</li>
<% @site.imported_data && @site.imported_data.status == "error" -> %>

View File

@ -46,6 +46,7 @@ defmodule Plausible.Workers.ImportGoogleAnalytics do
site = Repo.preload(site, memberships: :user)
Plausible.Site.import_failure(site) |> Repo.update!()
Plausible.ClickhouseRepo.clear_imported_stats_for(site.id)
Enum.each(site.memberships, fn membership ->
if membership.role in [:owner, :admin] do

View File

@ -769,5 +769,41 @@ defmodule PlausibleWeb.SiteControllerTest do
assert Repo.reload(site).imported_data == nil
end
test "removes actual imported data from Clickhouse", %{conn: conn, site: site} do
Plausible.Site.start_import(site, ~D[2022-01-01], Timex.today(), "Google Analytics")
|> Repo.update!()
populate_stats(site, [
build(:imported_visitors, pageviews: 10)
])
delete(conn, "/#{site.domain}/settings/forget-imported")
assert Plausible.Stats.Clickhouse.imported_pageview_count(site) == 0
end
test "cancels Oban job if it exists", %{conn: conn, site: site} do
{:ok, job} =
Plausible.Workers.ImportGoogleAnalytics.new(%{
"site_id" => site.id,
"view_id" => "123",
"start_date" => "2022-01-01",
"end_date" => "2023-01-01",
"access_token" => "token"
})
|> Oban.insert()
Plausible.Site.start_import(site, ~D[2022-01-01], Timex.today(), "Google Analytics")
|> Repo.update!()
populate_stats(site, [
build(:imported_visitors, pageviews: 10)
])
delete(conn, "/#{site.domain}/settings/forget-imported")
assert Repo.reload(job).state == "cancelled"
end
end
end

View File

@ -2,6 +2,7 @@ defmodule Plausible.Workers.ImportGoogleAnalyticsTest do
use Plausible.DataCase
use Bamboo.Test
import Double
import Plausible.TestUtils
alias Plausible.Workers.ImportGoogleAnalytics
@imported_data %Plausible.Site.ImportedData{
@ -100,6 +101,39 @@ defmodule Plausible.Workers.ImportGoogleAnalyticsTest do
assert Repo.reload!(site).imported_data.status == "error"
end
test "clears any orphaned data during impot" do
user = insert(:user, trial_expiry_date: Timex.today() |> Timex.shift(days: 1))
site = insert(:site, members: [user], imported_data: @imported_data)
populate_stats(site, [
build(:imported_visitors, pageviews: 10)
])
api_stub =
stub(Plausible.Google.Api, :import_analytics, fn _site,
_view_id,
_start_date,
_end_date,
_access_token ->
{:error, "Something went wrong"}
end)
ImportGoogleAnalytics.perform(
%Oban.Job{
args: %{
"site_id" => site.id,
"view_id" => "view_id",
"start_date" => "2020-01-01",
"end_date" => "2022-01-01",
"access_token" => "token"
}
},
api_stub
)
assert Plausible.Stats.Clickhouse.imported_pageview_count(site) == 0
end
test "sends email to owner after failed import" do
user = insert(:user, trial_expiry_date: Timex.today() |> Timex.shift(days: 1))
site = insert(:site, members: [user], imported_data: @imported_data)