From 0e0889cf080a3e8a41c507ba5601ea323125b27c Mon Sep 17 00:00:00 2001 From: emoralesms Date: Wed, 3 Jun 2026 14:59:40 -0300 Subject: [PATCH 1/5] feat: subscriber status stat model --- .../Models/SubscriberStatusStat.cs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 Doppler.ReportingApi/Models/SubscriberStatusStat.cs diff --git a/Doppler.ReportingApi/Models/SubscriberStatusStat.cs b/Doppler.ReportingApi/Models/SubscriberStatusStat.cs new file mode 100644 index 0000000..9d9765f --- /dev/null +++ b/Doppler.ReportingApi/Models/SubscriberStatusStat.cs @@ -0,0 +1,29 @@ +using System; + +namespace Doppler.ReportingApi.Models +{ + public class SubscriberStatusStat + { + public DateTime StatsAt { get; set; } + + public int NewSubscribers { get; set; } + + public int ActiveSubscribers { get; set; } + + public int InactiveDisableSubscribers { get; set; } + + public int UnsubscribedByHardSubscribers { get; set; } + + public int UnsubscribedBySoftSubscribers { get; set; } + + public int UnsubscribedBySubscriber { get; set; } + + public int UnsubscribedByNeverOpened { get; set; } + + public int PendingSubscribers { get; set; } + + public int UnsubscribedByClient { get; set; } + + public int StandBySubscribers { get; set; } + } +} From d16df809293e961ed8b30cef7c2885e1ce3fdcd4 Mon Sep 17 00:00:00 2001 From: emoralesms Date: Wed, 3 Jun 2026 15:00:01 -0300 Subject: [PATCH 2/5] feat: database query --- .../Infrastructure/ISummaryRepository.cs | 2 + .../Infrastructure/SummaryRepository.cs | 45 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/Doppler.ReportingApi/Infrastructure/ISummaryRepository.cs b/Doppler.ReportingApi/Infrastructure/ISummaryRepository.cs index f8ad8b3..36dbfc3 100644 --- a/Doppler.ReportingApi/Infrastructure/ISummaryRepository.cs +++ b/Doppler.ReportingApi/Infrastructure/ISummaryRepository.cs @@ -1,5 +1,6 @@ using Doppler.ReportingApi.Models; using System; +using System.Collections.Generic; using System.Threading.Tasks; namespace Doppler.ReportingApi.Infrastructure @@ -8,6 +9,7 @@ public interface ISummaryRepository { Task GetCampaignsSummaryByUserAsync(string userName, DateTime startDate, DateTime endDate); Task GetSubscribersSummaryByUserAsync(string userName, DateTime startDate, DateTime endDate); + Task> GetSubscribersDashboardByUserAsync(string userName, DateTime startDate, DateTime endDate); Task GetSystemUsageAsync(string accountName); } } diff --git a/Doppler.ReportingApi/Infrastructure/SummaryRepository.cs b/Doppler.ReportingApi/Infrastructure/SummaryRepository.cs index cd4955a..f01d71c 100644 --- a/Doppler.ReportingApi/Infrastructure/SummaryRepository.cs +++ b/Doppler.ReportingApi/Infrastructure/SummaryRepository.cs @@ -87,6 +87,51 @@ FROM Subscriber S } } + public async Task> GetSubscribersDashboardByUserAsync( + string userName, + DateTime startDate, + DateTime endDate) + { + using (var connection = _connectionFactory.GetConnection()) + { + startDate = startDate.Date; + endDate = endDate.Date; + + var query = @" + DECLARE @idUser INT; + + SELECT @idUser = IdUser + FROM [User] + WHERE Email = @userName; + + SELECT + StatsAt, + NewSubscribers, + ActiveSubscribers, + InactiveDisableSubscribers, + UnsubscribedByHardSubscribers, + UnsubscribedBySoftSubscribers, + UnsubscribedByNeverOpened, + PendingSubscribers, + UnsubscribedByClient, + StandBySubscribers + FROM SubscriberStatusStat + WHERE IdUser = @idUser + AND StatsAt BETWEEN @startDate AND @endDate + ORDER BY StatsAt; + "; + + return await connection.QueryAsync( + query, + new + { + userName, + startDate, + endDate + }); + } + } + public async Task GetSystemUsageAsync(string accountName) { using (var connection = _connectionFactory.GetConnection()) From 0831aebeaf2393cefbe2a457a15d34faa0f547b2 Mon Sep 17 00:00:00 2001 From: emoralesms Date: Wed, 3 Jun 2026 15:00:15 -0300 Subject: [PATCH 3/5] feat: controller subscribers --- .../Controllers/SummaryController.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Doppler.ReportingApi/Controllers/SummaryController.cs b/Doppler.ReportingApi/Controllers/SummaryController.cs index ce496df..cffe671 100644 --- a/Doppler.ReportingApi/Controllers/SummaryController.cs +++ b/Doppler.ReportingApi/Controllers/SummaryController.cs @@ -72,6 +72,26 @@ public async Task GetSubscribers(string accountName, [FromQuery] return new OkObjectResult(result); } + [HttpGet] + [Route("{accountName}/dashboard/subscribers")] + [ProducesResponseType(typeof(SubscriberStatusStat), 200)] + [Produces("application/json")] + [Authorize(Policies.OWN_RESOURCE_OR_SUPERUSER)] + public async Task GetSubscribersDashboard(string accountName, [FromQuery] BasicDateFilter dateFilter) + { + if (!dateFilter.StartDate.HasValue || !dateFilter.EndDate.HasValue) + { + return new BadRequestObjectResult("StartDate and EndDate are required fields"); + } + + var startDate = dateFilter.StartDate.Value.UtcDateTime; + var endDate = dateFilter.EndDate.Value.UtcDateTime; + + var result = await _summaryRepository.GetSubscribersDashboardByUserAsync(accountName, startDate, endDate); + + return new OkObjectResult(result); + } + /// /// Returns an object with info about the use of Doppler by a particular user /// From 1bfa905e919f7e4768170fb4c38e66faf32ad954 Mon Sep 17 00:00:00 2001 From: emoralesms Date: Wed, 3 Jun 2026 15:34:47 -0300 Subject: [PATCH 4/5] fix: change order --- Doppler.ReportingApi/Infrastructure/SummaryRepository.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doppler.ReportingApi/Infrastructure/SummaryRepository.cs b/Doppler.ReportingApi/Infrastructure/SummaryRepository.cs index f01d71c..f11de80 100644 --- a/Doppler.ReportingApi/Infrastructure/SummaryRepository.cs +++ b/Doppler.ReportingApi/Infrastructure/SummaryRepository.cs @@ -118,7 +118,7 @@ FROM [User] FROM SubscriberStatusStat WHERE IdUser = @idUser AND StatsAt BETWEEN @startDate AND @endDate - ORDER BY StatsAt; + ORDER BY StatsAt DESC; "; return await connection.QueryAsync( From 0ee238e2c88ba2ca813dbeba247b808c9b595e1c Mon Sep 17 00:00:00 2001 From: emoralesms Date: Fri, 5 Jun 2026 14:23:02 -0300 Subject: [PATCH 5/5] fix: contemplate timezone --- .../Infrastructure/SummaryRepository.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Doppler.ReportingApi/Infrastructure/SummaryRepository.cs b/Doppler.ReportingApi/Infrastructure/SummaryRepository.cs index f11de80..9cd5ffd 100644 --- a/Doppler.ReportingApi/Infrastructure/SummaryRepository.cs +++ b/Doppler.ReportingApi/Infrastructure/SummaryRepository.cs @@ -94,16 +94,19 @@ public async Task> GetSubscribersDashboardByUs { using (var connection = _connectionFactory.GetConnection()) { - startDate = startDate.Date; - endDate = endDate.Date; - var query = @" DECLARE @idUser INT; + DECLARE @timezone INT; SELECT @idUser = IdUser FROM [User] WHERE Email = @userName; + SELECT @timezone = timezone.offset + FROM dbo.usertimezone timezone + INNER JOIN dbo.[User] u ON u.idusertimezone = timezone.idusertimezone + WHERE u.[Email] = @userName; + SELECT StatsAt, NewSubscribers, @@ -117,7 +120,8 @@ FROM [User] StandBySubscribers FROM SubscriberStatusStat WHERE IdUser = @idUser - AND StatsAt BETWEEN @startDate AND @endDate + AND StatsAt >= CAST(DATEADD(MINUTE, @timezone, @startDate) AS DATE) + AND StatsAt < CAST(DATEADD(MINUTE, @timezone, @endDate) AS DATE) ORDER BY StatsAt DESC; ";