2024-03-21 13:37:10 +03:00
defmodule PlausibleWeb.GoogleAnalyticsController do
2024-03-12 20:08:25 +03:00
use PlausibleWeb , :controller
2024-03-28 11:32:41 +03:00
alias Plausible.Google
alias Plausible.Imported
require Plausible.Imported.SiteImport
2024-03-12 20:08:25 +03:00
plug ( PlausibleWeb.RequireAccountPlug )
plug ( PlausibleWeb.AuthorizeSiteAccess , [ :owner , :admin , :super_admin ] )
def user_metric_notice ( conn , %{
2024-03-21 13:37:10 +03:00
" property_or_view " = > property_or_view ,
2024-03-12 20:08:25 +03:00
" access_token " = > access_token ,
" refresh_token " = > refresh_token ,
" expires_at " = > expires_at ,
2024-03-28 11:32:41 +03:00
" start_date " = > start_date ,
" end_date " = > end_date ,
2024-03-12 20:08:25 +03:00
" legacy " = > legacy
} ) do
site = conn . assigns . site
conn
|> assign ( :skip_plausible_tracking , true )
|> render ( " user_metric_form.html " ,
site : site ,
2024-03-21 13:37:10 +03:00
property_or_view : property_or_view ,
2024-03-12 20:08:25 +03:00
access_token : access_token ,
refresh_token : refresh_token ,
expires_at : expires_at ,
2024-03-28 11:32:41 +03:00
start_date : start_date ,
end_date : end_date ,
2024-03-12 20:08:25 +03:00
legacy : legacy ,
layout : { PlausibleWeb.LayoutView , " focus.html " }
)
end
2024-03-28 11:32:41 +03:00
def property_or_view_form (
conn ,
%{
" access_token " = > access_token ,
" refresh_token " = > refresh_token ,
" expires_at " = > expires_at ,
" legacy " = > legacy
} = params
) do
2024-03-21 13:37:10 +03:00
site = conn . assigns . site
2024-03-12 20:08:25 +03:00
redirect_route =
if legacy == " true " do
2024-03-21 13:37:10 +03:00
Routes . site_path ( conn , :settings_integrations , site . domain )
else
Routes . site_path ( conn , :settings_imports_exports , site . domain )
end
result =
if legacy == " true " do
2024-03-28 11:32:41 +03:00
Google.UA.API . list_views ( access_token )
2024-03-12 20:08:25 +03:00
else
2024-03-28 11:32:41 +03:00
Google.API . list_properties_and_views ( access_token )
end
error =
case params [ " error " ] do
" no_data " ->
" No data found. Nothing to import. "
" no_time_window " ->
" Imported data time range is completely overlapping with existing data. Nothing to import. "
_ ->
nil
2024-03-12 20:08:25 +03:00
end
2024-03-21 13:37:10 +03:00
case result do
{ :ok , properties_and_views } ->
2024-03-12 20:08:25 +03:00
conn
|> assign ( :skip_plausible_tracking , true )
2024-03-21 13:37:10 +03:00
|> render ( " property_or_view_form.html " ,
2024-03-12 20:08:25 +03:00
access_token : access_token ,
refresh_token : refresh_token ,
expires_at : expires_at ,
site : conn . assigns . site ,
2024-03-21 13:37:10 +03:00
properties_and_views : properties_and_views ,
2024-03-28 11:32:41 +03:00
selected_property_or_view_error : error ,
2024-03-12 20:08:25 +03:00
legacy : legacy ,
layout : { PlausibleWeb.LayoutView , " focus.html " }
)
{ :error , :authentication_failed } ->
conn
|> put_flash (
:error ,
" We were unable to authenticate your Google Analytics account. Please check that you have granted us permission to 'See and download your Google Analytics data' and try again. "
)
|> redirect ( external : redirect_route )
2024-04-04 19:55:39 +03:00
{ :error , :timeout } ->
conn
|> put_flash (
:error ,
" Google Analytics API has timed out. Please try again. "
)
|> redirect ( external : redirect_route )
2024-03-12 20:08:25 +03:00
{ :error , _any } ->
conn
|> put_flash (
:error ,
2024-03-28 11:32:41 +03:00
" We were unable to list your Google Analytics properties and views. If the problem persists, please contact support for assistance. "
2024-03-12 20:08:25 +03:00
)
|> redirect ( external : redirect_route )
end
end
# see https://stackoverflow.com/a/57416769
2024-03-28 11:32:41 +03:00
@universal_analytics_new_user_metric_date ~D[ 2016-08-24 ]
2024-03-21 13:37:10 +03:00
2024-03-28 11:32:41 +03:00
def property_or_view (
conn ,
%{
" property_or_view " = > property_or_view ,
" access_token " = > access_token ,
" refresh_token " = > refresh_token ,
" expires_at " = > expires_at ,
" legacy " = > legacy
} = params
) do
2024-03-12 20:08:25 +03:00
site = conn . assigns . site
2024-03-28 11:32:41 +03:00
redirect_route =
if legacy == " true " do
Routes . site_path ( conn , :settings_integrations , site . domain )
else
Routes . site_path ( conn , :settings_imports_exports , site . domain )
end
with { :ok , api_start_date } <-
Google.API . get_analytics_start_date ( access_token , property_or_view ) ,
{ :ok , api_end_date } <- Google.API . get_analytics_end_date ( access_token , property_or_view ) ,
{ :ok , start_date , end_date } <- Imported . check_dates ( site , api_start_date , api_end_date ) do
action =
if Timex . before? ( api_start_date , @universal_analytics_new_user_metric_date ) do
:user_metric_notice
else
:confirm
end
redirect ( conn ,
external :
Routes . google_analytics_path ( conn , action , site . domain ,
property_or_view : property_or_view ,
access_token : access_token ,
refresh_token : refresh_token ,
expires_at : expires_at ,
start_date : Date . to_iso8601 ( start_date ) ,
end_date : Date . to_iso8601 ( end_date ) ,
legacy : legacy
)
)
else
{ :error , error } when error in [ :no_data , :no_time_window ] ->
params =
params
|> Map . take ( [ " access_token " , " refresh_token " , " expires_at " , " legacy " ] )
|> Map . put ( " error " , Atom . to_string ( error ) )
property_or_view_form ( conn , params )
2024-03-12 20:08:25 +03:00
2024-03-28 11:32:41 +03:00
{ :error , :authentication_failed } ->
2024-03-12 20:08:25 +03:00
conn
2024-03-28 11:32:41 +03:00
|> put_flash (
:error ,
" Google Analytics authentication seems to have expired. Please try again. "
2024-03-12 20:08:25 +03:00
)
2024-03-28 11:32:41 +03:00
|> redirect ( external : redirect_route )
2024-03-12 20:08:25 +03:00
2024-04-04 19:55:39 +03:00
{ :error , :timeout } ->
conn
|> put_flash (
:error ,
" Google Analytics API has timed out. Please try again. "
)
|> redirect ( external : redirect_route )
2024-03-28 11:32:41 +03:00
{ :error , _any } ->
conn
|> put_flash (
:error ,
" We were unable to retrieve information from Google Analytics. If the problem persists, please contact support for assistance. "
2024-03-21 13:37:10 +03:00
)
2024-03-28 11:32:41 +03:00
|> redirect ( external : redirect_route )
2024-03-12 20:08:25 +03:00
end
end
def confirm ( conn , %{
2024-03-21 13:37:10 +03:00
" property_or_view " = > property_or_view ,
2024-03-12 20:08:25 +03:00
" access_token " = > access_token ,
" refresh_token " = > refresh_token ,
" expires_at " = > expires_at ,
2024-03-28 11:32:41 +03:00
" start_date " = > start_date ,
" end_date " = > end_date ,
2024-03-12 20:08:25 +03:00
" legacy " = > legacy
} ) do
site = conn . assigns . site
2024-03-28 11:32:41 +03:00
start_date = Date . from_iso8601! ( start_date )
end_date = Date . from_iso8601! ( end_date )
redirect_route =
if legacy == " true " do
Routes . site_path ( conn , :settings_integrations , site . domain )
else
Routes . site_path ( conn , :settings_imports_exports , site . domain )
end
case Google.API . get_property_or_view ( access_token , property_or_view ) do
{ :ok , %{ name : property_or_view_name , id : property_or_view } } ->
conn
|> assign ( :skip_plausible_tracking , true )
|> render ( " confirm.html " ,
access_token : access_token ,
refresh_token : refresh_token ,
expires_at : expires_at ,
site : site ,
selected_property_or_view : property_or_view ,
selected_property_or_view_name : property_or_view_name ,
start_date : start_date ,
end_date : end_date ,
property? : Google.API . property? ( property_or_view ) ,
legacy : legacy ,
layout : { PlausibleWeb.LayoutView , " focus.html " }
)
2024-03-12 20:08:25 +03:00
2024-03-28 11:32:41 +03:00
{ :error , :authentication_failed } ->
conn
|> put_flash (
:error ,
" Google Analytics authentication seems to have expired. Please try again. "
)
|> redirect ( external : redirect_route )
2024-03-12 20:08:25 +03:00
2024-04-04 19:55:39 +03:00
{ :error , :timeout } ->
conn
|> put_flash (
:error ,
" Google Analytics API has timed out. Please try again. "
)
|> redirect ( external : redirect_route )
2024-03-28 11:32:41 +03:00
{ :error , :not_found } ->
conn
|> put_flash (
:error ,
" Google Analytics property not found. Please try again. "
)
|> redirect ( external : redirect_route )
2024-03-12 20:08:25 +03:00
2024-03-28 11:32:41 +03:00
{ :error , _any } ->
conn
|> put_flash (
:error ,
" We were unable to retrieve information from Google Analytics. If the problem persists, please contact support for assistance. "
)
|> redirect ( external : redirect_route )
end
2024-03-12 20:08:25 +03:00
end
def import ( conn , %{
2024-03-21 13:37:10 +03:00
" property_or_view " = > property_or_view ,
2024-03-12 20:08:25 +03:00
" start_date " = > start_date ,
" end_date " = > end_date ,
" access_token " = > access_token ,
" refresh_token " = > refresh_token ,
" expires_at " = > expires_at ,
" legacy " = > legacy
} ) do
site = conn . assigns . site
current_user = conn . assigns . current_user
2024-03-28 11:32:41 +03:00
start_date = Date . from_iso8601! ( start_date )
end_date = Date . from_iso8601! ( end_date )
2024-03-12 20:08:25 +03:00
redirect_route =
if legacy == " true " do
Routes . site_path ( conn , :settings_integrations , site . domain )
else
Routes . site_path ( conn , :settings_imports_exports , site . domain )
end
2024-03-28 11:32:41 +03:00
case Imported . check_dates ( site , start_date , end_date ) do
{ :ok , start_date , end_date } ->
if Google.API . property? ( property_or_view ) do
{ :ok , _ } =
Imported.GoogleAnalytics4 . new_import (
site ,
current_user ,
property : property_or_view ,
label : property_or_view ,
start_date : start_date ,
end_date : end_date ,
access_token : access_token ,
refresh_token : refresh_token ,
token_expires_at : expires_at
)
else
{ :ok , _ } =
Imported.UniversalAnalytics . new_import (
site ,
current_user ,
view_id : property_or_view ,
label : property_or_view ,
start_date : start_date ,
end_date : end_date ,
access_token : access_token ,
refresh_token : refresh_token ,
token_expires_at : expires_at ,
legacy : legacy == " true "
)
end
conn
|> put_flash ( :success , " Import scheduled. An email will be sent when it completes. " )
|> redirect ( external : redirect_route )
{ :error , :no_time_window } ->
conn
|> put_flash (
:error ,
" Import failed. No data could be imported because date range overlaps with existing data. "
2024-03-21 13:37:10 +03:00
)
2024-03-28 11:32:41 +03:00
|> redirect ( external : redirect_route )
2024-03-21 13:37:10 +03:00
end
2024-03-12 20:08:25 +03:00
end
end