Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidEggenberger committed Dec 28, 2024
2 parents 02856d7 + 7d5ce94 commit 3205300
Show file tree
Hide file tree
Showing 82 changed files with 465 additions and 304 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/Build_Test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 6.0.x
dotnet-version: 9.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>
</PropertyGroup>

Expand All @@ -10,7 +10,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.0" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using Shared.Features.Messaging.IntegrationEvents;
using Stripe;

namespace Modules.Subscriptions.Features.DomainFeatures.StripeCustomers.Application.IntegrationEvents
namespace Modules.Subscriptions.Features.DomainFeatures.StripeCustomers.Application.EventHandlers
{
public class TenantAdminCreatedIntegrationEventHandler : IIntegrationEventHandler<TenantAdminCreatedIntegrationEvent>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ namespace Modules.Subscriptions.Features.DomainFeatures.StripeCustomers
{
public class StripeCustomer : Entity
{
public Guid UserId { get; set; }
public string StripePortalCustomerId { get; set; }
public Guid UserId { get; private set; }
public string StripePortalCustomerId { get; private set; }

public static StripeCustomer Create(Guid userId, string stripePortalCustomerId)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ namespace Modules.Subscriptions.Features.DomainFeatures.StripeSubscriptions.Appl
{
public class CreateTrialingSubscription : Command
{
public Guid UserId { get; set; }
public Guid TenantId { get; set; }
public string StripeCustomerId { get; set; }
public Stripe.Subscription CreatedStripeSubscription { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public async Task HandleAsync(PauseActiveSubscription command, CancellationToken
{
var stripeSubscription = await module.SubscriptionsDbContext.StripeSubscriptions.FirstAsync(stripeSubscription => stripeSubscription.StripePortalSubscriptionId == command.Subscription.Id);

stripeSubscription.Status = StripeSubscriptionStatus.Paused;
stripeSubscription.UpdateStatus(StripeSubscriptionStatus.Paused);

await module.SubscriptionsDbContext.SaveChangesAsync(cancellationToken);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ public async Task HandleAsync(UpdateSubscriptionPeriod command, CancellationToke

if (stripeSubscription.Status != StripeSubscriptionStatus.Active)
{
stripeSubscription.Status = StripeSubscriptionStatus.Active;
stripeSubscription.UpdateStatus(StripeSubscriptionStatus.Active);
}
stripeSubscription.ExpirationDate = command.Subscription.CurrentPeriodEnd;
stripeSubscription.UpdateExpirationDate(command.Subscription.CurrentPeriodEnd);

await module.SubscriptionsDbContext.SaveChangesAsync(cancellationToken);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
using Shared.Features.Messaging.Query;
using Shared.Kernel.BuildingBlocks.Auth.Attributes;

namespace Modules.Subscriptions.Features.DomainFeatures.StripeSubscriptions.Application.Queries
{
[AuthorizeTenantAdmin]
public class GetSubscriptionForTenant : Query<object>
public class GetSubscriptionForTenant : Query<StripeSubscription>
{
public Guid UserId { get; set; }
public Guid TenantId { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@
using Microsoft.EntityFrameworkCore;
using Modules.Subscriptions.Features.DomainFeatures.StripeCustomers;
using Shared.Features.Domain;
using Shared.Kernel.BuildingBlocks.Auth;
using Shared.Kernel.DomainKernel;

namespace Modules.Subscriptions.Features.DomainFeatures.StripeSubscriptions
{
public class StripeSubscription : Entity
{
private StripeSubscription() { }

public string StripePortalSubscriptionId { get; set; }
public Guid StripeCustomerId { get; set; }
public StripeCustomer StripeCustomer { get; set; }
public DateTime? ExpirationDate { get; set; }
public SubscriptionPlanType PlanType { get; set; }
public StripeSubscriptionStatus Status { get; set; }
public string StripePortalSubscriptionId { get; private set; }
public Guid StripeCustomerId { get; private set; }
public StripeCustomer StripeCustomer { get; private set; }
public DateTime? ExpirationDate { get; private set; }
public SubscriptionPlanType PlanType { get; private set; }
public StripeSubscriptionStatus Status { get; private set; }

public static StripeSubscription Create(
DateTime? expirationDate,
Expand All @@ -35,6 +35,16 @@ public static StripeSubscription Create(
StripeCustomer = stripeCustomer
};
}

public void UpdateStatus(StripeSubscriptionStatus status)
{
Status = status;
}

public void UpdateExpirationDate(DateTime expirationDate)
{
ExpirationDate = expirationDate;
}
}

public class StripeSubscriptionEFConfiguration : IEntityTypeConfiguration<StripeSubscription>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Modules.Subscriptions.Features.Infrastructure.StripePayments;
using Shared.Features.Configuration;
using Shared.Kernel.BuildingBlocks.Auth;
using Shared.Kernel.DomainKernel;

namespace Modules.Subscriptions.Features.Infrastructure.Configuration
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using Modules.Subscriptions.Features.Infrastructure.Configuration;
using Modules.Subscriptions.Features.Infrastructure.EFCore;
using Shared.Features.Messaging.Command;
using Shared.Kernel.BuildingBlocks.Auth;
using Shared.Kernel.DomainKernel;
using Stripe.Checkout;

namespace Modules.Subscriptions.Features.Infrastructure.StripePayments
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Shared.Kernel.BuildingBlocks.Auth;
using Shared.Kernel.DomainKernel;

namespace Modules.Subscriptions.Features.Infrastructure.StripePayments
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0" />
<PackageReference Include="Stripe.net" Version="41.20.0" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="9.0.0" />
<PackageReference Include="Stripe.net" Version="47.2.0-beta.3" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using Shared.Kernel.BuildingBlocks;
using Shared.Kernel.BuildingBlocks.Auth;
using Shared.Kernel.DomainKernel;

namespace Modules.Subscriptions.IntegrationEvents
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
using Microsoft.AspNetCore.Mvc;
using Shared.Kernel.BuildingBlocks.Auth;
using Shared.Kernel.BuildingBlocks.Auth.Attributes;
using Modules.Subscriptions.Features.Infrastructure.StripePayments;
using Shared.Features.Server;
using Shared.Kernel.DomainKernel;
using Microsoft.AspNetCore.Authorization;
using Shared.Kernel.BuildingBlocks.Auth.Constants;

namespace Modules.Subscriptions.Server.Controllers
{
[Route("api/[controller]")]
[ApiController]
[AuthorizeTenantAdmin]
[Authorize(Policy = PolicyConstants.TenantAdminPolicy)]
public class StripeSessionController : BaseController
{
public StripeSessionController(IServiceProvider serviceProvider) : base(serviceProvider)
{

}
public StripeSessionController(IServiceProvider serviceProvider) : base(serviceProvider) { }

[HttpPost("checkout/{subscriptionPlanType}")]
public async Task<ActionResult> RedirectToStripePremiumSubscription([FromRoute] SubscriptionPlanType subscriptionPlanType)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Modules.Subscriptions.Features.DomainFeatures.StripeSubscriptions.Application.Queries;
using Shared.Features.Server;
using Shared.Kernel.BuildingBlocks.Auth.Attributes;
using Shared.Kernel.BuildingBlocks.Auth.Constants;

namespace Modules.Subscriptions.Web.Server.Controllers
{
[Route("api/[controller]")]
[ApiController]
[Authorize(Policy = PolicyConstants.TenantAdminPolicy)]
public class StripeSubscriptionsController : BaseController
{
public StripeSubscriptionsController(IServiceProvider serviceProvider) : base(serviceProvider)
{
}

[HttpGet]
[AuthorizeTenantAdmin]
public async Task GetSubscription()
{
var getSubscriptionForTenant = new GetSubscriptionForTenant
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Identity" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.ViewFeatures" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="6.0.16" />
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="9.0.0" />
</ItemGroup>

<ItemGroup>
Expand Down
25 changes: 11 additions & 14 deletions Source/Modules/Subscriptions/Web/Server/WebHooks/StripeWebhook.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,17 @@
using Microsoft.AspNetCore.Mvc;
using Stripe;
using Shared.Features.Server;
using Modules.Subscriptions.Features.Infrastructure.Configuration;
using Modules.Subscriptions.Features.DomainFeatures.StripeSubscriptions.Application.Commands;
using Modules.Subscriptions.Features;
using Stripe.V2;

namespace Modules.Subscriptions.Server.WebHooks
{
[Route("api/[controller]")]
[ApiController]
public class StripeWebhook : BaseController
public class StripeWebhook : BaseController<SubscriptionsModule>
{
private readonly SubscriptionsConfiguration subscriptionConfiguration;
public StripeWebhook(SubscriptionsConfiguration subscriptionConfiguration, IServiceProvider serviceProvider) : base(serviceProvider)
{
this.subscriptionConfiguration = subscriptionConfiguration;
}
public StripeWebhook(IServiceProvider serviceProvider) : base(serviceProvider) { }

[HttpPost]
[IgnoreAntiforgeryToken]
Expand All @@ -28,11 +25,11 @@ public async Task<IActionResult> Index()
var stripeEvent = EventUtility.ParseEvent(json, false);
var signatureHeader = Request.Headers["Stripe-Signature"];
stripeEvent = EventUtility.ConstructEvent(json,
signatureHeader, subscriptionConfiguration.StripeEndpointSecret, throwOnApiVersionMismatch: false);
signatureHeader, module.SubscriptionsConfiguration.StripeEndpointSecret, throwOnApiVersionMismatch: false);

// Minimum Events copied from https://stripe.com/docs/billing/subscriptions/build-subscriptions
// Sent when a customer clicks the Pay or Subscribe button in Checkout, informing you of a new purchase. (Stripe)
if (stripeEvent.Type == Events.CheckoutSessionCompleted)
if (stripeEvent.Type == EventTypes.CheckoutSessionCompleted)
{
var session = stripeEvent.Data.Object as Stripe.Checkout.Session;

Expand All @@ -41,29 +38,29 @@ public async Task<IActionResult> Index()

var createTrialingSubscription = new CreateTrialingSubscription
{
UserId = Guid.Parse(userId),
ExecutingUserId = Guid.Parse(userId),
StripeCustomerId = subscription.CustomerId,
CreatedStripeSubscription = subscription
};

await commandDispatcher.DispatchAsync(createTrialingSubscription);
}
// Sent each billing interval when a payment succeeds. (Stripe)
else if (stripeEvent.Type == Events.InvoicePaid)
else if (stripeEvent.Type == EventTypes.InvoicePaid)
{
var invoice = stripeEvent.Data.Object as Invoice;

var subscription = await new SubscriptionService().GetAsync(invoice.SubscriptionId);

var updateSubscriptionPeriod = new UpdateSubscriptionPeriod
{

Subscription = subscription
};


await commandDispatcher.DispatchAsync(updateSubscriptionPeriod);
}
// Sent each billing interval if there is an issue with your customer’s payment method. (Stripe)
else if (stripeEvent.Type == Events.InvoicePaymentFailed)
else if (stripeEvent.Type == EventTypes.InvoicePaymentFailed)
{
var invoice = stripeEvent.Data.Object as Invoice;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
using Microsoft.EntityFrameworkCore;
using Shared.Features.Messaging.Command;
using Shared.Features.Domain.Exceptions;
using System.Threading;
using Shared.Features.Server;
using Shared.Kernel.Errors;
using Modules.TenantIdentity.Features.DomainFeatures.Tenants.Domain;

namespace Modules.TenantIdentity.Features.DomainFeatures.Tenants.Application.Commands
{
Expand All @@ -17,10 +18,10 @@ public DeleteTenantCommandHandler(IServiceProvider serviceProvider) : base(servi

public async Task HandleAsync(DeleteTenant command, CancellationToken cancellationToken)
{
var tenant = await module.TenantIdentityDbContext.Tenants.SingleAsync(t => t.TenantId == command.TenantId);
var tenant = await module.TenantIdentityDbContext.Tenants.SingleAsync(t => t.Id == command.TenantId);
if (tenant == null)
{
throw new NotFoundException();
throw Errors.NotFound(nameof(Tenant), command.TenantId);
}

tenant.ThrowIfUserCantDeleteTenant();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using Shared.Features.Server;
using System.Threading;

namespace Modules.TenantIdentity.Features.DomainFeatures.Tenants.Application.IntegrationEvents
namespace Modules.TenantIdentity.Features.DomainFeatures.Tenants.Application.EventHandlers
{
public class TenantSubscriptionUpdatedIntegrationEventHandler : ServerExecutionBase<TenantIdentityModule>, IIntegrationEventHandler<TenantSubscriptionPlanUpdatedIntegrationEvent>
{
Expand All @@ -13,7 +13,7 @@ public TenantSubscriptionUpdatedIntegrationEventHandler(IServiceProvider service
public async Task HandleAsync(TenantSubscriptionPlanUpdatedIntegrationEvent integrationEvent, CancellationToken cancellation)
{
var tenant = await module.TenantIdentityDbContext.Tenants.FirstAsync(tenant => tenant.Id == integrationEvent.TenantId);
tenant.SubscriptionPlanType = integrationEvent.SubscriptionPlanType;
tenant.UpdateSubscriptionPlan(integrationEvent.SubscriptionPlanType);

await module.TenantIdentityDbContext.SaveChangesAsync();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,15 @@

namespace Modules.TenantIdentity.Features.DomainFeatures.Tenants.Application.Queries
{
public class GetAllTenantMembershipsOfUser : Query<List<TenantMembershipDTO>>
{
public Guid UserId { get; set; }
}
public class GetAllTenantMembershipsOfUser : Query<List<TenantMembershipDTO>> { }

public class GetAllTenantMembershipsOfUserQueryHandler : ServerExecutionBase<TenantIdentityModule>, IQueryHandler<GetAllTenantMembershipsOfUser, List<TenantMembershipDTO>>
{
public GetAllTenantMembershipsOfUserQueryHandler(IServiceProvider serviceProvider) : base(serviceProvider) { }

public async Task<List<TenantMembershipDTO>> HandleAsync(GetAllTenantMembershipsOfUser query, CancellationToken cancellation)
{
var tenantMemberships = await module.TenantIdentityDbContext.TenantMeberships.Where(tm => tm.UserId == query.UserId).ToListAsync();
var tenantMemberships = await module.TenantIdentityDbContext.TenantMeberships.Where(tm => tm.UserId == query.ExecutingUserId).ToListAsync();
return tenantMemberships.Select(tm => tm.ToDTO()).ToList();
}
}
Expand Down
Loading

0 comments on commit 3205300

Please sign in to comment.