github.com/wtfutil/wtf@v0.43.0/modules/googleanalytics/client.go (about)

     1  package googleanalytics
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"log"
     7  	"net/http"
     8  	"os"
     9  	"path/filepath"
    10  	"time"
    11  
    12  	"github.com/wtfutil/wtf/utils"
    13  	"golang.org/x/oauth2/google"
    14  	gaV3 "google.golang.org/api/analytics/v3"
    15  	gaV4 "google.golang.org/api/analyticsreporting/v4"
    16  	"google.golang.org/api/option"
    17  )
    18  
    19  type websiteReport struct {
    20  	Name           string
    21  	Report         *gaV4.GetReportsResponse
    22  	RealtimeReport *gaV3.RealtimeData
    23  }
    24  
    25  func (widget *Widget) fetch() []websiteReport {
    26  	secretPath, err := utils.ExpandHomeDir(widget.settings.secretFile)
    27  	if err != nil {
    28  		log.Fatalf("Unable to parse secretFile path")
    29  	}
    30  
    31  	serviceV4, err := makeReportServiceV4(secretPath)
    32  	if err != nil {
    33  		log.Fatalf("Unable to create v3 Google Analytics Reporting Service")
    34  	}
    35  
    36  	var serviceV3 *gaV3.Service
    37  	if widget.settings.enableRealtime {
    38  		serviceV3, err = makeReportServiceV3(secretPath)
    39  		if err != nil {
    40  			log.Fatalf("Unable to create v3 Google Analytics Reporting Service")
    41  		}
    42  	}
    43  
    44  	visitorsDataArray := getReports(
    45  		serviceV4, widget.settings.viewIds, widget.settings.months, serviceV3,
    46  	)
    47  	return visitorsDataArray
    48  }
    49  
    50  func buildNetClient(secretPath string) *http.Client {
    51  	clientSecret, err := os.ReadFile(filepath.Clean(secretPath))
    52  	if err != nil {
    53  		log.Fatalf("Unable to read secretPath. %v", err)
    54  	}
    55  
    56  	jwtConfig, err := google.JWTConfigFromJSON(clientSecret, gaV4.AnalyticsReadonlyScope)
    57  	if err != nil {
    58  		log.Fatalf("Unable to get config from JSON. %v", err)
    59  	}
    60  
    61  	return jwtConfig.Client(context.Background())
    62  }
    63  
    64  func makeReportServiceV3(secretPath string) (*gaV3.Service, error) {
    65  	client := buildNetClient(secretPath)
    66  
    67  	svc, err := gaV3.NewService(context.Background(), option.WithHTTPClient(client))
    68  	if err != nil {
    69  		log.Fatalf("Failed to create v3 Google Analytics Reporting Service")
    70  	}
    71  
    72  	return svc, err
    73  }
    74  
    75  func makeReportServiceV4(secretPath string) (*gaV4.Service, error) {
    76  	client := buildNetClient(secretPath)
    77  	svc, err := gaV4.NewService(context.Background(), option.WithHTTPClient(client))
    78  	if err != nil {
    79  		log.Fatalf("Failed to create v4 Google Analytics Reporting Service")
    80  	}
    81  
    82  	return svc, err
    83  }
    84  
    85  func getReports(
    86  	serviceV4 *gaV4.Service, viewIds map[string]interface{}, displayedMonths int, serviceV3 *gaV3.Service,
    87  ) []websiteReport {
    88  	startDate := fmt.Sprintf("%s-01", time.Now().AddDate(0, -displayedMonths+1, 0).Format("2006-01"))
    89  	var websiteReports []websiteReport
    90  
    91  	for website, viewID := range viewIds {
    92  		// For custom queries: https://ga-dev-tools.appspot.com/dimensions-metrics-explorer/
    93  
    94  		req := &gaV4.GetReportsRequest{
    95  			ReportRequests: []*gaV4.ReportRequest{
    96  				{
    97  					ViewId: viewID.(string),
    98  					DateRanges: []*gaV4.DateRange{
    99  						{StartDate: startDate, EndDate: "today"},
   100  					},
   101  					Metrics: []*gaV4.Metric{
   102  						{Expression: "ga:sessions"},
   103  					},
   104  					Dimensions: []*gaV4.Dimension{
   105  						{Name: "ga:month"},
   106  					},
   107  				},
   108  			},
   109  		}
   110  		response, err := serviceV4.Reports.BatchGet(req).Do()
   111  
   112  		if err != nil {
   113  			log.Fatalf("GET request to analyticsreporting/v4 returned error with viewID: %s", viewID)
   114  		}
   115  		if response.HTTPStatusCode != 200 {
   116  			log.Fatalf("Did not get expected HTTP response code")
   117  		}
   118  
   119  		report := websiteReport{Name: website, Report: response}
   120  		if serviceV3 != nil {
   121  			report.RealtimeReport = getLiveCount(serviceV3, viewID.(string))
   122  		}
   123  		websiteReports = append(websiteReports, report)
   124  	}
   125  	return websiteReports
   126  }
   127  
   128  func getLiveCount(service *gaV3.Service, viewID string) *gaV3.RealtimeData {
   129  	res, err := service.Data.Realtime.Get("ga:"+viewID, "rt:activeUsers").Do()
   130  	if err != nil {
   131  		log.Fatalf("Failed to fetch real time data for view ID %s: %v.  Have you enrolled in the real time beta?  If not, do so here: https://docs.google.com/forms/d/1qfRFysCikpgCMGqgF3yXdUyQW4xAlLyjKuOoOEFN2Uw/viewform", viewID, err)
   132  	}
   133  
   134  	return res
   135  }