187 lines
5.6 KiB
C#
187 lines
5.6 KiB
C#
using DotNetEnv;
|
|
using Google.Apis.AnalyticsData.v1beta;
|
|
using Google.Apis.AnalyticsData.v1beta.Data;
|
|
using Google.Apis.Auth.OAuth2;
|
|
using Google.Apis.Services;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
|
Env.Load();
|
|
|
|
var builder = WebApplication.CreateBuilder(args);
|
|
|
|
// Add services to the container.
|
|
builder.Services.AddEndpointsApiExplorer();
|
|
builder.Services.AddSwaggerGen();
|
|
|
|
// Register Google Analytics Data Client
|
|
builder.Services.AddSingleton<AnalyticsDataService>(sp =>
|
|
{
|
|
GoogleCredential credential;
|
|
try
|
|
{
|
|
// Tries to find credentials from GOOGLE_APPLICATION_CREDENTIALS environment variable
|
|
// or default cloud environment credentials.
|
|
credential = GoogleCredential.GetApplicationDefault();
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// Fallback for local development if env var not set (User might need to run 'gcloud auth application-default login')
|
|
// Or we warn them. For now, we assume it's set up or will fail at runtime.
|
|
throw new InvalidOperationException("Could not load Google Credentials. Set GOOGLE_APPLICATION_CREDENTIALS or run 'gcloud auth application-default login'.");
|
|
}
|
|
|
|
if (credential.IsCreateScopedRequired)
|
|
{
|
|
credential = credential.CreateScoped(AnalyticsDataService.Scope.AnalyticsReadonly);
|
|
}
|
|
|
|
var service = new AnalyticsDataService(new BaseClientService.Initializer
|
|
{
|
|
HttpClientInitializer = credential,
|
|
ApplicationName = "TravelMate Backend",
|
|
});
|
|
|
|
return service;
|
|
});
|
|
|
|
var app = builder.Build();
|
|
|
|
// Configure the HTTP request pipeline.
|
|
if (app.Environment.IsDevelopment())
|
|
{
|
|
app.UseSwagger();
|
|
app.UseSwaggerUI();
|
|
}
|
|
|
|
app.UseHttpsRedirection();
|
|
|
|
string? ga4PropertyId = Environment.GetEnvironmentVariable("GA4_PROPERTY_ID");
|
|
if (string.IsNullOrEmpty(ga4PropertyId))
|
|
{
|
|
Console.WriteLine("Warning: GA4_PROPERTY_ID not set in .env");
|
|
// Default or error? Let's just hold it and fail in the endpoint if needed, or fail startup.
|
|
// For now, let's allow it to start but endpoint will likely fail.
|
|
}
|
|
|
|
app.MapGet("/api/metrics/daily", async (
|
|
[FromServices] AnalyticsDataService service,
|
|
[FromQuery] string from,
|
|
[FromQuery] string to) =>
|
|
{
|
|
// Basic validation
|
|
// Basic validation: Check if it's a valid date OR a valid GA4 keyword
|
|
bool IsValidDate(string date)
|
|
{
|
|
return DateTime.TryParse(date, out _) ||
|
|
date == "today" ||
|
|
date == "yesterday" ||
|
|
date.EndsWith("daysAgo");
|
|
}
|
|
|
|
if (!IsValidDate(from) || !IsValidDate(to))
|
|
{
|
|
return Results.BadRequest(new { error = "Invalid date format. Use YYYY-MM-DD, 'today', 'yesterday', or 'NdaysAgo'." });
|
|
}
|
|
|
|
var request = new RunReportRequest
|
|
{
|
|
Property = $"properties/{ga4PropertyId}",
|
|
DateRanges = new List<DateRange>
|
|
{
|
|
new DateRange { StartDate = from, EndDate = to }
|
|
},
|
|
Dimensions = new List<Dimension>
|
|
{
|
|
new Dimension { Name = "date" }
|
|
},
|
|
Metrics = new List<Metric>
|
|
{
|
|
new Metric { Name = "activeUsers" } // equivalent to Daily Active Users in this context often
|
|
// Or strictly "activeUsers"
|
|
}
|
|
};
|
|
|
|
try
|
|
{
|
|
var response = await service.Properties.RunReport(request, $"properties/{ga4PropertyId}").ExecuteAsync();
|
|
|
|
var result = response.Rows?.Select(row => new
|
|
{
|
|
date = FormatDate(row.DimensionValues[0].Value), // GA4 returns date as YYYYMMDD string usually
|
|
dailyActiveUsers = int.Parse(row.MetricValues[0].Value)
|
|
}) ?? Enumerable.Empty<object>();
|
|
|
|
return Results.Ok(result);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"Error: {ex}");
|
|
return Results.Problem($"Analytics API Error: {ex.Message}");
|
|
}
|
|
})
|
|
.WithName("GetDailyMetrics")
|
|
.WithOpenApi();
|
|
|
|
app.MapGet("/api/metrics/general", async (
|
|
[FromServices] AnalyticsDataService service) =>
|
|
{
|
|
// "Global" means all time ideally, or a very long range.
|
|
// GA4 retention might limit this for user-level data, but aggregated metrics usually go back further.
|
|
var startDate = "2023-01-01"; // Arbitrary start date for the app
|
|
var endDate = "today";
|
|
|
|
var request = new RunReportRequest
|
|
{
|
|
Property = $"properties/{ga4PropertyId}",
|
|
DateRanges = new List<DateRange>
|
|
{
|
|
new DateRange { StartDate = startDate, EndDate = endDate }
|
|
},
|
|
Metrics = new List<Metric>
|
|
{
|
|
new Metric { Name = "totalUsers" }, // Proxy for "nb de comptes"
|
|
new Metric { Name = "eventCount" } // Proxy for "nb de requètes"
|
|
}
|
|
};
|
|
|
|
try
|
|
{
|
|
var response = await service.Properties.RunReport(request, $"properties/{ga4PropertyId}").ExecuteAsync();
|
|
|
|
var totalUsers = 0;
|
|
var eventCount = 0;
|
|
|
|
if (response.Rows != null && response.Rows.Count > 0)
|
|
{
|
|
var row = response.Rows[0];
|
|
totalUsers = int.Parse(row.MetricValues[0].Value);
|
|
eventCount = int.Parse(row.MetricValues[1].Value);
|
|
}
|
|
|
|
return Results.Ok(new
|
|
{
|
|
totalAccounts = totalUsers,
|
|
totalRequests = eventCount
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"Error: {ex}");
|
|
return Results.Problem($"Analytics API Error: {ex.Message}");
|
|
}
|
|
})
|
|
.WithName("GetGeneralMetrics")
|
|
.WithOpenApi();
|
|
|
|
app.Run();
|
|
|
|
// Helper to format GA4 YYYYMMDD to YYYY-MM-DD
|
|
static string FormatDate(string gaDate)
|
|
{
|
|
if (gaDate.Length == 8)
|
|
{
|
|
return $"{gaDate.Substring(0, 4)}-{gaDate.Substring(4, 2)}-{gaDate.Substring(6, 2)}";
|
|
}
|
|
return gaDate;
|
|
}
|