PlotDirector/PlotLine/Data/SubscriptionRepository.cs
2026-06-07 14:59:41 +01:00

183 lines
8.3 KiB
C#

using System.Data;
using Dapper;
using PlotLine.Models;
namespace PlotLine.Data;
public interface ISubscriptionRepository
{
Task<UserSubscriptionDetail?> GetCurrentSubscriptionAsync(int userId);
Task<SubscriptionLevel?> GetSubscriptionLevelAsync(int subscriptionLevelId);
Task<IReadOnlyList<SubscriptionLevel>> GetActiveSubscriptionLevelsAsync();
Task<int> GetOwnedBookCountAsync(int userId);
Task<int> GetChapterCountForBookAsync(int bookId);
Task<int> GetSceneCountForBookAsync(int bookId);
Task<int> GetCharacterCountForProjectAsync(int projectId);
Task<int> GetCollaboratorCountForOwnerAsync(int userId);
Task<SubscriptionUsageSummary> GetUsageSummaryForOwnerAsync(int userId);
Task<SubscriptionLevel?> GetSubscriptionLevelByStripePriceAsync(string stripePriceId);
Task SetStripeCustomerAsync(int userId, string stripeCustomerId);
Task<bool> TryBeginStripeWebhookEventAsync(string stripeEventId, string eventType);
Task CompleteStripeWebhookEventAsync(string stripeEventId, string processingStatus, string? errorMessage = null);
Task ApplyStripeStateAsync(StripeSubscriptionSyncState state);
Task DowngradeToDraftDeskAsync(string? stripeCustomerId, string? stripeSubscriptionId, string? lastStripeEventId);
Task RecordPaymentFailureAsync(string? stripeCustomerId, string? stripeSubscriptionId, string? lastStripeEventId);
Task ClearPaymentFailureAsync(string? stripeCustomerId, string? stripeSubscriptionId, string? lastStripeEventId);
}
public sealed class SubscriptionRepository(ISqlConnectionFactory connectionFactory) : ISubscriptionRepository
{
public async Task<UserSubscriptionDetail?> GetCurrentSubscriptionAsync(int userId)
{
using var connection = connectionFactory.CreateConnection();
return await connection.QuerySingleOrDefaultAsync<UserSubscriptionDetail>(
"dbo.UserSubscription_GetCurrent",
new { UserID = userId },
commandType: CommandType.StoredProcedure);
}
public async Task<SubscriptionLevel?> GetSubscriptionLevelAsync(int subscriptionLevelId)
{
using var connection = connectionFactory.CreateConnection();
return await connection.QuerySingleOrDefaultAsync<SubscriptionLevel>(
"dbo.SubscriptionLevel_Get",
new { SubscriptionLevelID = subscriptionLevelId },
commandType: CommandType.StoredProcedure);
}
public async Task<IReadOnlyList<SubscriptionLevel>> GetActiveSubscriptionLevelsAsync()
{
using var connection = connectionFactory.CreateConnection();
var rows = await connection.QueryAsync<SubscriptionLevel>(
"dbo.SubscriptionLevel_ListActive",
commandType: CommandType.StoredProcedure);
return rows.ToList();
}
public async Task<int> GetOwnedBookCountAsync(int userId)
{
using var connection = connectionFactory.CreateConnection();
return await connection.QuerySingleAsync<int>(
"dbo.SubscriptionUsage_BookCountForOwner",
new { UserID = userId },
commandType: CommandType.StoredProcedure);
}
public async Task<int> GetChapterCountForBookAsync(int bookId)
{
using var connection = connectionFactory.CreateConnection();
return await connection.QuerySingleAsync<int>(
"dbo.SubscriptionUsage_ChapterCountForBook",
new { BookID = bookId },
commandType: CommandType.StoredProcedure);
}
public async Task<int> GetSceneCountForBookAsync(int bookId)
{
using var connection = connectionFactory.CreateConnection();
return await connection.QuerySingleAsync<int>(
"dbo.SubscriptionUsage_SceneCountForBook",
new { BookID = bookId },
commandType: CommandType.StoredProcedure);
}
public async Task<int> GetCharacterCountForProjectAsync(int projectId)
{
using var connection = connectionFactory.CreateConnection();
return await connection.QuerySingleAsync<int>(
"dbo.SubscriptionUsage_CharacterCountForProject",
new { ProjectID = projectId },
commandType: CommandType.StoredProcedure);
}
public async Task<int> GetCollaboratorCountForOwnerAsync(int userId)
{
using var connection = connectionFactory.CreateConnection();
return await connection.QuerySingleAsync<int>(
"dbo.SubscriptionUsage_CollaboratorCountForOwner",
new { UserID = userId },
commandType: CommandType.StoredProcedure);
}
public async Task<SubscriptionUsageSummary> GetUsageSummaryForOwnerAsync(int userId)
{
using var connection = connectionFactory.CreateConnection();
return await connection.QuerySingleAsync<SubscriptionUsageSummary>(
"dbo.SubscriptionUsage_GetSummaryForOwner",
new { UserID = userId },
commandType: CommandType.StoredProcedure);
}
public async Task<SubscriptionLevel?> GetSubscriptionLevelByStripePriceAsync(string stripePriceId)
{
using var connection = connectionFactory.CreateConnection();
return await connection.QuerySingleOrDefaultAsync<SubscriptionLevel>(
"dbo.SubscriptionLevel_GetByStripePrice",
new { StripePriceId = stripePriceId },
commandType: CommandType.StoredProcedure);
}
public async Task SetStripeCustomerAsync(int userId, string stripeCustomerId)
{
using var connection = connectionFactory.CreateConnection();
await connection.ExecuteAsync(
"dbo.UserSubscription_SetStripeCustomer",
new { UserID = userId, StripeCustomerId = stripeCustomerId },
commandType: CommandType.StoredProcedure);
}
public async Task<bool> TryBeginStripeWebhookEventAsync(string stripeEventId, string eventType)
{
using var connection = connectionFactory.CreateConnection();
return await connection.QuerySingleAsync<bool>(
"dbo.StripeWebhookEvent_TryBegin",
new { StripeEventId = stripeEventId, EventType = eventType },
commandType: CommandType.StoredProcedure);
}
public async Task CompleteStripeWebhookEventAsync(string stripeEventId, string processingStatus, string? errorMessage = null)
{
using var connection = connectionFactory.CreateConnection();
await connection.ExecuteAsync(
"dbo.StripeWebhookEvent_Complete",
new { StripeEventId = stripeEventId, ProcessingStatus = processingStatus, ErrorMessage = errorMessage },
commandType: CommandType.StoredProcedure);
}
public async Task ApplyStripeStateAsync(StripeSubscriptionSyncState state)
{
using var connection = connectionFactory.CreateConnection();
await connection.ExecuteAsync(
"dbo.UserSubscription_ApplyStripeState",
state,
commandType: CommandType.StoredProcedure);
}
public async Task DowngradeToDraftDeskAsync(string? stripeCustomerId, string? stripeSubscriptionId, string? lastStripeEventId)
{
using var connection = connectionFactory.CreateConnection();
await connection.ExecuteAsync(
"dbo.UserSubscription_DowngradeToDraftDesk",
new { StripeCustomerId = stripeCustomerId, StripeSubscriptionId = stripeSubscriptionId, LastStripeEventId = lastStripeEventId },
commandType: CommandType.StoredProcedure);
}
public async Task RecordPaymentFailureAsync(string? stripeCustomerId, string? stripeSubscriptionId, string? lastStripeEventId)
{
using var connection = connectionFactory.CreateConnection();
await connection.ExecuteAsync(
"dbo.UserSubscription_RecordPaymentFailure",
new { StripeCustomerId = stripeCustomerId, StripeSubscriptionId = stripeSubscriptionId, LastStripeEventId = lastStripeEventId },
commandType: CommandType.StoredProcedure);
}
public async Task ClearPaymentFailureAsync(string? stripeCustomerId, string? stripeSubscriptionId, string? lastStripeEventId)
{
using var connection = connectionFactory.CreateConnection();
await connection.ExecuteAsync(
"dbo.UserSubscription_ClearPaymentFailure",
new { StripeCustomerId = stripeCustomerId, StripeSubscriptionId = stripeSubscriptionId, LastStripeEventId = lastStripeEventId },
commandType: CommandType.StoredProcedure);
}
}