mirror of
				https://github.com/taigrr/wtf
				synced 2025-01-18 04:03:14 -08:00 
			
		
		
		
	Add google analytics module
This commit is contained in:
		
							parent
							
								
									4f8a4c9dc2
								
							
						
					
					
						commit
						ae61d2f7ad
					
				
							
								
								
									
										93
									
								
								modules/googleanalytics/client.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								modules/googleanalytics/client.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,93 @@
 | 
			
		||||
package googleanalytics
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"log"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/wtfutil/wtf/utils"
 | 
			
		||||
	"golang.org/x/oauth2"
 | 
			
		||||
	"golang.org/x/oauth2/google"
 | 
			
		||||
	ga "google.golang.org/api/analyticsreporting/v4"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type websiteReport struct {
 | 
			
		||||
    Name string
 | 
			
		||||
    Report *ga.GetReportsResponse
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (widget *Widget) Fetch() ([]websiteReport) {
 | 
			
		||||
	secretPath, err := utils.ExpandHomeDir(widget.settings.secretFile)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatalf("Unable to parse secretFile path")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	service, err := makeReportService(secretPath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatalf("Unable to create Google Analytics Reporting Service")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	visitorsDataArray := getReports(service, widget.settings.viewIds, widget.settings.months)
 | 
			
		||||
	return visitorsDataArray
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func makeReportService(secretPath string) (*ga.Service, error) {
 | 
			
		||||
	clientSecret, err := ioutil.ReadFile(secretPath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatalf("Unable to read secretPath. %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	jwtConfig, err := google.JWTConfigFromJSON(clientSecret, ga.AnalyticsReadonlyScope)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatalf("Unable to get config from JSON. %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var netClient *http.Client
 | 
			
		||||
	netClient = jwtConfig.Client(oauth2.NoContext)
 | 
			
		||||
	svc, err := ga.New(netClient)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatalf("Failed to create Google Analytics Reporting Service")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return svc, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getReports(service *ga.Service, viewIds map[string]interface{}, displayedMonths int) ([]websiteReport) {
 | 
			
		||||
	startDate := fmt.Sprintf("%s-01", time.Now().AddDate(0, -displayedMonths+1, 0).Format("2006-01"))
 | 
			
		||||
	var websiteReports []websiteReport = nil
 | 
			
		||||
 | 
			
		||||
	for website, viewId := range viewIds {
 | 
			
		||||
		// For custom queries: https://ga-dev-tools.appspot.com/dimensions-metrics-explorer/
 | 
			
		||||
 | 
			
		||||
		req := &ga.GetReportsRequest{
 | 
			
		||||
			ReportRequests: []*ga.ReportRequest{
 | 
			
		||||
				{
 | 
			
		||||
					ViewId: viewId.(string),
 | 
			
		||||
					DateRanges: []*ga.DateRange{
 | 
			
		||||
						{StartDate: startDate, EndDate: "today"},
 | 
			
		||||
					},
 | 
			
		||||
					Metrics: []*ga.Metric{
 | 
			
		||||
						{Expression: "ga:sessions"},
 | 
			
		||||
					},
 | 
			
		||||
					Dimensions: []*ga.Dimension{
 | 
			
		||||
						{Name: "ga:month"},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		}
 | 
			
		||||
		response, err := service.Reports.BatchGet(req).Do()
 | 
			
		||||
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Fatalf("GET request to analyticsreporting/v4 returned error with viewID: %s", viewId)
 | 
			
		||||
		}
 | 
			
		||||
		if response.HTTPStatusCode != 200 {
 | 
			
		||||
			log.Fatalf("Did not get expected HTTP response code")
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		report := websiteReport{Name: website, Report: response,}
 | 
			
		||||
		websiteReports = append(websiteReports, report)
 | 
			
		||||
	}
 | 
			
		||||
	return websiteReports
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										54
									
								
								modules/googleanalytics/display.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								modules/googleanalytics/display.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,54 @@
 | 
			
		||||
package googleanalytics
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"time"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (widget *Widget) createTable(websiteReports []websiteReport) (string) {
 | 
			
		||||
  content := widget.createHeader()
 | 
			
		||||
 | 
			
		||||
	for _, websiteReport := range websiteReports {
 | 
			
		||||
		websiteRow := ""
 | 
			
		||||
 | 
			
		||||
		for _, report := range websiteReport.Report.Reports {
 | 
			
		||||
			websiteRow += fmt.Sprintf(" %-20s", websiteReport.Name)
 | 
			
		||||
			reportRows := report.Data.Rows
 | 
			
		||||
			noDataMonth := widget.settings.months - len(reportRows)
 | 
			
		||||
 | 
			
		||||
			// Fill in requested months with no data from query
 | 
			
		||||
			if noDataMonth > 0 {
 | 
			
		||||
					websiteRow += strings.Repeat("-         ", noDataMonth)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if reportRows == nil {
 | 
			
		||||
				websiteRow += fmt.Sprintf("No data found for given ViewId.")
 | 
			
		||||
			} else {
 | 
			
		||||
				for _, row := range reportRows {
 | 
			
		||||
					metrics := row.Metrics
 | 
			
		||||
 | 
			
		||||
					for _, metric := range metrics {
 | 
			
		||||
						websiteRow += fmt.Sprintf("%-10s", metric.Values[0])
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			content += websiteRow + "\n"
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return content
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (widget *Widget) createHeader() (string) {
 | 
			
		||||
  // Creates the table header of consisting of Months
 | 
			
		||||
	currentMonth := int(time.Now().Month())
 | 
			
		||||
	widgetStartMonth := currentMonth-widget.settings.months+1
 | 
			
		||||
  header := "                     "
 | 
			
		||||
 | 
			
		||||
  for i := widgetStartMonth; i < currentMonth+1; i++ {
 | 
			
		||||
  	header += fmt.Sprintf("%-10s", time.Month(i))
 | 
			
		||||
  }
 | 
			
		||||
  header += "\n"
 | 
			
		||||
 | 
			
		||||
  return header
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								modules/googleanalytics/settings.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								modules/googleanalytics/settings.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
			
		||||
package googleanalytics
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/olebedev/config"
 | 
			
		||||
	"github.com/wtfutil/wtf/cfg"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const defaultTitle = "Google Analytics"
 | 
			
		||||
 | 
			
		||||
type Settings struct {
 | 
			
		||||
	common *cfg.Common
 | 
			
		||||
 | 
			
		||||
	months				int
 | 
			
		||||
	secretFile    string `help:"Your Google client secret JSON file." values:"A string representing a file path to the JSON secret file."`
 | 
			
		||||
	viewIds				map[string]interface{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewSettingsFromYAML(name string, ymlConfig *config.Config, globalConfig *config.Config) *Settings {
 | 
			
		||||
 | 
			
		||||
	settings := Settings{
 | 
			
		||||
		common: cfg.NewCommonSettingsFromModule(name, defaultTitle, ymlConfig, globalConfig),
 | 
			
		||||
 | 
			
		||||
		months:			ymlConfig.UInt("months"),
 | 
			
		||||
		secretFile: ymlConfig.UString("secretFile"),
 | 
			
		||||
		viewIds:  ymlConfig.UMap("viewIds"),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &settings
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								modules/googleanalytics/widget.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								modules/googleanalytics/widget.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
			
		||||
package googleanalytics
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/rivo/tview"
 | 
			
		||||
	"github.com/wtfutil/wtf/wtf"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Widget struct {
 | 
			
		||||
	wtf.TextWidget
 | 
			
		||||
 | 
			
		||||
	settings *Settings
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewWidget(app *tview.Application, settings *Settings) *Widget {
 | 
			
		||||
	widget := Widget{
 | 
			
		||||
		TextWidget: wtf.NewTextWidget(app, settings.common, false),
 | 
			
		||||
 | 
			
		||||
		settings: settings,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &widget
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (widget *Widget) Refresh() {
 | 
			
		||||
	websiteReports := widget.Fetch()
 | 
			
		||||
	contentTable := widget.createTable(websiteReports)
 | 
			
		||||
 | 
			
		||||
	widget.Redraw(widget.CommonSettings().Title, contentTable, false)
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user