Merge remote-tracking branch 'origin/Devsights-changes'
This commit is contained in:
@@ -53,14 +53,14 @@ public class PresentationInfos
|
||||
[MaxLength(255)] public string PhoneNumber { get; set; } = string.Empty;
|
||||
[MaxLength(255)] public string Email { get; set; } = string.Empty;
|
||||
[MaxLength(2000)] public string Title { get; set; } = string.Empty;
|
||||
[MaxLength(2000)] public string MainImageUrl { get; set; } = string.Empty;
|
||||
[MaxLength(2000)] public string? MainImageUrl { get; set; } = string.Empty;
|
||||
[MaxLength(10000)] public string MainImageText { get; set; } = string.Empty;
|
||||
[MaxLength(10000)] public string MainVideoText { get; set; } = string.Empty;
|
||||
[MaxLength(2000)] public string ImagesSubtitle { get; set; } = string.Empty;
|
||||
[MaxLength(2000)] public string Image1Url { get; set; } = string.Empty;
|
||||
[MaxLength(2000)] public string Image2Url { get; set; } = string.Empty;
|
||||
[MaxLength(2000)] public string Image3Url { get; set; } = string.Empty;
|
||||
[MaxLength(2000)] public string Image4Url { get; set; } = string.Empty;
|
||||
[MaxLength(2000)] public string? Image1Url { get; set; } = string.Empty;
|
||||
[MaxLength(2000)] public string? Image2Url { get; set; } = string.Empty;
|
||||
[MaxLength(2000)] public string? Image3Url { get; set; } = string.Empty;
|
||||
[MaxLength(2000)] public string? Image4Url { get; set; } = string.Empty;
|
||||
[MaxLength(10000)] public string ImagesText { get; set; } = string.Empty;
|
||||
[MaxLength(2000)] public string VideoSubtitle { get; set; } = string.Empty;
|
||||
[MaxLength(2000)] public string VideoSubtitleMain { get; set; } = string.Empty;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Hutopy.Web.Features.Contents.Data;
|
||||
using Hutopy.Web.Common.BlobStorage;
|
||||
using Hutopy.Web.Features.Contents.Data;
|
||||
|
||||
namespace Hutopy.Web.Features.Contents.Handlers;
|
||||
|
||||
@@ -8,29 +9,37 @@ public record ChangePresentationInfosRequest(
|
||||
string? PhoneNumber,
|
||||
string? Email,
|
||||
string? Title,
|
||||
string? MainImageUrl,
|
||||
string? MainImageText,
|
||||
string? MainVideoText,
|
||||
string? ImagesSubtitle,
|
||||
string? Image1Url,
|
||||
string? Image2Url,
|
||||
string? Image3Url,
|
||||
string? Image4Url,
|
||||
string? ImagesText,
|
||||
string? VideoSubtitle,
|
||||
string? VideoSubtitleMain,
|
||||
string? VideoUrlMain,
|
||||
string? VideoUrl,
|
||||
string? VideoText);
|
||||
string? VideoText,
|
||||
string? MainImageUrl,
|
||||
string? Image1Url,
|
||||
string? Image2Url,
|
||||
string? Image3Url,
|
||||
string? Image4Url,
|
||||
IFormFile? MainImage,
|
||||
IFormFile? Image1,
|
||||
IFormFile? Image2,
|
||||
IFormFile? Image3,
|
||||
IFormFile? Image4);
|
||||
|
||||
[PublicAPI]
|
||||
public class ChangePresentationInfosHandler(
|
||||
ContentDbContext context)
|
||||
ContentDbContext context,
|
||||
AzureBlobStorage blobStorage)
|
||||
: Endpoint<ChangePresentationInfosRequest>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/api/creators/{CreatorId}/presentation-infos");
|
||||
Options(o => o.WithTags("Creators"));
|
||||
AllowFileUploads();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(
|
||||
@@ -40,30 +49,67 @@ public class ChangePresentationInfosHandler(
|
||||
var creator = await context
|
||||
.Creators
|
||||
.Include(c => c.PresentationInfos)
|
||||
.SingleAsync(
|
||||
.SingleOrDefaultAsync(
|
||||
c => c.Id == request.CreatorId,
|
||||
cancellationToken: ct);
|
||||
|
||||
creator.PresentationInfos.PhoneNumber = request.PhoneNumber ?? "";
|
||||
creator.PresentationInfos.Email = request.Email ?? "";
|
||||
creator.PresentationInfos.Title = request.Title ?? "";
|
||||
creator.PresentationInfos.MainImageUrl = request.MainImageUrl ?? "";
|
||||
creator.PresentationInfos.MainImageText = request.MainImageText ?? "";
|
||||
creator.PresentationInfos.MainVideoText = request.MainVideoText ?? "";
|
||||
creator.PresentationInfos.ImagesSubtitle = request.ImagesSubtitle ?? "";
|
||||
creator.PresentationInfos.Image1Url = request.Image1Url ?? "";
|
||||
creator.PresentationInfos.Image2Url = request.Image2Url ?? "";
|
||||
creator.PresentationInfos.Image3Url = request.Image3Url ?? "";
|
||||
creator.PresentationInfos.Image4Url = request.Image4Url ?? "";
|
||||
creator.PresentationInfos.ImagesText = request.ImagesText ?? "";
|
||||
creator.PresentationInfos.VideoSubtitle = request.VideoSubtitle ?? "";
|
||||
creator.PresentationInfos.VideoSubtitleMain = request.VideoSubtitleMain ?? "";
|
||||
creator.PresentationInfos.VideoUrlMain = request.VideoUrlMain ?? "";
|
||||
creator.PresentationInfos.VideoUrl = request.VideoUrl ?? "";
|
||||
creator.PresentationInfos.VideoText = request.VideoText ?? "";
|
||||
|
||||
await context.SaveChangesAsync(ct);
|
||||
if (creator is null)
|
||||
{
|
||||
await SendNotFoundAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
async Task<string> UploadFileOrDefaultAsync(
|
||||
IFormFile? file,
|
||||
string subDirectory,
|
||||
string fileName,
|
||||
string? newUrl)
|
||||
{
|
||||
if (newUrl == "")
|
||||
return "";
|
||||
|
||||
if (file != null)
|
||||
{
|
||||
return await blobStorage.UploadFileAsync(
|
||||
ContainerNames.Creators,
|
||||
$"{request.CreatorId}/{subDirectory}/{fileName}",
|
||||
file.OpenReadStream(),
|
||||
file.ContentType,
|
||||
ct);
|
||||
}
|
||||
|
||||
return newUrl?.Trim() ?? "";
|
||||
}
|
||||
|
||||
creator.PresentationInfos.MainImageUrl = await UploadFileOrDefaultAsync(
|
||||
request.MainImage, "Profile", "MainImage", request.MainImageUrl);
|
||||
|
||||
creator.PresentationInfos.Image1Url = await UploadFileOrDefaultAsync(
|
||||
request.Image1, "Profile", "Image1", request.Image1Url);
|
||||
|
||||
creator.PresentationInfos.Image2Url = await UploadFileOrDefaultAsync(
|
||||
request.Image2, "Profile", "Image2", request.Image2Url);
|
||||
|
||||
creator.PresentationInfos.Image3Url = await UploadFileOrDefaultAsync(
|
||||
request.Image3, "Profile", "Image3", request.Image3Url);
|
||||
|
||||
creator.PresentationInfos.Image4Url = await UploadFileOrDefaultAsync(
|
||||
request.Image4, "Profile", "Image4", request.Image4Url);
|
||||
|
||||
creator.PresentationInfos.PhoneNumber = request.PhoneNumber?.Trim() ?? "";
|
||||
creator.PresentationInfos.Email = request.Email?.Trim() ?? "";
|
||||
creator.PresentationInfos.Title = request.Title?.Trim() ?? "";
|
||||
creator.PresentationInfos.MainImageText = request.MainImageText?.Trim() ?? "";
|
||||
creator.PresentationInfos.MainVideoText = request.MainVideoText?.Trim() ?? "";
|
||||
creator.PresentationInfos.ImagesSubtitle = request.ImagesSubtitle?.Trim() ?? "";
|
||||
creator.PresentationInfos.ImagesText = request.ImagesText?.Trim() ?? "";
|
||||
creator.PresentationInfos.VideoSubtitle = request.VideoSubtitle?.Trim() ?? "";
|
||||
creator.PresentationInfos.VideoSubtitleMain = request.VideoSubtitleMain?.Trim() ?? "";
|
||||
creator.PresentationInfos.VideoUrlMain = request.VideoUrlMain?.Trim() ?? "";
|
||||
creator.PresentationInfos.VideoUrl = request.VideoUrl?.Trim() ?? "";
|
||||
creator.PresentationInfos.VideoText = request.VideoText?.Trim() ?? "";
|
||||
|
||||
await context.SaveChangesAsync(ct);
|
||||
await SendOkAsync(ct);
|
||||
}
|
||||
}
|
||||
|
||||
292
src/Web/Features/Memberships/Data/Migrations/20241216215210_UpdateSeedData.Designer.cs
generated
Normal file
292
src/Web/Features/Memberships/Data/Migrations/20241216215210_UpdateSeedData.Designer.cs
generated
Normal file
@@ -0,0 +1,292 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Hutopy.Web.Features.Memberships.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Hutopy.Web.Features.Memberships.Data.Migrations
|
||||
{
|
||||
[DbContext(typeof(MembershipDbContext))]
|
||||
[Migration("20241216215210_UpdateSeedData")]
|
||||
partial class UpdateSeedData
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasDefaultSchema("Membership")
|
||||
.HasAnnotation("ProductVersion", "8.0.10")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Memberships.Data.Creator", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("PortraitUrl")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("StripeAccountId")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Creators", "Membership");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Memberships.Data.Subscription", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP");
|
||||
|
||||
b.Property<Guid>("CreatorId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTimeOffset?>("EndDate")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<DateTimeOffset>("StartDate")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("StripeSessionId")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("character varying(255)");
|
||||
|
||||
b.Property<string>("StripeSubscriptionId")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("character varying(255)");
|
||||
|
||||
b.Property<Guid>("TierId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CreatorId");
|
||||
|
||||
b.HasIndex("TierId");
|
||||
|
||||
b.ToTable("Subscriptions", "Membership");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Memberships.Data.Tier", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP");
|
||||
|
||||
b.Property<Guid>("CreatorId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("CurrencyCode")
|
||||
.IsRequired()
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.IsRequired()
|
||||
.HasMaxLength(4096)
|
||||
.HasColumnType("character varying(4096)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b.Property<decimal>("Price")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<string>("StripePriceId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b.Property<string>("StripeProductId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CreatorId");
|
||||
|
||||
b.ToTable("Tiers", "Membership");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Memberships.Data.Tip", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<decimal>("Amount")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP");
|
||||
|
||||
b.Property<Guid>("CreatorId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("CreatorName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Currency")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Message")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("StripeSessionId")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid>("TipperId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("TipperName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid>("TransactionId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("TransactionId");
|
||||
|
||||
b.ToTable("Tips", "Membership");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Memberships.Data.Transaction", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<decimal>("Amount")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP");
|
||||
|
||||
b.Property<string>("Currency")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("StripeInvoiceUrl")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid?>("SubscriptionId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime>("Timestamp")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("Type")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("SubscriptionId");
|
||||
|
||||
b.ToTable("Transactions", "Membership");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Memberships.Data.Subscription", b =>
|
||||
{
|
||||
b.HasOne("Hutopy.Web.Features.Memberships.Data.Creator", "Creator")
|
||||
.WithMany()
|
||||
.HasForeignKey("CreatorId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Hutopy.Web.Features.Memberships.Data.Tier", "Tier")
|
||||
.WithMany("Subscriptions")
|
||||
.HasForeignKey("TierId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Creator");
|
||||
|
||||
b.Navigation("Tier");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Memberships.Data.Tier", b =>
|
||||
{
|
||||
b.HasOne("Hutopy.Web.Features.Memberships.Data.Creator", "Creator")
|
||||
.WithMany()
|
||||
.HasForeignKey("CreatorId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Creator");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Memberships.Data.Tip", b =>
|
||||
{
|
||||
b.HasOne("Hutopy.Web.Features.Memberships.Data.Transaction", "Transaction")
|
||||
.WithMany()
|
||||
.HasForeignKey("TransactionId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Transaction");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Memberships.Data.Transaction", b =>
|
||||
{
|
||||
b.HasOne("Hutopy.Web.Features.Memberships.Data.Subscription", null)
|
||||
.WithMany("Transactions")
|
||||
.HasForeignKey("SubscriptionId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Memberships.Data.Subscription", b =>
|
||||
{
|
||||
b.Navigation("Transactions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Memberships.Data.Tier", b =>
|
||||
{
|
||||
b.Navigation("Subscriptions");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Hutopy.Web.Features.Memberships.Data.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class UpdateSeedData : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
52
src/Web/Features/Memberships/Handlers/ChangeStripeId.cs
Normal file
52
src/Web/Features/Memberships/Handlers/ChangeStripeId.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using Hutopy.Web.Common.Security;
|
||||
using Hutopy.Web.Features.Memberships.Data;
|
||||
using Hutopy.Web.Features.Memberships.Infrastructure;
|
||||
|
||||
namespace Hutopy.Web.Features.Memberships.Handlers;
|
||||
|
||||
[PublicAPI]
|
||||
public record struct ChangeStripeIdRequest(
|
||||
string StripeAccountId);
|
||||
|
||||
public class ChangeStripeIdHandler(
|
||||
MembershipDbContext dbContext,
|
||||
StripeService stripeService)
|
||||
: Endpoint<ChangeStripeIdRequest>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/api/creators/stripe-account");
|
||||
Options(o => o.WithTags("Memberships"));
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(
|
||||
ChangeStripeIdRequest req,
|
||||
CancellationToken ct)
|
||||
{
|
||||
var creatorId = HttpContext.User.GetUserId();
|
||||
|
||||
var creator = await dbContext
|
||||
.Creators
|
||||
.FindAsync(
|
||||
[creatorId],
|
||||
cancellationToken: ct);
|
||||
|
||||
if (creator is null)
|
||||
{
|
||||
creator = new Creator
|
||||
{
|
||||
Id = creatorId,
|
||||
Name = HttpContext.User.GetAlias() ?? creatorId.ToString()
|
||||
};
|
||||
|
||||
await dbContext.AddAsync(creator, ct);
|
||||
}
|
||||
|
||||
creator.StripeAccountId = req.StripeAccountId;
|
||||
creator.PortraitUrl = HttpContext.User.GetPortraitUrl();
|
||||
|
||||
await dbContext.SaveChangesAsync(ct);
|
||||
|
||||
await SendOkAsync(creator.Id, ct);
|
||||
}
|
||||
}
|
||||
@@ -51,6 +51,8 @@ public class SendTipHandler(
|
||||
{
|
||||
Post("/api/tips");
|
||||
Options(o => o.WithTags("Memberships"));
|
||||
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(
|
||||
@@ -68,8 +70,6 @@ public class SendTipHandler(
|
||||
}
|
||||
|
||||
var checkoutSession = await stripeService.CreateTipCheckoutSessionAsync(
|
||||
User.GetUserId(),
|
||||
User.GetAlias()!,
|
||||
creator.Id,
|
||||
creator.Name,
|
||||
req.Amount,
|
||||
@@ -77,7 +77,8 @@ public class SendTipHandler(
|
||||
req.Message,
|
||||
creator.StripeAccountId,
|
||||
req.CheckoutSuccessUrl,
|
||||
req.CheckoutCancelledUrl);
|
||||
req.CheckoutCancelledUrl
|
||||
);
|
||||
|
||||
await SendAsync(
|
||||
new SendTipResponse("Pending", checkoutSession.Url),
|
||||
|
||||
@@ -55,8 +55,6 @@ public sealed class StripeService(
|
||||
}
|
||||
|
||||
public async Task<Session> CreateTipCheckoutSessionAsync(
|
||||
Guid tipperId,
|
||||
string tipperName,
|
||||
Guid creatorId,
|
||||
string creatorName,
|
||||
decimal amount,
|
||||
@@ -72,10 +70,7 @@ public sealed class StripeService(
|
||||
// Create Stripe customer for the user if not already created
|
||||
var customerService = new CustomerService();
|
||||
var customer = await customerService.CreateAsync(
|
||||
new CustomerCreateOptions
|
||||
{
|
||||
Metadata = new Dictionary<string, string> { { "userId", tipperId.ToString() } }
|
||||
},
|
||||
new CustomerCreateOptions{},
|
||||
cancellationToken: ct);
|
||||
|
||||
// Create paymentIntent for the user
|
||||
@@ -116,8 +111,6 @@ public sealed class StripeService(
|
||||
CancelUrl = cancelUrl, // Redirect after canceled payment
|
||||
Metadata = new Dictionary<string, string>
|
||||
{
|
||||
{ "tipperId", tipperId.ToString() },
|
||||
{ "tipperName", tipperName },
|
||||
{ "creatorId", creatorId.ToString() },
|
||||
{ "creatorName", creatorName },
|
||||
{ "message", message },
|
||||
|
||||
70
src/Web/Features/Messages/Data/Migrations/20241217225954_ChangeStripeId.Designer.cs
generated
Normal file
70
src/Web/Features/Messages/Data/Migrations/20241217225954_ChangeStripeId.Designer.cs
generated
Normal file
@@ -0,0 +1,70 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Hutopy.Web.Features.Messages.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Hutopy.Web.Features.Messages.Migrations
|
||||
{
|
||||
[DbContext(typeof(MessagingDbContext))]
|
||||
[Migration("20241217225954_ChangeStripeId")]
|
||||
partial class ChangeStripeId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasDefaultSchema("Messaging")
|
||||
.HasAnnotation("ProductVersion", "8.0.10")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Messages.Data.Message", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP");
|
||||
|
||||
b.Property<Guid>("CreatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("CreatedByName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("character varying(255)");
|
||||
|
||||
b.Property<string>("CreatedByPortraitUrl")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("character varying(255)");
|
||||
|
||||
b.Property<Guid?>("ParentId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<Guid>("SubjectId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.IsRequired()
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Messages", "Messaging");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Hutopy.Web.Features.Messages.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class ChangeStripeId : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Value",
|
||||
schema: "Messaging",
|
||||
table: "Messages",
|
||||
type: "character varying(2048)",
|
||||
maxLength: 2048,
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "text");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Value",
|
||||
schema: "Messaging",
|
||||
table: "Messages",
|
||||
type: "text",
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "character varying(2048)",
|
||||
oldMaxLength: 2048);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ namespace Hutopy.Web.Features.Messages.Migrations
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasDefaultSchema("Messaging")
|
||||
.HasAnnotation("ProductVersion", "8.0.4")
|
||||
.HasAnnotation("ProductVersion", "8.0.10")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
@@ -54,7 +54,8 @@ namespace Hutopy.Web.Features.Messages.Migrations
|
||||
|
||||
b.Property<string>("Value")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
using Hutopy.Web.Features.Users.Handlers.Models;
|
||||
using Hutopy.Web.Features.Memberships.Data;
|
||||
using Hutopy.Web.Features.Memberships.Infrastructure;
|
||||
|
||||
namespace Hutopy.Web.Features.Users.Handlers;
|
||||
|
||||
[PublicAPI]
|
||||
public class GetCurrentUserQueryHandler(
|
||||
IdentityService identityService)
|
||||
IdentityService identityService,
|
||||
MembershipDbContext membershipDbContext)
|
||||
: EndpointWithoutRequest<UserDto>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/api/users/profile");
|
||||
Options(o => o.WithTags("Users"));
|
||||
Options(o => o.WithTags("Memberships"));
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(
|
||||
@@ -26,6 +29,12 @@ public class GetCurrentUserQueryHandler(
|
||||
|
||||
var roles = await identityService.GetCurrentUserRolesAsync();
|
||||
|
||||
var stripeId = await membershipDbContext
|
||||
.Creators
|
||||
.Where(c => c.Id == userModel.Id)
|
||||
.Select(c => c.StripeAccountId)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
await SendOkAsync(
|
||||
new UserDto
|
||||
{
|
||||
@@ -40,6 +49,7 @@ public class GetCurrentUserQueryHandler(
|
||||
BirthDate = userModel.BirthDate,
|
||||
Address = userModel.Address,
|
||||
UserRoles = roles,
|
||||
StripeId = stripeId ?? string.Empty
|
||||
},
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
@@ -13,4 +13,5 @@ public class UserDto
|
||||
public string? PhoneNumber { get; init; }
|
||||
public DateTime? BirthDate { get; init; }
|
||||
public string? Address { get; init; }
|
||||
public string? StripeId { get; init; }
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
using Hutopy.Web.Common;
|
||||
using Hutopy.Web.Features.Contents.Data;
|
||||
using ContentCreator = Hutopy.Web.Features.Contents.Data.Creator;
|
||||
using Hutopy.Web.Features.Memberships.Data;
|
||||
using MembershipCreator = Hutopy.Web.Features.Memberships.Data.Creator;
|
||||
using Hutopy.Web.Features.Messages.Data;
|
||||
using Hutopy.Web.Features.Users;
|
||||
|
||||
@@ -16,7 +19,8 @@ public static class WebApplicationExtensions
|
||||
var seeder = new TestDataSeeder(
|
||||
scope.ServiceProvider.GetRequiredService<ApplicationUserManager>(),
|
||||
scope.ServiceProvider.GetRequiredService<ContentDbContext>(),
|
||||
scope.ServiceProvider.GetRequiredService<MessagingDbContext>());
|
||||
scope.ServiceProvider.GetRequiredService<MessagingDbContext>(),
|
||||
scope.ServiceProvider.GetRequiredService<MembershipDbContext>());
|
||||
|
||||
await seeder.SeedAsync();
|
||||
}
|
||||
@@ -25,7 +29,8 @@ public static class WebApplicationExtensions
|
||||
internal class TestDataSeeder(
|
||||
ApplicationUserManager userManager,
|
||||
ContentDbContext contentContext,
|
||||
MessagingDbContext messagingContext)
|
||||
MessagingDbContext messagingContext,
|
||||
MembershipDbContext membershipContext)
|
||||
{
|
||||
private const string DefaultPassword = "Test123#";
|
||||
|
||||
@@ -65,11 +70,23 @@ internal class TestDataSeeder(
|
||||
|
||||
await messagingContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
// convert to MembershipCreator
|
||||
var membershipCreator = new MembershipCreator
|
||||
{
|
||||
Id = creator.Id,
|
||||
Name = creator.Name,
|
||||
StripeAccountId = Guid.NewGuid().ToString(),
|
||||
PortraitUrl = creator.Images.Logo,
|
||||
};
|
||||
|
||||
await membershipContext.Creators.AddAsync(membershipCreator);
|
||||
await membershipContext.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private List<Content> GenerateContent(
|
||||
Creator creator,
|
||||
ContentCreator creator,
|
||||
int contentCount)
|
||||
{
|
||||
var currentDate = DateTimeOffset.UtcNow;
|
||||
@@ -191,7 +208,7 @@ internal class TestDataSeeder(
|
||||
[
|
||||
];
|
||||
|
||||
private readonly static Creator HutopyCreator = new()
|
||||
private readonly static ContentCreator HutopyCreator = new()
|
||||
{
|
||||
Name = "hutopy",
|
||||
Title = "Page officielle",
|
||||
@@ -222,7 +239,7 @@ internal class TestDataSeeder(
|
||||
}
|
||||
};
|
||||
|
||||
private readonly static Creator ArpsCreator = new()
|
||||
private readonly static ContentCreator ArpsCreator = new()
|
||||
{
|
||||
Name = "arps",
|
||||
Title = "Créateur de contenu",
|
||||
@@ -255,7 +272,7 @@ internal class TestDataSeeder(
|
||||
}
|
||||
};
|
||||
|
||||
private readonly static Creator ChloeBeaugrandCreator = new()
|
||||
private readonly static ContentCreator ChloeBeaugrandCreator = new()
|
||||
{
|
||||
Name = "chloebeaugrand",
|
||||
Title = "Page officielle",
|
||||
@@ -285,7 +302,7 @@ internal class TestDataSeeder(
|
||||
}
|
||||
};
|
||||
|
||||
private readonly static Creator GuillaumeMCreator = new()
|
||||
private readonly static ContentCreator GuillaumeMCreator = new()
|
||||
{
|
||||
Name = "guillaumem",
|
||||
Title = "Page officielle",
|
||||
@@ -317,7 +334,7 @@ internal class TestDataSeeder(
|
||||
}
|
||||
};
|
||||
|
||||
private readonly static Creator LeffetCreator = new()
|
||||
private readonly static ContentCreator LeffetCreator = new()
|
||||
{
|
||||
Name = "leffet",
|
||||
Title = "Page officielle",
|
||||
@@ -348,7 +365,7 @@ internal class TestDataSeeder(
|
||||
}
|
||||
};
|
||||
|
||||
private readonly static Creator MathieuCaron = new()
|
||||
private readonly static ContentCreator MathieuCaron = new()
|
||||
{
|
||||
Name = "mathieucaron",
|
||||
Title = "Page officielle",
|
||||
@@ -378,7 +395,7 @@ internal class TestDataSeeder(
|
||||
}
|
||||
};
|
||||
|
||||
private readonly Creator[] _creators =
|
||||
private readonly ContentCreator[] _creators =
|
||||
[
|
||||
HutopyCreator,
|
||||
ArpsCreator,
|
||||
|
||||
Reference in New Issue
Block a user