From e50831a1e9907eeeebdfacd2563e70e7fdd3489c Mon Sep 17 00:00:00 2001 From: Carl-Johnsons Date: Thu, 11 Jun 2026 12:49:12 +0700 Subject: [PATCH 01/14] fix: #258 --- .../DuendeIdentityServer/AppCommandHandler.cs | 3 + .../DuendeIdentityServer.csproj | 7 +- .../DuendeIdentityServer/HostingExtensions.cs | 10 + .../DependencyInjection.cs | 8 + .../IdentityService.Infrastructure.csproj | 1 + .../Persistence/ApplicationDbContext.cs | 3 +- ...erverPersistedGrantDbMigration.Designer.cs | 270 ++++++++++++++++++ ...IdentityServerPersistedGrantDbMigration.cs | 209 ++++++++++++++ .../PersistedGrantDbContextModelSnapshot.cs | 267 +++++++++++++++++ 9 files changed, 774 insertions(+), 4 deletions(-) create mode 100644 app/server/IdentityService/src/IdentityService.Infrastructure/Persistence/IdentityServer/PersistedGrant/20260611045123_InitialIdentityServerPersistedGrantDbMigration.Designer.cs create mode 100644 app/server/IdentityService/src/IdentityService.Infrastructure/Persistence/IdentityServer/PersistedGrant/20260611045123_InitialIdentityServerPersistedGrantDbMigration.cs create mode 100644 app/server/IdentityService/src/IdentityService.Infrastructure/Persistence/IdentityServer/PersistedGrant/PersistedGrantDbContextModelSnapshot.cs diff --git a/app/server/IdentityService/src/DuendeIdentityServer/AppCommandHandler.cs b/app/server/IdentityService/src/DuendeIdentityServer/AppCommandHandler.cs index 31ed0458e..9470280f6 100755 --- a/app/server/IdentityService/src/DuendeIdentityServer/AppCommandHandler.cs +++ b/app/server/IdentityService/src/DuendeIdentityServer/AppCommandHandler.cs @@ -1,4 +1,6 @@ using Contract.Constants; +using Microsoft.EntityFrameworkCore; +using Duende.IdentityServer.EntityFramework.DbContexts; using IdentityService.Domain.Interfaces; using IdentityService.Infrastructure; @@ -29,6 +31,7 @@ public static async Task TryHandleAsync(this WebApplicationBuilder builder { case COMMAND_ARGS.MIGRATE: dbContext.MigrateDb(sp); + sp.GetRequiredService().Database.Migrate(); break; case COMMAND_ARGS.SEED: dbContext.SeedDb(sp).GetAwaiter().GetResult(); diff --git a/app/server/IdentityService/src/DuendeIdentityServer/DuendeIdentityServer.csproj b/app/server/IdentityService/src/DuendeIdentityServer/DuendeIdentityServer.csproj index 37077aff8..fe6a84671 100755 --- a/app/server/IdentityService/src/DuendeIdentityServer/DuendeIdentityServer.csproj +++ b/app/server/IdentityService/src/DuendeIdentityServer/DuendeIdentityServer.csproj @@ -24,7 +24,6 @@ - @@ -34,7 +33,11 @@ - + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/app/server/IdentityService/src/DuendeIdentityServer/HostingExtensions.cs b/app/server/IdentityService/src/DuendeIdentityServer/HostingExtensions.cs index 0e3a97c38..809d76285 100755 --- a/app/server/IdentityService/src/DuendeIdentityServer/HostingExtensions.cs +++ b/app/server/IdentityService/src/DuendeIdentityServer/HostingExtensions.cs @@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.HttpOverrides; +using Microsoft.EntityFrameworkCore; using Newtonsoft.Json; namespace DuendeIdentityServer; @@ -68,6 +69,15 @@ public static WebApplication ConfigureServices(this WebApplicationBuilder builde // keep old key for 7 days in discovery for validation of tokens options.KeyManagement.RetentionDuration = TimeSpan.FromDays(7); }) + .AddOperationalStore(options => + { + options.ConfigureDbContext = builder => + builder.UseNpgsql(EnvUtility.GetConnectionString(), + sql => sql.MigrationsAssembly("IdentityService.Infrastructure")); + + options.EnableTokenCleanup = true; + options.TokenCleanupInterval = 3600; + }) .AddInMemoryIdentityResources(Config.IdentityResources) .AddInMemoryApiScopes(Config.ApiScopes) .AddInMemoryClients(Config.Clients) diff --git a/app/server/IdentityService/src/IdentityService.Infrastructure/DependencyInjection.cs b/app/server/IdentityService/src/IdentityService.Infrastructure/DependencyInjection.cs index 8fac6d386..2357b99ca 100644 --- a/app/server/IdentityService/src/IdentityService.Infrastructure/DependencyInjection.cs +++ b/app/server/IdentityService/src/IdentityService.Infrastructure/DependencyInjection.cs @@ -30,6 +30,14 @@ public static IServiceCollection AddMinimalInfrastructureServices(this IServiceC AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true); services.AddDbContext(options => options.UseNpgsql(Contract.Utilities.EnvUtility.GetConnectionString())); + services.AddIdentityServer() + .AddOperationalStore(options => + { + options.ConfigureDbContext = b => + b.UseNpgsql( + Contract.Utilities.EnvUtility.GetConnectionString(), + sql => sql.MigrationsAssembly("IdentityService.Infrastructure")); + }); services.AddIdentity() .AddEntityFrameworkStores() .AddDefaultTokenProviders(); diff --git a/app/server/IdentityService/src/IdentityService.Infrastructure/IdentityService.Infrastructure.csproj b/app/server/IdentityService/src/IdentityService.Infrastructure/IdentityService.Infrastructure.csproj index 0f0d6f71f..63b595dd4 100644 --- a/app/server/IdentityService/src/IdentityService.Infrastructure/IdentityService.Infrastructure.csproj +++ b/app/server/IdentityService/src/IdentityService.Infrastructure/IdentityService.Infrastructure.csproj @@ -8,6 +8,7 @@ + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/app/server/IdentityService/src/IdentityService.Infrastructure/Persistence/ApplicationDbContext.cs b/app/server/IdentityService/src/IdentityService.Infrastructure/Persistence/ApplicationDbContext.cs index e2c55ee08..d9f26fa95 100644 --- a/app/server/IdentityService/src/IdentityService.Infrastructure/Persistence/ApplicationDbContext.cs +++ b/app/server/IdentityService/src/IdentityService.Infrastructure/Persistence/ApplicationDbContext.cs @@ -26,8 +26,7 @@ public ApplicationDbContext(DbContextOptions options) public void MigrateDb(IServiceProvider serviceProvider) { - var db = serviceProvider.GetRequiredService(); - db.Database.Migrate(); + serviceProvider.GetRequiredService().Database.Migrate(); Console.WriteLine("✅ Database migrated successfully."); } diff --git a/app/server/IdentityService/src/IdentityService.Infrastructure/Persistence/IdentityServer/PersistedGrant/20260611045123_InitialIdentityServerPersistedGrantDbMigration.Designer.cs b/app/server/IdentityService/src/IdentityService.Infrastructure/Persistence/IdentityServer/PersistedGrant/20260611045123_InitialIdentityServerPersistedGrantDbMigration.Designer.cs new file mode 100644 index 000000000..e60bbb15d --- /dev/null +++ b/app/server/IdentityService/src/IdentityService.Infrastructure/Persistence/IdentityServer/PersistedGrant/20260611045123_InitialIdentityServerPersistedGrantDbMigration.Designer.cs @@ -0,0 +1,270 @@ +// +using System; +using Duende.IdentityServer.EntityFramework.DbContexts; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace IdentityService.Infrastructure.Persistence.IdentityServer.PersistedGrant +{ + [DbContext(typeof(PersistedGrantDbContext))] + [Migration("20260611045123_InitialIdentityServerPersistedGrantDbMigration")] + partial class InitialIdentityServerPersistedGrantDbMigration + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.11") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Duende.IdentityServer.EntityFramework.Entities.DeviceFlowCodes", b => + { + b.Property("UserCode") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone"); + + b.Property("Data") + .IsRequired() + .HasMaxLength(50000) + .HasColumnType("character varying(50000)"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("DeviceCode") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Expiration") + .IsRequired() + .HasColumnType("timestamp without time zone"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("SubjectId") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.HasKey("UserCode"); + + b.HasIndex("DeviceCode") + .IsUnique(); + + b.HasIndex("Expiration"); + + b.ToTable("DeviceCodes", (string)null); + }); + + modelBuilder.Entity("Duende.IdentityServer.EntityFramework.Entities.Key", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Algorithm") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Created") + .HasColumnType("timestamp without time zone"); + + b.Property("Data") + .IsRequired() + .HasColumnType("text"); + + b.Property("DataProtected") + .HasColumnType("boolean"); + + b.Property("IsX509Certificate") + .HasColumnType("boolean"); + + b.Property("Use") + .HasColumnType("text"); + + b.Property("Version") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("Use"); + + b.ToTable("Keys", (string)null); + }); + + modelBuilder.Entity("Duende.IdentityServer.EntityFramework.Entities.PersistedGrant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ConsumedTime") + .HasColumnType("timestamp without time zone"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone"); + + b.Property("Data") + .IsRequired() + .HasMaxLength(50000) + .HasColumnType("character varying(50000)"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Expiration") + .HasColumnType("timestamp without time zone"); + + b.Property("Key") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("SubjectId") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Id"); + + b.HasIndex("ConsumedTime"); + + b.HasIndex("Expiration"); + + b.HasIndex("Key") + .IsUnique(); + + b.HasIndex("SubjectId", "ClientId", "Type"); + + b.HasIndex("SubjectId", "SessionId", "Type"); + + b.ToTable("PersistedGrants", (string)null); + }); + + modelBuilder.Entity("Duende.IdentityServer.EntityFramework.Entities.PushedAuthorizationRequest", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ExpiresAtUtc") + .HasColumnType("timestamp without time zone"); + + b.Property("Parameters") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReferenceValueHash") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.HasKey("Id"); + + b.HasIndex("ExpiresAtUtc"); + + b.HasIndex("ReferenceValueHash") + .IsUnique(); + + b.ToTable("PushedAuthorizationRequests", (string)null); + }); + + modelBuilder.Entity("Duende.IdentityServer.EntityFramework.Entities.ServerSideSession", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("timestamp without time zone"); + + b.Property("Data") + .IsRequired() + .HasColumnType("text"); + + b.Property("DisplayName") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Expires") + .HasColumnType("timestamp without time zone"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Renewed") + .HasColumnType("timestamp without time zone"); + + b.Property("Scheme") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("SubjectId") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("DisplayName"); + + b.HasIndex("Expires"); + + b.HasIndex("Key") + .IsUnique(); + + b.HasIndex("SessionId"); + + b.HasIndex("SubjectId"); + + b.ToTable("ServerSideSessions", (string)null); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/app/server/IdentityService/src/IdentityService.Infrastructure/Persistence/IdentityServer/PersistedGrant/20260611045123_InitialIdentityServerPersistedGrantDbMigration.cs b/app/server/IdentityService/src/IdentityService.Infrastructure/Persistence/IdentityServer/PersistedGrant/20260611045123_InitialIdentityServerPersistedGrantDbMigration.cs new file mode 100644 index 000000000..6f23ca045 --- /dev/null +++ b/app/server/IdentityService/src/IdentityService.Infrastructure/Persistence/IdentityServer/PersistedGrant/20260611045123_InitialIdentityServerPersistedGrantDbMigration.cs @@ -0,0 +1,209 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace IdentityService.Infrastructure.Persistence.IdentityServer.PersistedGrant +{ + /// + public partial class InitialIdentityServerPersistedGrantDbMigration : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "DeviceCodes", + columns: table => new + { + UserCode = table.Column(type: "character varying(200)", maxLength: 200, nullable: false), + DeviceCode = table.Column(type: "character varying(200)", maxLength: 200, nullable: false), + SubjectId = table.Column(type: "character varying(200)", maxLength: 200, nullable: true), + SessionId = table.Column(type: "character varying(100)", maxLength: 100, nullable: true), + ClientId = table.Column(type: "character varying(200)", maxLength: 200, nullable: false), + Description = table.Column(type: "character varying(200)", maxLength: 200, nullable: true), + CreationTime = table.Column(type: "timestamp without time zone", nullable: false), + Expiration = table.Column(type: "timestamp without time zone", nullable: false), + Data = table.Column(type: "character varying(50000)", maxLength: 50000, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_DeviceCodes", x => x.UserCode); + }); + + migrationBuilder.CreateTable( + name: "Keys", + columns: table => new + { + Id = table.Column(type: "text", nullable: false), + Version = table.Column(type: "integer", nullable: false), + Created = table.Column(type: "timestamp without time zone", nullable: false), + Use = table.Column(type: "text", nullable: true), + Algorithm = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), + IsX509Certificate = table.Column(type: "boolean", nullable: false), + DataProtected = table.Column(type: "boolean", nullable: false), + Data = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Keys", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "PersistedGrants", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Key = table.Column(type: "character varying(200)", maxLength: 200, nullable: true), + Type = table.Column(type: "character varying(50)", maxLength: 50, nullable: false), + SubjectId = table.Column(type: "character varying(200)", maxLength: 200, nullable: true), + SessionId = table.Column(type: "character varying(100)", maxLength: 100, nullable: true), + ClientId = table.Column(type: "character varying(200)", maxLength: 200, nullable: false), + Description = table.Column(type: "character varying(200)", maxLength: 200, nullable: true), + CreationTime = table.Column(type: "timestamp without time zone", nullable: false), + Expiration = table.Column(type: "timestamp without time zone", nullable: true), + ConsumedTime = table.Column(type: "timestamp without time zone", nullable: true), + Data = table.Column(type: "character varying(50000)", maxLength: 50000, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_PersistedGrants", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "PushedAuthorizationRequests", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + ReferenceValueHash = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), + ExpiresAtUtc = table.Column(type: "timestamp without time zone", nullable: false), + Parameters = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_PushedAuthorizationRequests", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "ServerSideSessions", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Key = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), + Scheme = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), + SubjectId = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), + SessionId = table.Column(type: "character varying(100)", maxLength: 100, nullable: true), + DisplayName = table.Column(type: "character varying(100)", maxLength: 100, nullable: true), + Created = table.Column(type: "timestamp without time zone", nullable: false), + Renewed = table.Column(type: "timestamp without time zone", nullable: false), + Expires = table.Column(type: "timestamp without time zone", nullable: true), + Data = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ServerSideSessions", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_DeviceCodes_DeviceCode", + table: "DeviceCodes", + column: "DeviceCode", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_DeviceCodes_Expiration", + table: "DeviceCodes", + column: "Expiration"); + + migrationBuilder.CreateIndex( + name: "IX_Keys_Use", + table: "Keys", + column: "Use"); + + migrationBuilder.CreateIndex( + name: "IX_PersistedGrants_ConsumedTime", + table: "PersistedGrants", + column: "ConsumedTime"); + + migrationBuilder.CreateIndex( + name: "IX_PersistedGrants_Expiration", + table: "PersistedGrants", + column: "Expiration"); + + migrationBuilder.CreateIndex( + name: "IX_PersistedGrants_Key", + table: "PersistedGrants", + column: "Key", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_PersistedGrants_SubjectId_ClientId_Type", + table: "PersistedGrants", + columns: new[] { "SubjectId", "ClientId", "Type" }); + + migrationBuilder.CreateIndex( + name: "IX_PersistedGrants_SubjectId_SessionId_Type", + table: "PersistedGrants", + columns: new[] { "SubjectId", "SessionId", "Type" }); + + migrationBuilder.CreateIndex( + name: "IX_PushedAuthorizationRequests_ExpiresAtUtc", + table: "PushedAuthorizationRequests", + column: "ExpiresAtUtc"); + + migrationBuilder.CreateIndex( + name: "IX_PushedAuthorizationRequests_ReferenceValueHash", + table: "PushedAuthorizationRequests", + column: "ReferenceValueHash", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_ServerSideSessions_DisplayName", + table: "ServerSideSessions", + column: "DisplayName"); + + migrationBuilder.CreateIndex( + name: "IX_ServerSideSessions_Expires", + table: "ServerSideSessions", + column: "Expires"); + + migrationBuilder.CreateIndex( + name: "IX_ServerSideSessions_Key", + table: "ServerSideSessions", + column: "Key", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_ServerSideSessions_SessionId", + table: "ServerSideSessions", + column: "SessionId"); + + migrationBuilder.CreateIndex( + name: "IX_ServerSideSessions_SubjectId", + table: "ServerSideSessions", + column: "SubjectId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "DeviceCodes"); + + migrationBuilder.DropTable( + name: "Keys"); + + migrationBuilder.DropTable( + name: "PersistedGrants"); + + migrationBuilder.DropTable( + name: "PushedAuthorizationRequests"); + + migrationBuilder.DropTable( + name: "ServerSideSessions"); + } + } +} diff --git a/app/server/IdentityService/src/IdentityService.Infrastructure/Persistence/IdentityServer/PersistedGrant/PersistedGrantDbContextModelSnapshot.cs b/app/server/IdentityService/src/IdentityService.Infrastructure/Persistence/IdentityServer/PersistedGrant/PersistedGrantDbContextModelSnapshot.cs new file mode 100644 index 000000000..fc686109b --- /dev/null +++ b/app/server/IdentityService/src/IdentityService.Infrastructure/Persistence/IdentityServer/PersistedGrant/PersistedGrantDbContextModelSnapshot.cs @@ -0,0 +1,267 @@ +// +using System; +using Duende.IdentityServer.EntityFramework.DbContexts; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace IdentityService.Infrastructure.Persistence.IdentityServer.PersistedGrant +{ + [DbContext(typeof(PersistedGrantDbContext))] + partial class PersistedGrantDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.11") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Duende.IdentityServer.EntityFramework.Entities.DeviceFlowCodes", b => + { + b.Property("UserCode") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone"); + + b.Property("Data") + .IsRequired() + .HasMaxLength(50000) + .HasColumnType("character varying(50000)"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("DeviceCode") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Expiration") + .IsRequired() + .HasColumnType("timestamp without time zone"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("SubjectId") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.HasKey("UserCode"); + + b.HasIndex("DeviceCode") + .IsUnique(); + + b.HasIndex("Expiration"); + + b.ToTable("DeviceCodes", (string)null); + }); + + modelBuilder.Entity("Duende.IdentityServer.EntityFramework.Entities.Key", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Algorithm") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Created") + .HasColumnType("timestamp without time zone"); + + b.Property("Data") + .IsRequired() + .HasColumnType("text"); + + b.Property("DataProtected") + .HasColumnType("boolean"); + + b.Property("IsX509Certificate") + .HasColumnType("boolean"); + + b.Property("Use") + .HasColumnType("text"); + + b.Property("Version") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("Use"); + + b.ToTable("Keys", (string)null); + }); + + modelBuilder.Entity("Duende.IdentityServer.EntityFramework.Entities.PersistedGrant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ConsumedTime") + .HasColumnType("timestamp without time zone"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone"); + + b.Property("Data") + .IsRequired() + .HasMaxLength(50000) + .HasColumnType("character varying(50000)"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Expiration") + .HasColumnType("timestamp without time zone"); + + b.Property("Key") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("SubjectId") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Id"); + + b.HasIndex("ConsumedTime"); + + b.HasIndex("Expiration"); + + b.HasIndex("Key") + .IsUnique(); + + b.HasIndex("SubjectId", "ClientId", "Type"); + + b.HasIndex("SubjectId", "SessionId", "Type"); + + b.ToTable("PersistedGrants", (string)null); + }); + + modelBuilder.Entity("Duende.IdentityServer.EntityFramework.Entities.PushedAuthorizationRequest", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ExpiresAtUtc") + .HasColumnType("timestamp without time zone"); + + b.Property("Parameters") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReferenceValueHash") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.HasKey("Id"); + + b.HasIndex("ExpiresAtUtc"); + + b.HasIndex("ReferenceValueHash") + .IsUnique(); + + b.ToTable("PushedAuthorizationRequests", (string)null); + }); + + modelBuilder.Entity("Duende.IdentityServer.EntityFramework.Entities.ServerSideSession", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("timestamp without time zone"); + + b.Property("Data") + .IsRequired() + .HasColumnType("text"); + + b.Property("DisplayName") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Expires") + .HasColumnType("timestamp without time zone"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Renewed") + .HasColumnType("timestamp without time zone"); + + b.Property("Scheme") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("SubjectId") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("DisplayName"); + + b.HasIndex("Expires"); + + b.HasIndex("Key") + .IsUnique(); + + b.HasIndex("SessionId"); + + b.HasIndex("SubjectId"); + + b.ToTable("ServerSideSessions", (string)null); + }); +#pragma warning restore 612, 618 + } + } +} From 345f781236142e1116dfc931f28369facd12f087 Mon Sep 17 00:00:00 2001 From: Carl-Johnsons Date: Thu, 11 Jun 2026 13:29:33 +0700 Subject: [PATCH 02/14] chore: apply remote db migrations --- .../Contract/Contract/Utilities/EnvUtility.cs | 2 +- scripts/local/apply-all-migrations.sh | 41 +++++++++++++++---- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/app/server/Contract/Contract/Utilities/EnvUtility.cs b/app/server/Contract/Contract/Utilities/EnvUtility.cs index fd12041ab..5d3d2936a 100644 --- a/app/server/Contract/Contract/Utilities/EnvUtility.cs +++ b/app/server/Contract/Contract/Utilities/EnvUtility.cs @@ -54,7 +54,7 @@ public static string GetConnectionString() var db = DotNetEnv.Env.GetString("DB", "Not found").Trim(); var user = DotNetEnv.Env.GetString("POSTGRES_USER", "Not found").Trim(); var pwd = DotNetEnv.Env.GetString("POSTGRES_PASSWORD", "Not found").Trim(); - var connectionString = $"Host={host};Port={port};Database={db};Username={user};Password={pwd};"; + var connectionString = $"Host={host};Port={port};Database={db};Username={user};Password={pwd};SSL Mode=Require;Trust Server Certificate=true;"; return connectionString; } diff --git a/scripts/local/apply-all-migrations.sh b/scripts/local/apply-all-migrations.sh index 42894e37b..8991222cc 100755 --- a/scripts/local/apply-all-migrations.sh +++ b/scripts/local/apply-all-migrations.sh @@ -1,6 +1,31 @@ #!/bin/bash -. ./scripts/lib.sh && check_docker +. ./scripts/lib.sh + +TARGET_ENV=$1 +ENV_FILE=".env" +case "$TARGET_ENV" in + "dev"|"") + ENV_FILE=".env" + check_docker + ;; + "staging" | "production") + ENV_FILE=".env.$TARGET_ENV" + ;; + *) + # Invalid argument + printf "${DANGER}Invalid argument: '$TARGET_ENV'. Usage: $0 [-psh] [dev|staging|production]${NC}\n" + exit 1 + ;; +esac +echo "Migrating database for environment: $ENV_FILE" + +if [ ! -f "$ENV_FILE" ]; then + err_env_missing + exit +fi + +export $(grep -v '^#' $ENV_FILE | xargs) project_root=$(pwd) @@ -16,9 +41,9 @@ update_database() { if [ -f $env_path ]; then # Export each line as an environment variable - export $(grep -v '^#' .env | xargs) + export $(grep -v '^#' $env_path | xargs) else - echo ".env file not found." + echo "$env_path file not found." fi if [[ " ${POSTGRES_REQUIRED_SERVICES[@]} " =~ " ${name} " ]]; then @@ -34,8 +59,8 @@ update_database() { fi } -update_database "./app/server/IdentityService/.env" "./app/server/IdentityService/src/DuendeIdentityServer" "Identity" -update_database "./app/server/UserService/.env" "./app/server/UserService/src/UserService.API" "User" -update_database "./app/server/RecipeService/.env" "./app/server/RecipeService/src/RecipeService.API" "Recipe" -update_database "./app/server/NotificationService/.env" "./app/server/NotificationService/src/NotificationService.API" "Notification" -update_database "./app/server/TrackingService/.env" "./app/server/TrackingService/src/TrackingService.API" "Tracking" \ No newline at end of file +update_database "./app/server/IdentityService/$ENV_FILE" "./app/server/IdentityService/src/DuendeIdentityServer" "Identity" +update_database "./app/server/UserService/$ENV_FILE" "./app/server/UserService/src/UserService.API" "User" +update_database "./app/server/RecipeService/$ENV_FILE" "./app/server/RecipeService/src/RecipeService.API" "Recipe" +update_database "./app/server/NotificationService/$ENV_FILE" "./app/server/NotificationService/src/NotificationService.API" "Notification" +update_database "./app/server/TrackingService/$ENV_FILE" "./app/server/TrackingService/src/TrackingService.API" "Tracking" \ No newline at end of file From 964e73f8d8aa56d70aafa8604a388df460b5f760 Mon Sep 17 00:00:00 2001 From: Carl-Johnsons Date: Fri, 12 Jun 2026 10:36:47 +0700 Subject: [PATCH 03/14] chore: remove SSL mode remote db for local dev --- app/server/Contract/Contract/Utilities/EnvUtility.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/server/Contract/Contract/Utilities/EnvUtility.cs b/app/server/Contract/Contract/Utilities/EnvUtility.cs index 5d3d2936a..aa7ddbd8b 100644 --- a/app/server/Contract/Contract/Utilities/EnvUtility.cs +++ b/app/server/Contract/Contract/Utilities/EnvUtility.cs @@ -54,7 +54,11 @@ public static string GetConnectionString() var db = DotNetEnv.Env.GetString("DB", "Not found").Trim(); var user = DotNetEnv.Env.GetString("POSTGRES_USER", "Not found").Trim(); var pwd = DotNetEnv.Env.GetString("POSTGRES_PASSWORD", "Not found").Trim(); - var connectionString = $"Host={host};Port={port};Database={db};Username={user};Password={pwd};SSL Mode=Require;Trust Server Certificate=true;"; + var connectionString = $"Host={host};Port={port};Database={db};Username={user};Password={pwd};"; + if (IsProduction()) + { + connectionString = $"{connectionString}SSL Mode=Require;Trust Server Certificate=true;"; + } return connectionString; } From 3033df11ed793c03b4c3ea4c755947514b24adf3 Mon Sep 17 00:00:00 2001 From: Carl-Johnsons Date: Fri, 12 Jun 2026 10:45:54 +0700 Subject: [PATCH 04/14] chore: clean code --- scripts/local/apply-all-migrations.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/local/apply-all-migrations.sh b/scripts/local/apply-all-migrations.sh index 8991222cc..d90484f40 100755 --- a/scripts/local/apply-all-migrations.sh +++ b/scripts/local/apply-all-migrations.sh @@ -39,12 +39,13 @@ update_database() { local project=$2 local name=$3 - if [ -f $env_path ]; then - # Export each line as an environment variable - export $(grep -v '^#' $env_path | xargs) - else + if [[ ! -f "$env_path" ]]; then echo "$env_path file not found." + return 1 fi + + # Export each line as an environment variable + export $(grep -v '^#' $env_path | xargs) if [[ " ${POSTGRES_REQUIRED_SERVICES[@]} " =~ " ${name} " ]]; then echo -e "${INFO}Running Postgresql migrations for ${name}...${NC}" From d87ea751af61e18e72f691995775b932ddcf8118 Mon Sep 17 00:00:00 2001 From: Carl-Johnsons Date: Fri, 12 Jun 2026 10:54:35 +0700 Subject: [PATCH 05/14] chore: add retry on failure for persisted grant db --- .../DuendeIdentityServer/HostingExtensions.cs | 9 +++++++-- .../DependencyInjection.cs | 16 +++++++++++----- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/app/server/IdentityService/src/DuendeIdentityServer/HostingExtensions.cs b/app/server/IdentityService/src/DuendeIdentityServer/HostingExtensions.cs index 809d76285..8d9222d74 100755 --- a/app/server/IdentityService/src/DuendeIdentityServer/HostingExtensions.cs +++ b/app/server/IdentityService/src/DuendeIdentityServer/HostingExtensions.cs @@ -72,8 +72,13 @@ public static WebApplication ConfigureServices(this WebApplicationBuilder builde .AddOperationalStore(options => { options.ConfigureDbContext = builder => - builder.UseNpgsql(EnvUtility.GetConnectionString(), - sql => sql.MigrationsAssembly("IdentityService.Infrastructure")); + builder.UseNpgsql(EnvUtility.GetConnectionString(), + options => options.MigrationsAssembly("IdentityService.Infrastructure") + .EnableRetryOnFailure( + maxRetryCount: 10, + maxRetryDelay: TimeSpan.FromSeconds(15), + errorCodesToAdd: null + )); options.EnableTokenCleanup = true; options.TokenCleanupInterval = 3600; diff --git a/app/server/IdentityService/src/IdentityService.Infrastructure/DependencyInjection.cs b/app/server/IdentityService/src/IdentityService.Infrastructure/DependencyInjection.cs index 2357b99ca..7d266453c 100644 --- a/app/server/IdentityService/src/IdentityService.Infrastructure/DependencyInjection.cs +++ b/app/server/IdentityService/src/IdentityService.Infrastructure/DependencyInjection.cs @@ -27,16 +27,22 @@ public static IServiceCollection AddInfrastructureServices(this IServiceCollecti public static IServiceCollection AddMinimalInfrastructureServices(this IServiceCollection services) { + var connectionString = Contract.Utilities.EnvUtility.GetConnectionString(); AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true); services.AddDbContext(options => - options.UseNpgsql(Contract.Utilities.EnvUtility.GetConnectionString())); + options.UseNpgsql(connectionString)); services.AddIdentityServer() .AddOperationalStore(options => { - options.ConfigureDbContext = b => - b.UseNpgsql( - Contract.Utilities.EnvUtility.GetConnectionString(), - sql => sql.MigrationsAssembly("IdentityService.Infrastructure")); + options.ConfigureDbContext = builder => + builder.UseNpgsql(connectionString, + options => options.MigrationsAssembly("IdentityService.Infrastructure") + .EnableRetryOnFailure( + maxRetryCount: 10, + maxRetryDelay: TimeSpan.FromSeconds(15), + errorCodesToAdd: null + )); + }); services.AddIdentity() .AddEntityFrameworkStores() From 4880301755ab2b4d4576f2a43ad366ffc4551089 Mon Sep 17 00:00:00 2001 From: Carl-Johnsons Date: Fri, 12 Jun 2026 10:58:40 +0700 Subject: [PATCH 06/14] chore: clear contract warnings --- .../Contract/Event/UserEvent/UpdateUserTotalRecipeEvent.cs | 1 - app/server/Contract/Contract/Protos/TrackingService.proto | 1 - 2 files changed, 2 deletions(-) diff --git a/app/server/Contract/Contract/Event/UserEvent/UpdateUserTotalRecipeEvent.cs b/app/server/Contract/Contract/Event/UserEvent/UpdateUserTotalRecipeEvent.cs index f2e05697d..e52a858ac 100644 --- a/app/server/Contract/Contract/Event/UserEvent/UpdateUserTotalRecipeEvent.cs +++ b/app/server/Contract/Contract/Event/UserEvent/UpdateUserTotalRecipeEvent.cs @@ -1,5 +1,4 @@ using MassTransit; -using MassTransit; namespace Contract.Event.UserEvent; [EntityName("UpdateUserTotalRecipeEvent")] public class UpdateUserTotalRecipeEvent diff --git a/app/server/Contract/Contract/Protos/TrackingService.proto b/app/server/Contract/Contract/Protos/TrackingService.proto index c3c01b405..984ac1139 100644 --- a/app/server/Contract/Contract/Protos/TrackingService.proto +++ b/app/server/Contract/Contract/Protos/TrackingService.proto @@ -1,7 +1,6 @@ syntax = "proto3"; import "google/protobuf/timestamp.proto"; -import "google/protobuf/wrappers.proto"; package TrackingProto; From 4a9517799f5122186d7be3be53f3baefd87ed6b9 Mon Sep 17 00:00:00 2001 From: Carl-Johnsons Date: Fri, 12 Jun 2026 11:05:11 +0700 Subject: [PATCH 07/14] chore: clear api-gateway warnings --- .../APIGateway/src/APIGateway/DependenciesInjection.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/server/APIGateway/src/APIGateway/DependenciesInjection.cs b/app/server/APIGateway/src/APIGateway/DependenciesInjection.cs index c8ac829e6..80e9918a6 100644 --- a/app/server/APIGateway/src/APIGateway/DependenciesInjection.cs +++ b/app/server/APIGateway/src/APIGateway/DependenciesInjection.cs @@ -139,7 +139,12 @@ public static WebApplication UseAPIServices(this WebApplication app) private static bool Authorize(HttpContext ctx) { - if (ctx.Items.DownstreamRoute().AuthenticationOptions.AuthenticationProviderKey == null) return true; + if (ctx.Items.DownstreamRoute() + .AuthenticationOptions + .AuthenticationProviderKeys?.Length == 0) + { + return true; + } else { bool auth = false; From 3b705e7a62d3d3aab9888667353f63202ef5605d Mon Sep 17 00:00:00 2001 From: Carl-Johnsons Date: Fri, 12 Jun 2026 11:46:19 +0700 Subject: [PATCH 08/14] chore: clear duende identity warnings --- .../DuendeIdentityServer/AppCommandHandler.cs | 2 +- .../DTOs/MappingConfig.cs | 3 +-- .../DuendeIdentityServer.csproj | 2 +- .../Extensions/ReinforcedTypingsExtension.cs | 5 +++++ .../DuendeIdentityServer/HostingExtensions.cs | 20 ++++++++++--------- .../Account/ChangePassword/Index.cshtml.cs | 4 ++-- .../ChangePasswordSuccess/Index.cshtml.cs | 4 ++-- .../Account/ForgotPassword/Index.cshtml.cs | 2 +- .../VerifyForgotPassword/Index.cshtml.cs | 6 +++--- .../Pages/ExternalLogin/Callback.cshtml.cs | 4 ++-- .../src/DuendeIdentityServer/Program.cs | 2 +- .../Configs/MappingConfig.cs | 3 +-- .../DependencyInjection.cs | 8 +++++--- .../IdentityService.Application.csproj | 2 +- 14 files changed, 37 insertions(+), 30 deletions(-) diff --git a/app/server/IdentityService/src/DuendeIdentityServer/AppCommandHandler.cs b/app/server/IdentityService/src/DuendeIdentityServer/AppCommandHandler.cs index 9470280f6..9376daf1e 100755 --- a/app/server/IdentityService/src/DuendeIdentityServer/AppCommandHandler.cs +++ b/app/server/IdentityService/src/DuendeIdentityServer/AppCommandHandler.cs @@ -34,7 +34,7 @@ public static async Task TryHandleAsync(this WebApplicationBuilder builder sp.GetRequiredService().Database.Migrate(); break; case COMMAND_ARGS.SEED: - dbContext.SeedDb(sp).GetAwaiter().GetResult(); + await dbContext.SeedDb(sp); break; } } diff --git a/app/server/IdentityService/src/DuendeIdentityServer/DTOs/MappingConfig.cs b/app/server/IdentityService/src/DuendeIdentityServer/DTOs/MappingConfig.cs index 0678ad730..d6a56746a 100755 --- a/app/server/IdentityService/src/DuendeIdentityServer/DTOs/MappingConfig.cs +++ b/app/server/IdentityService/src/DuendeIdentityServer/DTOs/MappingConfig.cs @@ -14,8 +14,7 @@ public static MapperConfiguration RegisterMaps() config.CreateMap().ReverseMap(); config.CreateMap().ReverseMap(); config.CreateMap().ReverseMap(); - }); - + }, null); return mappingConfig; } diff --git a/app/server/IdentityService/src/DuendeIdentityServer/DuendeIdentityServer.csproj b/app/server/IdentityService/src/DuendeIdentityServer/DuendeIdentityServer.csproj index fe6a84671..a94b09b17 100755 --- a/app/server/IdentityService/src/DuendeIdentityServer/DuendeIdentityServer.csproj +++ b/app/server/IdentityService/src/DuendeIdentityServer/DuendeIdentityServer.csproj @@ -16,7 +16,7 @@ - + diff --git a/app/server/IdentityService/src/DuendeIdentityServer/Extensions/ReinforcedTypingsExtension.cs b/app/server/IdentityService/src/DuendeIdentityServer/Extensions/ReinforcedTypingsExtension.cs index abdf7da66..9f05a0d72 100755 --- a/app/server/IdentityService/src/DuendeIdentityServer/Extensions/ReinforcedTypingsExtension.cs +++ b/app/server/IdentityService/src/DuendeIdentityServer/Extensions/ReinforcedTypingsExtension.cs @@ -1,5 +1,6 @@ using Contract.Extension; using IdentityService.Domain.Errors; +using Reinforced.Typings.Ast.TypeNames; using Reinforced.Typings.Fluent; using ConfigurationBuilder = Reinforced.Typings.Fluent.ConfigurationBuilder; namespace DuendeIdentityServer.Extensions; @@ -20,6 +21,10 @@ public static void ConfigureReinforcedTypings(ConfigurationBuilder builder) builder.ConfigCommonReinforcedTypings(EXPORT_FILE_PATH, FILE_NAME, errorsTypes); + builder.Substitute(typeof(DateTimeOffset), new RtSimpleTypeName("string")); + builder.Substitute(typeof(Microsoft.AspNetCore.Identity.IdentityRole), new RtSimpleTypeName("any")); + builder.Substitute(typeof(IFormFile), new RtSimpleTypeName("any")); + // DTO and Entities builder.ExportAsInterfaces([ typeof(StatisticEntity), diff --git a/app/server/IdentityService/src/DuendeIdentityServer/HostingExtensions.cs b/app/server/IdentityService/src/DuendeIdentityServer/HostingExtensions.cs index 8d9222d74..9d82a9de9 100755 --- a/app/server/IdentityService/src/DuendeIdentityServer/HostingExtensions.cs +++ b/app/server/IdentityService/src/DuendeIdentityServer/HostingExtensions.cs @@ -44,9 +44,11 @@ public static WebApplication ConfigureServices(this WebApplicationBuilder builde }); // Register automapper - IMapper mapper = MappingConfig.RegisterMaps().CreateMapper(); - services.AddSingleton(mapper); - services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); + // IMapper mapper = MappingConfig.RegisterMaps().CreateMapper(); + // services.AddSingleton(mapper); + services.AddAutoMapper( + cfg => { }, + AppDomain.CurrentDomain.GetAssemblies()); services.AddCommonAPIWithoutAuthServices(); services @@ -138,7 +140,7 @@ public static WebApplication ConfigureServices(this WebApplicationBuilder builde return builder.Build(); } - public static async Task ConfigurePipelineAsync(this WebApplication app) + public static Task ConfigurePipeline(this WebApplication app) { if (EnvUtility.IsProduction() || EnvUtility.IsStaging()) { @@ -199,11 +201,11 @@ public static async Task ConfigurePipelineAsync(this WebApplicat app.UseSignalRServiceAsync(); app.Use(async (context, next) => - { - Console.WriteLine($"RemoteIp: {context.Connection.RemoteIpAddress}"); - await next(); - }); + { + Console.WriteLine($"RemoteIp: {context.Connection.RemoteIpAddress}"); + await next(); + }); - return app; + return Task.FromResult(app); } } diff --git a/app/server/IdentityService/src/DuendeIdentityServer/Pages/Account/ChangePassword/Index.cshtml.cs b/app/server/IdentityService/src/DuendeIdentityServer/Pages/Account/ChangePassword/Index.cshtml.cs index a37045359..58cac3e16 100755 --- a/app/server/IdentityService/src/DuendeIdentityServer/Pages/Account/ChangePassword/Index.cshtml.cs +++ b/app/server/IdentityService/src/DuendeIdentityServer/Pages/Account/ChangePassword/Index.cshtml.cs @@ -42,7 +42,7 @@ public Index( _sender = sender; } - public async Task OnGet(string returnUrl, string identifier) + public Task OnGet(string returnUrl, string identifier) { Input = new InputModel { @@ -53,7 +53,7 @@ public async Task OnGet(string returnUrl, string identifier) ViewData["ReturnUrl"] = encodedRedirectUri; - return Page(); + return Task.FromResult(Page()); } public async Task OnPost() diff --git a/app/server/IdentityService/src/DuendeIdentityServer/Pages/Account/ChangePasswordSuccess/Index.cshtml.cs b/app/server/IdentityService/src/DuendeIdentityServer/Pages/Account/ChangePasswordSuccess/Index.cshtml.cs index 060108bd0..93ddca79e 100755 --- a/app/server/IdentityService/src/DuendeIdentityServer/Pages/Account/ChangePasswordSuccess/Index.cshtml.cs +++ b/app/server/IdentityService/src/DuendeIdentityServer/Pages/Account/ChangePasswordSuccess/Index.cshtml.cs @@ -11,11 +11,11 @@ public class Index : PageModel public Index() { } - public async Task OnGet(string returnUrl) + public Task OnGet(string returnUrl) { var encodedRedirectUri = WebUtility.UrlEncode(returnUrl); ViewData["ReturnUrl"] = encodedRedirectUri; - return Page(); + return Task.FromResult(Page()); } } diff --git a/app/server/IdentityService/src/DuendeIdentityServer/Pages/Account/ForgotPassword/Index.cshtml.cs b/app/server/IdentityService/src/DuendeIdentityServer/Pages/Account/ForgotPassword/Index.cshtml.cs index 54bb71c34..e0e3f4bb1 100755 --- a/app/server/IdentityService/src/DuendeIdentityServer/Pages/Account/ForgotPassword/Index.cshtml.cs +++ b/app/server/IdentityService/src/DuendeIdentityServer/Pages/Account/ForgotPassword/Index.cshtml.cs @@ -128,7 +128,7 @@ public async Task OnPost() } catch (Exception ex) { - ModelState.AddModelError(string.Empty, "Send OTP failed! Please try again"); + ModelState.AddModelError(string.Empty, $"Send OTP failed! Please try again ({ex.Message})"); } break; case "ReturnFind": diff --git a/app/server/IdentityService/src/DuendeIdentityServer/Pages/Account/VerifyForgotPassword/Index.cshtml.cs b/app/server/IdentityService/src/DuendeIdentityServer/Pages/Account/VerifyForgotPassword/Index.cshtml.cs index f0193cfe4..2e527c008 100755 --- a/app/server/IdentityService/src/DuendeIdentityServer/Pages/Account/VerifyForgotPassword/Index.cshtml.cs +++ b/app/server/IdentityService/src/DuendeIdentityServer/Pages/Account/VerifyForgotPassword/Index.cshtml.cs @@ -30,7 +30,7 @@ public Index( _sender = sender; } - public async Task OnGet(string returnUrl, string identifier) + public Task OnGet(string returnUrl, string identifier) { Input = new InputModel { @@ -45,7 +45,7 @@ public async Task OnGet(string returnUrl, string identifier) IsValidOTP = false, }; - return Page(); + return Task.FromResult(Page()); } public async Task OnPost() @@ -176,7 +176,7 @@ public async Task OnPost() Identifier = Input.Identifier, OTP = Input.OTP!, Method = IdentifierUtility.Check(Input.Identifier), - Password = Input.Password + Password = Input.Password! }); result.ThrowIfFailure(); diff --git a/app/server/IdentityService/src/DuendeIdentityServer/Pages/ExternalLogin/Callback.cshtml.cs b/app/server/IdentityService/src/DuendeIdentityServer/Pages/ExternalLogin/Callback.cshtml.cs index 0216cba23..f84be3ba6 100755 --- a/app/server/IdentityService/src/DuendeIdentityServer/Pages/ExternalLogin/Callback.cshtml.cs +++ b/app/server/IdentityService/src/DuendeIdentityServer/Pages/ExternalLogin/Callback.cshtml.cs @@ -71,7 +71,7 @@ public async Task OnGet() externalUser.FindFirst(ClaimTypes.NameIdentifier) ?? throw new InvalidOperationException("Unknown userid"); - var provider = result.Properties.Items["scheme"] ?? throw new InvalidOperationException("Null scheme in authentiation properties"); + var provider = result.Properties?.Items["scheme"] ?? throw new InvalidOperationException("Null scheme in authentiation properties"); var providerUserId = userIdClaim.Value; // find external user @@ -87,7 +87,7 @@ public async Task OnGet() Provider = provider, ProviderUserId = providerUserId, Claims = externalUser.Claims, - AccessToken = accessToken + AccessToken = accessToken! }); response.ThrowIfFailure(); user = response.Value; diff --git a/app/server/IdentityService/src/DuendeIdentityServer/Program.cs b/app/server/IdentityService/src/DuendeIdentityServer/Program.cs index 15ddaf33c..5257dd1e0 100755 --- a/app/server/IdentityService/src/DuendeIdentityServer/Program.cs +++ b/app/server/IdentityService/src/DuendeIdentityServer/Program.cs @@ -13,7 +13,7 @@ var app = await builder .ConfigureServices() - .ConfigurePipelineAsync(); + .ConfigurePipeline(); app.Start(); diff --git a/app/server/IdentityService/src/IdentityService.Application/Configs/MappingConfig.cs b/app/server/IdentityService/src/IdentityService.Application/Configs/MappingConfig.cs index 96093944a..937ffd1f5 100644 --- a/app/server/IdentityService/src/IdentityService.Application/Configs/MappingConfig.cs +++ b/app/server/IdentityService/src/IdentityService.Application/Configs/MappingConfig.cs @@ -12,8 +12,7 @@ public static MapperConfiguration RegisterMaps() { config.CreateMap(typeof(List<>), typeof(RepeatedField<>)).ConvertUsing(typeof(ListToRepeatedFieldConverter<,>)); config.CreateMap(typeof(RepeatedField<>), typeof(List<>)).ConvertUsing(typeof(RepeatedFieldToListConverter<,>)); - }); - + }, null); return mappingConfig; } diff --git a/app/server/IdentityService/src/IdentityService.Application/DependencyInjection.cs b/app/server/IdentityService/src/IdentityService.Application/DependencyInjection.cs index 471443eb7..e7f89d7d7 100644 --- a/app/server/IdentityService/src/IdentityService.Application/DependencyInjection.cs +++ b/app/server/IdentityService/src/IdentityService.Application/DependencyInjection.cs @@ -15,9 +15,11 @@ public static IServiceCollection AddApplicationServices(this IServiceCollection services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly())); services.AddGrpcClientServices(); // Register automapper - IMapper mapper = MappingConfig.RegisterMaps().CreateMapper(); - services.AddSingleton(mapper); - services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); + // IMapper mapper = MappingConfig.RegisterMaps().CreateMapper(); + // services.AddSingleton(mapper); + services.AddAutoMapper( + cfg => { }, + AppDomain.CurrentDomain.GetAssemblies()); return services; } diff --git a/app/server/IdentityService/src/IdentityService.Application/IdentityService.Application.csproj b/app/server/IdentityService/src/IdentityService.Application/IdentityService.Application.csproj index c962e5247..a362a9904 100644 --- a/app/server/IdentityService/src/IdentityService.Application/IdentityService.Application.csproj +++ b/app/server/IdentityService/src/IdentityService.Application/IdentityService.Application.csproj @@ -7,7 +7,7 @@ - + From 0a17b0f6681caabf20442facd975393b9a13aeff Mon Sep 17 00:00:00 2001 From: Carl-Johnsons Date: Fri, 12 Jun 2026 11:55:04 +0700 Subject: [PATCH 09/14] chore: clear upload warnings --- .../src/UploadFileService.API/Configs/MappingConfig.cs | 2 +- .../src/UploadFileService.API/DependenciesInjection.cs | 6 +++--- .../src/UploadFileService.API/UploadFileService.API.csproj | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/server/UploadFileService/src/UploadFileService.API/Configs/MappingConfig.cs b/app/server/UploadFileService/src/UploadFileService.API/Configs/MappingConfig.cs index 72fd237d9..00f12a8ea 100644 --- a/app/server/UploadFileService/src/UploadFileService.API/Configs/MappingConfig.cs +++ b/app/server/UploadFileService/src/UploadFileService.API/Configs/MappingConfig.cs @@ -27,7 +27,7 @@ public static MapperConfiguration RegisterMaps() .MapFrom(src => ByteString.CopyFrom(src.Stream))); config.CreateMap().ReverseMap(); - }); + }, null); //mappingConfig.AssertConfigurationIsValid(); return mappingConfig; diff --git a/app/server/UploadFileService/src/UploadFileService.API/DependenciesInjection.cs b/app/server/UploadFileService/src/UploadFileService.API/DependenciesInjection.cs index 826027a36..52cf89fd3 100644 --- a/app/server/UploadFileService/src/UploadFileService.API/DependenciesInjection.cs +++ b/app/server/UploadFileService/src/UploadFileService.API/DependenciesInjection.cs @@ -24,9 +24,9 @@ public static WebApplicationBuilder AddAPIServices(this WebApplicationBuilder bu services.AddSwaggerServices(); // Register automapper - IMapper mapper = MappingConfig.RegisterMaps().CreateMapper(); - services.AddSingleton(mapper); - services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); + services.AddAutoMapper( + cfg => { }, + AppDomain.CurrentDomain.GetAssemblies()); services.AddCommonAPIServices(); diff --git a/app/server/UploadFileService/src/UploadFileService.API/UploadFileService.API.csproj b/app/server/UploadFileService/src/UploadFileService.API/UploadFileService.API.csproj index 7b095d1a6..497447adb 100644 --- a/app/server/UploadFileService/src/UploadFileService.API/UploadFileService.API.csproj +++ b/app/server/UploadFileService/src/UploadFileService.API/UploadFileService.API.csproj @@ -16,7 +16,7 @@ - + From 05b6b9312ef8abbc76e08c1503f52b113e085575 Mon Sep 17 00:00:00 2001 From: Carl-Johnsons Date: Fri, 12 Jun 2026 13:21:01 +0700 Subject: [PATCH 10/14] chore: clear user service warnings --- .../src/UserService.API/AppCommandHandler.cs | 6 ++-- .../{MappingConfig.cs => UserProfile.cs} | 24 ++++----------- .../UserService.API/DependenciesInjection.cs | 5 ++-- .../Extensions/ReinforcedTypingsExtension.cs | 2 ++ .../Configs/MappingConfig.cs | 30 ------------------- .../Configs/UserProfile.cs | 24 +++++++++++++++ .../DependencyInjection.cs | 6 ++-- .../UserService.Application.csproj | 2 +- 8 files changed, 42 insertions(+), 57 deletions(-) rename app/server/UserService/src/UserService.API/Configs/{MappingConfig.cs => UserProfile.cs} (70%) delete mode 100644 app/server/UserService/src/UserService.Application/Configs/MappingConfig.cs create mode 100644 app/server/UserService/src/UserService.Application/Configs/UserProfile.cs diff --git a/app/server/UserService/src/UserService.API/AppCommandHandler.cs b/app/server/UserService/src/UserService.API/AppCommandHandler.cs index 8b99b2ee4..f6c178a4b 100644 --- a/app/server/UserService/src/UserService.API/AppCommandHandler.cs +++ b/app/server/UserService/src/UserService.API/AppCommandHandler.cs @@ -6,7 +6,7 @@ namespace UserService.API; public static class AppCommandHandler { - public static async Task TryHandleAsync(this WebApplicationBuilder builder, string[] args) + public static Task TryHandleAsync(this WebApplicationBuilder builder, string[] args) { var uniqueArgs = args .Where(COMMAND_ARGS.All.Contains) @@ -14,7 +14,7 @@ public static async Task TryHandleAsync(this WebApplicationBuilder builder .ToArray(); if (uniqueArgs.Length == 0) { - return false; + return Task.FromResult(false); } builder.Services.AddMinimalInfrastructureServices(); @@ -34,6 +34,6 @@ public static async Task TryHandleAsync(this WebApplicationBuilder builder break; } } - return true; + return Task.FromResult(true); } } \ No newline at end of file diff --git a/app/server/UserService/src/UserService.API/Configs/MappingConfig.cs b/app/server/UserService/src/UserService.API/Configs/UserProfile.cs similarity index 70% rename from app/server/UserService/src/UserService.API/Configs/MappingConfig.cs rename to app/server/UserService/src/UserService.API/Configs/UserProfile.cs index 27aac019c..2d7ce92c6 100644 --- a/app/server/UserService/src/UserService.API/Configs/MappingConfig.cs +++ b/app/server/UserService/src/UserService.API/Configs/UserProfile.cs @@ -7,19 +7,13 @@ namespace UserService.API.Configs; -public class MappingConfig +public class UserProfile : Profile { - - public static MapperConfiguration RegisterMaps() + public UserProfile() { - var mappingConfig = new MapperConfiguration(config => - { - //config.CreateMap().ReverseMap(); - config.CreateMap().ReverseMap(); - config.CreateMap().ReverseMap(); - - // Map object to grpc object - config.CreateMap() + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + CreateMap() .ForMember(dest => dest.Dob, opt => opt.MapFrom(src => src.Dob.HasValue ? Timestamp.FromDateTime(((DateTime)src.Dob).ToUniversalTime()) @@ -31,9 +25,7 @@ public static MapperConfiguration RegisterMaps() opt => opt.MapFrom(src => src.Dob.ToDateTime())) .ForMember(dest => dest.AccountId, opt => opt.MapFrom(src => Guid.Parse(src.AccountId))); - - - config.CreateMap() + CreateMap() .ForMember(dest => dest.Users, opt => opt.MapFrom(src => src.Users.ToDictionary( user => user.Key, @@ -43,9 +35,5 @@ public static MapperConfiguration RegisterMaps() AvtUrl = user.Value.AvtUrl, DisplayName = user.Value.DisplayName }))).ReverseMap(); - }); - - - return mappingConfig; } } diff --git a/app/server/UserService/src/UserService.API/DependenciesInjection.cs b/app/server/UserService/src/UserService.API/DependenciesInjection.cs index ca3689566..dc8e38b74 100644 --- a/app/server/UserService/src/UserService.API/DependenciesInjection.cs +++ b/app/server/UserService/src/UserService.API/DependenciesInjection.cs @@ -19,8 +19,9 @@ public static WebApplicationBuilder AddAPIServices(this WebApplicationBuilder bu builder.ConfigureCommonAPIServices(); - IMapper mapper = MappingConfig.RegisterMaps().CreateMapper(); - services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); + services.AddAutoMapper( + cfg => { }, + AppDomain.CurrentDomain.GetAssemblies()); services.AddInfrastructureServices(); services.AddApplicationServices(); diff --git a/app/server/UserService/src/UserService.API/Extensions/ReinforcedTypingsExtension.cs b/app/server/UserService/src/UserService.API/Extensions/ReinforcedTypingsExtension.cs index d784414a2..d084300bc 100644 --- a/app/server/UserService/src/UserService.API/Extensions/ReinforcedTypingsExtension.cs +++ b/app/server/UserService/src/UserService.API/Extensions/ReinforcedTypingsExtension.cs @@ -1,6 +1,7 @@ using Contract.DTOs; using Contract.Extension; using RecipeService.API.DTOs; +using Reinforced.Typings.Ast.TypeNames; using Reinforced.Typings.Fluent; using UserService.API.DTOs; using UserService.Domain.Entities; @@ -26,6 +27,7 @@ public static void ConfigureReinforcedTypings(ConfigurationBuilder builder) Directory.CreateDirectory(EXPORT_FILE_PATH); builder.ConfigCommonReinforcedTypings(EXPORT_FILE_PATH, FILE_NAME, errorsTypes); + builder.Substitute(typeof(IFormFile), new RtSimpleTypeName("any")); // DTO and Entites builder.ExportAsInterfaces([ diff --git a/app/server/UserService/src/UserService.Application/Configs/MappingConfig.cs b/app/server/UserService/src/UserService.Application/Configs/MappingConfig.cs deleted file mode 100644 index 071400414..000000000 --- a/app/server/UserService/src/UserService.Application/Configs/MappingConfig.cs +++ /dev/null @@ -1,30 +0,0 @@ -using AutoMapper; -using Contract.DTOs.UserDTO; -using Google.Protobuf.Collections; -using UserService.Application.Configs.MapperConverters; -using UserService.Domain.Entities; -using UserService.Domain.Responses; - -namespace UserService.Application.Configs; - -public class MappingConfig -{ - public static MapperConfiguration RegisterMaps() - { - var mappingConfig = new MapperConfiguration(config => - { - config.CreateMap().ReverseMap(); - config.CreateMap().ReverseMap(); - config.CreateMap().ReverseMap(); - config.CreateMap().ReverseMap(); - - - // Grpc mapping - config.CreateMap(typeof(List<>), typeof(RepeatedField<>)).ConvertUsing(typeof(ListToRepeatedFieldConverter<,>)); - config.CreateMap(typeof(RepeatedField<>), typeof(List<>)).ConvertUsing(typeof(RepeatedFieldToListConverter<,>)); - }); - - - return mappingConfig; - } -} diff --git a/app/server/UserService/src/UserService.Application/Configs/UserProfile.cs b/app/server/UserService/src/UserService.Application/Configs/UserProfile.cs new file mode 100644 index 000000000..9a4bc6cfc --- /dev/null +++ b/app/server/UserService/src/UserService.Application/Configs/UserProfile.cs @@ -0,0 +1,24 @@ +using AutoMapper; +using Contract.DTOs.UserDTO; +using Google.Protobuf.Collections; +using UserService.Application.Configs.MapperConverters; +using UserService.Domain.Entities; +using UserService.Domain.Responses; + +namespace UserService.Application.Configs; + +public class UserProfile : Profile +{ + public UserProfile() + { + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + + // Grpc mapping + CreateMap(typeof(List<>), typeof(RepeatedField<>)).ConvertUsing(typeof(ListToRepeatedFieldConverter<,>)); + CreateMap(typeof(RepeatedField<>), typeof(List<>)).ConvertUsing(typeof(RepeatedFieldToListConverter<,>)); + } +} + diff --git a/app/server/UserService/src/UserService.Application/DependencyInjection.cs b/app/server/UserService/src/UserService.Application/DependencyInjection.cs index f5a6675ee..68f83001e 100644 --- a/app/server/UserService/src/UserService.Application/DependencyInjection.cs +++ b/app/server/UserService/src/UserService.Application/DependencyInjection.cs @@ -14,9 +14,9 @@ public static IServiceCollection AddApplicationServices(this IServiceCollection { services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly())); // Register automapper - IMapper mapper = MappingConfig.RegisterMaps().CreateMapper(); - services.AddSingleton(mapper); - services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); + services.AddAutoMapper( + cfg => { }, + AppDomain.CurrentDomain.GetAssemblies()); services.AddGrpcClientService(); return services; } diff --git a/app/server/UserService/src/UserService.Application/UserService.Application.csproj b/app/server/UserService/src/UserService.Application/UserService.Application.csproj index 2ec124a51..eb9ea7b30 100644 --- a/app/server/UserService/src/UserService.Application/UserService.Application.csproj +++ b/app/server/UserService/src/UserService.Application/UserService.Application.csproj @@ -13,7 +13,7 @@ - + From e3420c8bb6d5cbd97dde1acdf138fb14136b2bbe Mon Sep 17 00:00:00 2001 From: Carl-Johnsons Date: Fri, 12 Jun 2026 14:09:51 +0700 Subject: [PATCH 11/14] chore: clear recipe service warnings --- .../RecipeService.API/AppCommandHandler.cs | 6 +- .../Configs/MappingConfig.cs | 97 ------------------- .../Configs/RecipeProfile.cs | 89 +++++++++++++++++ .../DependenciesInjection.cs | 6 +- .../Extensions/ReinforcedTypingsExtension.cs | 3 + .../Configs/MappingConfig.cs | 56 ----------- .../Configs/RecipeProfile.cs | 48 +++++++++ .../DependencyInjection.cs | 6 +- .../RecipeService.Application.csproj | 2 +- .../Queries/GetReportReasonsQueryHandler.cs | 14 +-- .../RecipeService/src/RecipeWorker/Worker.cs | 6 +- 11 files changed, 161 insertions(+), 172 deletions(-) delete mode 100644 app/server/RecipeService/src/RecipeService.API/Configs/MappingConfig.cs create mode 100644 app/server/RecipeService/src/RecipeService.API/Configs/RecipeProfile.cs delete mode 100644 app/server/RecipeService/src/RecipeService.Application/Configs/MappingConfig.cs create mode 100644 app/server/RecipeService/src/RecipeService.Application/Configs/RecipeProfile.cs diff --git a/app/server/RecipeService/src/RecipeService.API/AppCommandHandler.cs b/app/server/RecipeService/src/RecipeService.API/AppCommandHandler.cs index 569757cd9..13a96a729 100644 --- a/app/server/RecipeService/src/RecipeService.API/AppCommandHandler.cs +++ b/app/server/RecipeService/src/RecipeService.API/AppCommandHandler.cs @@ -6,7 +6,7 @@ namespace RecipeService.API; public static class AppCommandHandler { - public static async Task TryHandleAsync(this WebApplicationBuilder builder, string[] args) + public static Task TryHandleAsync(this WebApplicationBuilder builder, string[] args) { var uniqueArgs = args .Where(COMMAND_ARGS.All.Contains) @@ -14,7 +14,7 @@ public static async Task TryHandleAsync(this WebApplicationBuilder builder .ToArray(); if (uniqueArgs.Length == 0) { - return false; + return Task.FromResult(false); } builder.Services.AddMinimalInfrastructureServices(); @@ -31,6 +31,6 @@ public static async Task TryHandleAsync(this WebApplicationBuilder builder break; } } - return true; + return Task.FromResult(true); } } \ No newline at end of file diff --git a/app/server/RecipeService/src/RecipeService.API/Configs/MappingConfig.cs b/app/server/RecipeService/src/RecipeService.API/Configs/MappingConfig.cs deleted file mode 100644 index 2f1b5f70f..000000000 --- a/app/server/RecipeService/src/RecipeService.API/Configs/MappingConfig.cs +++ /dev/null @@ -1,97 +0,0 @@ -using AutoMapper; -using Contract.DTOs.RecipeDTO; -using RecipeProto; -using RecipeService.API.DTOs; -using RecipeService.Application.Recipes.Commands; -using RecipeService.Domain.Entities; - -namespace RecipeService.API.Configs; - -public class MappingConfig -{ - public static MapperConfiguration RegisterMaps() - { - var mappingConfig = new MapperConfiguration(config => - { - - config.CreateMap() - .ForMember(dest => dest.Steps, opt => opt.MapFrom(src => src.Steps)).ReverseMap(); - - config.CreateMap().ReverseMap(); - - config.CreateMap() - .ForMember(dest => dest.Steps, opt => opt.MapFrom(src => src.Steps)) - .ForMember(dest => dest.CookTime, opt => opt.MapFrom(src => src.CookTime)) - .ReverseMap() - .ForMember(dest => dest.Steps, opt => opt.MapFrom(src => src.Steps)) - .ForMember(dest => dest.CookTime, opt => - opt.MapFrom(src => !string.IsNullOrEmpty(src.CookTime) ? src.CookTime : "")); - - config.CreateMap() - .ForMember(dest => dest.Steps, opt => opt.MapFrom(src => src.Steps)).ReverseMap(); - - config.CreateMap().ReverseMap(); - - config.CreateMap() - .ForMember(dest => dest.Steps, opt => opt.MapFrom(src => src.Steps)).ReverseMap(); - - //Grpc mapping - config.CreateMap() - .ForMember(dest => dest.Steps, opt => opt.MapFrom(src => src.Steps)) - .ForMember(dest => dest.CookTime, opt => opt.MapFrom(src => src.CookTime)) - .ReverseMap() - .ForMember(dest => dest.Steps, opt => opt.MapFrom(src => src.Steps)) - .ForMember(dest => dest.CookTime, opt => - opt.MapFrom(src => !string.IsNullOrEmpty(src.CookTime) ? src.CookTime : "")); - - config.CreateMap().ReverseMap(); - - config.CreateMap() - .ForMember( - dest => dest.Status, - opt => opt.MapFrom(src => Enum.Parse(src.Status)) - ) - .ForMember( - dest => dest.Category, - opt => opt.MapFrom(src => Enum.Parse(src.Category)) - ) - .ReverseMap() - .ForMember( - dest => dest.Status, - opt => opt.MapFrom(src => src.Status.ToString()) - ) - .ForMember( - dest => dest.Category, - opt => opt.MapFrom(src => src.Category.ToString()) - ); - - ///////////////////////////////////////////////////// - - - config.CreateMap().ReverseMap(); - - config.CreateMap() - .ForMember( - dest => dest.Status, - opt => opt.MapFrom(src => Enum.Parse(src.Status)) - ) - .ForMember( - dest => dest.Category, - opt => opt.MapFrom(src => Enum.Parse(src.Category)) - ) - .ReverseMap() - .ForMember( - dest => dest.Status, - opt => opt.MapFrom(src => src.Status.ToString()) - ) - .ForMember( - dest => dest.Category, - opt => opt.MapFrom(src => src.Category.ToString()) - ); - - - }); - - return mappingConfig; - } -} diff --git a/app/server/RecipeService/src/RecipeService.API/Configs/RecipeProfile.cs b/app/server/RecipeService/src/RecipeService.API/Configs/RecipeProfile.cs new file mode 100644 index 000000000..fddf2177b --- /dev/null +++ b/app/server/RecipeService/src/RecipeService.API/Configs/RecipeProfile.cs @@ -0,0 +1,89 @@ +using AutoMapper; +using Contract.DTOs.RecipeDTO; +using RecipeProto; +using RecipeService.API.DTOs; +using RecipeService.Application.Recipes.Commands; +using RecipeService.Domain.Entities; + +namespace RecipeService.API.Configs; + +public class RecipeProfile : Profile +{ + public RecipeProfile() + { + CreateMap() + .ForMember(dest => dest.Steps, opt => opt.MapFrom(src => src.Steps)).ReverseMap(); + + CreateMap().ReverseMap(); + + CreateMap() + .ForMember(dest => dest.Steps, opt => opt.MapFrom(src => src.Steps)) + .ForMember(dest => dest.CookTime, opt => opt.MapFrom(src => src.CookTime)) + .ReverseMap() + .ForMember(dest => dest.Steps, opt => opt.MapFrom(src => src.Steps)) + .ForMember(dest => dest.CookTime, opt => + opt.MapFrom(src => !string.IsNullOrEmpty(src.CookTime) ? src.CookTime : "")); + + CreateMap() + .ForMember(dest => dest.Steps, opt => opt.MapFrom(src => src.Steps)).ReverseMap(); + + CreateMap().ReverseMap(); + + CreateMap() + .ForMember(dest => dest.Steps, opt => opt.MapFrom(src => src.Steps)).ReverseMap(); + + //Grpc mapping + CreateMap() + .ForMember(dest => dest.Steps, opt => opt.MapFrom(src => src.Steps)) + .ForMember(dest => dest.CookTime, opt => opt.MapFrom(src => src.CookTime)) + .ReverseMap() + .ForMember(dest => dest.Steps, opt => opt.MapFrom(src => src.Steps)) + .ForMember(dest => dest.CookTime, opt => + opt.MapFrom(src => !string.IsNullOrEmpty(src.CookTime) ? src.CookTime : "")); + + CreateMap().ReverseMap(); + + CreateMap() + .ForMember( + dest => dest.Status, + opt => opt.MapFrom(src => Enum.Parse(src.Status)) + ) + .ForMember( + dest => dest.Category, + opt => opt.MapFrom(src => Enum.Parse(src.Category)) + ) + .ReverseMap() + .ForMember( + dest => dest.Status, + opt => opt.MapFrom(src => src.Status.ToString()) + ) + .ForMember( + dest => dest.Category, + opt => opt.MapFrom(src => src.Category.ToString()) + ); + + ///////////////////////////////////////////////////// + + + CreateMap().ReverseMap(); + + CreateMap() + .ForMember( + dest => dest.Status, + opt => opt.MapFrom(src => Enum.Parse(src.Status)) + ) + .ForMember( + dest => dest.Category, + opt => opt.MapFrom(src => Enum.Parse(src.Category)) + ) + .ReverseMap() + .ForMember( + dest => dest.Status, + opt => opt.MapFrom(src => src.Status.ToString()) + ) + .ForMember( + dest => dest.Category, + opt => opt.MapFrom(src => src.Category.ToString()) + ); + } +} \ No newline at end of file diff --git a/app/server/RecipeService/src/RecipeService.API/DependenciesInjection.cs b/app/server/RecipeService/src/RecipeService.API/DependenciesInjection.cs index 21eefa4b5..0e1eb7be2 100644 --- a/app/server/RecipeService/src/RecipeService.API/DependenciesInjection.cs +++ b/app/server/RecipeService/src/RecipeService.API/DependenciesInjection.cs @@ -24,9 +24,9 @@ public static WebApplicationBuilder AddAPIServices(this WebApplicationBuilder bu services.AddSwaggerServices(); // Register automapper - IMapper mapper = MappingConfig.RegisterMaps().CreateMapper(); - services.AddSingleton(mapper); - services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); + services.AddAutoMapper( + cfg => { }, + AppDomain.CurrentDomain.GetAssemblies()); services.AddCommonAPIServices(); diff --git a/app/server/RecipeService/src/RecipeService.API/Extensions/ReinforcedTypingsExtension.cs b/app/server/RecipeService/src/RecipeService.API/Extensions/ReinforcedTypingsExtension.cs index a6eb9172d..e19796051 100644 --- a/app/server/RecipeService/src/RecipeService.API/Extensions/ReinforcedTypingsExtension.cs +++ b/app/server/RecipeService/src/RecipeService.API/Extensions/ReinforcedTypingsExtension.cs @@ -4,6 +4,7 @@ using RecipeService.Domain.Entities; using RecipeService.Domain.Errors; using RecipeService.Domain.Responses; +using Reinforced.Typings.Ast.TypeNames; using Reinforced.Typings.Fluent; using ConfigurationBuilder = Reinforced.Typings.Fluent.ConfigurationBuilder; namespace RecipeService.API.Extensions; @@ -26,6 +27,8 @@ public static void ConfigureReinforcedTypings(ConfigurationBuilder builder) Directory.CreateDirectory(EXPORT_FILE_PATH); builder.ConfigCommonReinforcedTypings(EXPORT_FILE_PATH, FILE_NAME, errorsTypes); + builder.Substitute(typeof(IFormFile), new RtSimpleTypeName("any")); + builder.Substitute(typeof(TagValue), new RtSimpleTypeName("any")); // DTO and Entites builder.ExportAsInterfaces([ typeof(DateStatisticEntity), diff --git a/app/server/RecipeService/src/RecipeService.Application/Configs/MappingConfig.cs b/app/server/RecipeService/src/RecipeService.Application/Configs/MappingConfig.cs deleted file mode 100644 index 2dcf82666..000000000 --- a/app/server/RecipeService/src/RecipeService.Application/Configs/MappingConfig.cs +++ /dev/null @@ -1,56 +0,0 @@ -using AutoMapper; -using Contract.DTOs.UserDTO; -using Google.Protobuf.Collections; -using RecipeProto; -using RecipeService.Application.Configs.MapperConverters; -using RecipeService.Domain.Entities; -using RecipeService.Domain.Responses; -using UserProto; - -namespace RecipeService.Application.Configs; - -public class MappingConfig -{ - public static MapperConfiguration RegisterMaps() - { - var mappingConfig = new MapperConfiguration(config => - { - config.CreateMap() - .ForMember(dest => dest.DisplayName, opt => opt.Ignore()) - .ForMember(dest => dest.AvatarUrl, opt => opt.Ignore()) - .ReverseMap(); - - config.CreateMap() - .ForMember(dest => dest.ImageUrl, opt => opt.MapFrom(src => src.RecipeImgUrl)) - .ReverseMap(); - - config.CreateMap() - .ForMember(dest => dest.Status, opt => opt.MapFrom(src => src.Status.ToString())) - .ReverseMap() - .ForMember(dest => dest.Status, opt => opt.MapFrom(src => Enum.Parse(typeof(TagStatus), src.Status))); - - // Grpc mapping - config.CreateMap(typeof(List<>), typeof(RepeatedField<>)).ConvertUsing(typeof(ListToRepeatedFieldConverter<,>)); - config.CreateMap(typeof(RepeatedField<>), typeof(List<>)).ConvertUsing(typeof(RepeatedFieldToListConverter<,>)); - - config.CreateMap() - .ForMember(dest => dest.Users, - opt => opt.MapFrom(src => src.Users.ToDictionary( - user => user.Key, - user => new CommonProto.GrpcSimpleUser - { - AccountId = user.Value.AccountId.ToString(), - AvtUrl = user.Value.AvtUrl, - DisplayName = user.Value.DisplayName - }))).ReverseMap(); - - config.CreateMap() - .ReverseMap(); - - }); - //mappingConfig.AssertConfigurationIsValid(); - - - return mappingConfig; - } -} diff --git a/app/server/RecipeService/src/RecipeService.Application/Configs/RecipeProfile.cs b/app/server/RecipeService/src/RecipeService.Application/Configs/RecipeProfile.cs new file mode 100644 index 000000000..0ba25dc25 --- /dev/null +++ b/app/server/RecipeService/src/RecipeService.Application/Configs/RecipeProfile.cs @@ -0,0 +1,48 @@ +using AutoMapper; +using Contract.DTOs.UserDTO; +using Google.Protobuf.Collections; +using RecipeProto; +using RecipeService.Application.Configs.MapperConverters; +using RecipeService.Domain.Entities; +using RecipeService.Domain.Responses; +using UserProto; + +namespace RecipeService.Application.Configs; + +public class RecipeProfile : Profile +{ + public RecipeProfile() + { + CreateMap() + .ForMember(dest => dest.DisplayName, opt => opt.Ignore()) + .ForMember(dest => dest.AvatarUrl, opt => opt.Ignore()) + .ReverseMap(); + + CreateMap() + .ForMember(dest => dest.ImageUrl, opt => opt.MapFrom(src => src.RecipeImgUrl)) + .ReverseMap(); + + CreateMap() + .ForMember(dest => dest.Status, opt => opt.MapFrom(src => src.Status.ToString())) + .ReverseMap() + .ForMember(dest => dest.Status, opt => opt.MapFrom(src => Enum.Parse(typeof(TagStatus), src.Status))); + + // Grpc mapping + CreateMap(typeof(List<>), typeof(RepeatedField<>)).ConvertUsing(typeof(ListToRepeatedFieldConverter<,>)); + CreateMap(typeof(RepeatedField<>), typeof(List<>)).ConvertUsing(typeof(RepeatedFieldToListConverter<,>)); + + CreateMap() + .ForMember(dest => dest.Users, + opt => opt.MapFrom(src => src.Users.ToDictionary( + user => user.Key, + user => new CommonProto.GrpcSimpleUser + { + AccountId = user.Value.AccountId.ToString(), + AvtUrl = user.Value.AvtUrl, + DisplayName = user.Value.DisplayName + }))).ReverseMap(); + + CreateMap() + .ReverseMap(); + } +} \ No newline at end of file diff --git a/app/server/RecipeService/src/RecipeService.Application/DependencyInjection.cs b/app/server/RecipeService/src/RecipeService.Application/DependencyInjection.cs index 0aa6600e6..990786769 100644 --- a/app/server/RecipeService/src/RecipeService.Application/DependencyInjection.cs +++ b/app/server/RecipeService/src/RecipeService.Application/DependencyInjection.cs @@ -18,9 +18,9 @@ public static IServiceCollection AddApplicationServices(this IServiceCollection { services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly())); // Register automapper - IMapper mapper = MappingConfig.RegisterMaps().CreateMapper(); - services.AddSingleton(mapper); - services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); + services.AddAutoMapper( + cfg => { }, + AppDomain.CurrentDomain.GetAssemblies()); //Grpc services.AddGrpcClientService(); diff --git a/app/server/RecipeService/src/RecipeService.Application/RecipeService.Application.csproj b/app/server/RecipeService/src/RecipeService.Application/RecipeService.Application.csproj index c94400eb5..4b7be187b 100644 --- a/app/server/RecipeService/src/RecipeService.Application/RecipeService.Application.csproj +++ b/app/server/RecipeService/src/RecipeService.Application/RecipeService.Application.csproj @@ -6,7 +6,7 @@ - + diff --git a/app/server/RecipeService/src/RecipeService.Application/ReportReasons/Queries/GetReportReasonsQueryHandler.cs b/app/server/RecipeService/src/RecipeService.Application/ReportReasons/Queries/GetReportReasonsQueryHandler.cs index 039b38939..a100b6ba9 100644 --- a/app/server/RecipeService/src/RecipeService.Application/ReportReasons/Queries/GetReportReasonsQueryHandler.cs +++ b/app/server/RecipeService/src/RecipeService.Application/ReportReasons/Queries/GetReportReasonsQueryHandler.cs @@ -11,14 +11,14 @@ public class GetReportReasonsQuery : IRequest? public class GetReportReasonsQueryHandler : IRequestHandler?>> { - public async Task?>> Handle(GetReportReasonsQuery request, CancellationToken cancellationToken) + public Task?>> Handle(GetReportReasonsQuery request, CancellationToken cancellationToken) { var lang = request.Language; var type = request.ReportType; if (string.IsNullOrEmpty(lang) || string.IsNullOrEmpty(type)) { - return Result?>.Failure(RecipeError.NullParameter); + return Task.FromResult(Result?>.Failure(RecipeError.NullParameter)); } if (type == "Recipe") @@ -29,10 +29,10 @@ public class GetReportReasonsQueryHandler : IRequestHandler?>.Failure(RecipeError.NotFound, "Not found report recipe reason"); + return Task.FromResult(Result?>.Failure(RecipeError.NotFound, "Not found report recipe reason")); } - return Result?>.Success(reasons); + return Task.FromResult(Result?>.Success(reasons)); } if (type == "Comment") @@ -43,12 +43,12 @@ public class GetReportReasonsQueryHandler : IRequestHandler?>.Failure(RecipeError.NotFound, "Not found report comment reason"); + return Task.FromResult(Result?>.Failure(RecipeError.NotFound, "Not found report comment reason")); } - return Result?>.Success(reasons); + return Task.FromResult(Result?>.Success(reasons)); } - return Result?>.Failure(RecipeError.NotFound); + return Task.FromResult(Result?>.Failure(RecipeError.NotFound)); } } diff --git a/app/server/RecipeService/src/RecipeWorker/Worker.cs b/app/server/RecipeService/src/RecipeWorker/Worker.cs index a077553be..b3baf885c 100644 --- a/app/server/RecipeService/src/RecipeWorker/Worker.cs +++ b/app/server/RecipeService/src/RecipeWorker/Worker.cs @@ -16,7 +16,7 @@ public Task StartingAsync(CancellationToken cancellationToken) _logger.LogInformation("Recipe worker starting"); return Task.CompletedTask; } - public async Task StartAsync(CancellationToken cancellationToken) + public Task StartAsync(CancellationToken cancellationToken) { _logger.LogInformation("Recipe worker start"); try @@ -26,6 +26,7 @@ public async Task StartAsync(CancellationToken cancellationToken) { _logger.LogError(ex.Message); } + return Task.CompletedTask; } public Task StartedAsync(CancellationToken cancellationToken) { @@ -37,9 +38,10 @@ public Task StoppingAsync(CancellationToken cancellationToken) _logger.LogInformation("Recipe worker stopping"); return Task.CompletedTask; } - public async Task StopAsync(CancellationToken cancellationToken) + public Task StopAsync(CancellationToken cancellationToken) { _logger.LogInformation("Recipe worker stop"); + return Task.CompletedTask; } public Task StoppedAsync(CancellationToken cancellationToken) { From a0fbe1cecd41d167a1e160b982c7dbc8d4e8a04a Mon Sep 17 00:00:00 2001 From: Carl-Johnsons Date: Fri, 12 Jun 2026 14:29:02 +0700 Subject: [PATCH 12/14] chore: clear notification service warnings --- .../src/EmailWorker/EmailWorker.csproj | 2 +- .../AppCommandHandler.cs | 6 ++-- .../Configs/MappingConfig.cs | 34 ------------------- .../Configs/NotificationProfile.cs | 28 +++++++++++++++ .../DependencyInjection.cs | 6 ++-- .../NotificationService.Application.csproj | 2 +- 6 files changed, 36 insertions(+), 42 deletions(-) delete mode 100644 app/server/NotificationService/src/NotificationService.Application/Configs/MappingConfig.cs create mode 100644 app/server/NotificationService/src/NotificationService.Application/Configs/NotificationProfile.cs diff --git a/app/server/NotificationService/src/EmailWorker/EmailWorker.csproj b/app/server/NotificationService/src/EmailWorker/EmailWorker.csproj index 4728ffc44..b5d80bd61 100644 --- a/app/server/NotificationService/src/EmailWorker/EmailWorker.csproj +++ b/app/server/NotificationService/src/EmailWorker/EmailWorker.csproj @@ -16,7 +16,7 @@ - + diff --git a/app/server/NotificationService/src/NotificationService.API/AppCommandHandler.cs b/app/server/NotificationService/src/NotificationService.API/AppCommandHandler.cs index 7ed170701..e5f13cf80 100644 --- a/app/server/NotificationService/src/NotificationService.API/AppCommandHandler.cs +++ b/app/server/NotificationService/src/NotificationService.API/AppCommandHandler.cs @@ -6,7 +6,7 @@ namespace NotificationService.API; public static class AppCommandHandler { - public static async Task TryHandleAsync(this WebApplicationBuilder builder, string[] args) + public static Task TryHandleAsync(this WebApplicationBuilder builder, string[] args) { var uniqueArgs = args .Where(COMMAND_ARGS.All.Contains) @@ -14,7 +14,7 @@ public static async Task TryHandleAsync(this WebApplicationBuilder builder .ToArray(); if (uniqueArgs.Length == 0) { - return false; + return Task.FromResult(false); } builder.Services.AddMinimalInfrastructureServices(); @@ -31,6 +31,6 @@ public static async Task TryHandleAsync(this WebApplicationBuilder builder break; } } - return true; + return Task.FromResult(true); } } \ No newline at end of file diff --git a/app/server/NotificationService/src/NotificationService.Application/Configs/MappingConfig.cs b/app/server/NotificationService/src/NotificationService.Application/Configs/MappingConfig.cs deleted file mode 100644 index 3cec212b1..000000000 --- a/app/server/NotificationService/src/NotificationService.Application/Configs/MappingConfig.cs +++ /dev/null @@ -1,34 +0,0 @@ -using AutoMapper; -using Contract.DTOs.UserDTO; -using Google.Protobuf.Collections; -using NotificationService.Application.Configs.MapperConverters; -using UserProto; - -namespace NotificationService.Application.Configs; - -public class MappingConfig -{ - public static MapperConfiguration RegisterMaps() - { - var mappingConfig = new MapperConfiguration(config => - { - // Grpc mapping - config.CreateMap(typeof(List<>), typeof(RepeatedField<>)).ConvertUsing(typeof(ListToRepeatedFieldConverter<,>)); - config.CreateMap(typeof(RepeatedField<>), typeof(List<>)).ConvertUsing(typeof(RepeatedFieldToListConverter<,>)); - - config.CreateMap() - .ForMember(dest => dest.Users, - opt => opt.MapFrom(src => src.Users.ToDictionary( - user => user.Key, - user => new CommonProto.GrpcSimpleUser - { - AccountId = user.Value.AccountId.ToString(), - AvtUrl = user.Value.AvtUrl, - DisplayName = user.Value.DisplayName - }))).ReverseMap(); - }); - //mappingConfig.AssertConfigurationIsValid(); - - return mappingConfig; - } -} diff --git a/app/server/NotificationService/src/NotificationService.Application/Configs/NotificationProfile.cs b/app/server/NotificationService/src/NotificationService.Application/Configs/NotificationProfile.cs new file mode 100644 index 000000000..5f4239196 --- /dev/null +++ b/app/server/NotificationService/src/NotificationService.Application/Configs/NotificationProfile.cs @@ -0,0 +1,28 @@ +using AutoMapper; +using Contract.DTOs.UserDTO; +using Google.Protobuf.Collections; +using NotificationService.Application.Configs.MapperConverters; +using UserProto; + +namespace NotificationService.Application.Configs; + +public class NotificationProfile : Profile +{ + public NotificationProfile() + { + // Grpc mapping + CreateMap(typeof(List<>), typeof(RepeatedField<>)).ConvertUsing(typeof(ListToRepeatedFieldConverter<,>)); + CreateMap(typeof(RepeatedField<>), typeof(List<>)).ConvertUsing(typeof(RepeatedFieldToListConverter<,>)); + + CreateMap() + .ForMember(dest => dest.Users, + opt => opt.MapFrom(src => src.Users.ToDictionary( + user => user.Key, + user => new CommonProto.GrpcSimpleUser + { + AccountId = user.Value.AccountId.ToString(), + AvtUrl = user.Value.AvtUrl, + DisplayName = user.Value.DisplayName + }))).ReverseMap(); + } +} \ No newline at end of file diff --git a/app/server/NotificationService/src/NotificationService.Application/DependencyInjection.cs b/app/server/NotificationService/src/NotificationService.Application/DependencyInjection.cs index 5195aec17..44b788b96 100644 --- a/app/server/NotificationService/src/NotificationService.Application/DependencyInjection.cs +++ b/app/server/NotificationService/src/NotificationService.Application/DependencyInjection.cs @@ -11,9 +11,9 @@ public static class DependencyInjection public static IServiceCollection AddApplicationServices(this IServiceCollection services) { // Register automapper - IMapper mapper = MappingConfig.RegisterMaps().CreateMapper(); - services.AddSingleton(mapper); - services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); + services.AddAutoMapper( + cfg => { }, + AppDomain.CurrentDomain.GetAssemblies()); services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly())); services.AddGrpcClientService(); return services; diff --git a/app/server/NotificationService/src/NotificationService.Application/NotificationService.Application.csproj b/app/server/NotificationService/src/NotificationService.Application/NotificationService.Application.csproj index b83087536..1bb113f8c 100644 --- a/app/server/NotificationService/src/NotificationService.Application/NotificationService.Application.csproj +++ b/app/server/NotificationService/src/NotificationService.Application/NotificationService.Application.csproj @@ -6,7 +6,7 @@ enable - + From dc2877315d1e3849d89efac2e7ef214343439436 Mon Sep 17 00:00:00 2001 From: Carl-Johnsons Date: Fri, 12 Jun 2026 15:09:21 +0700 Subject: [PATCH 13/14] chore: clear tracking service warnings --- .../TrackingService.API/AppCommandHandler.cs | 6 ++--- .../Configs/MappingConfig.cs | 17 -------------- .../Controllers/TrackingController.cs | 12 +++++----- .../DependenciesInjection.cs | 10 ++++---- .../Configs/MappingConfig.cs | 23 ------------------- .../Configs/TrackingProfile.cs | 15 ++++++++++++ .../DependencyInjection.cs | 6 ++--- .../TrackingService.Application.csproj | 2 +- .../SearchUserViewRecipeDetaiQueryHandler.cs | 9 ++++++-- 9 files changed, 39 insertions(+), 61 deletions(-) delete mode 100644 app/server/TrackingService/src/TrackingService.API/Configs/MappingConfig.cs delete mode 100644 app/server/TrackingService/src/TrackingService.Application/Configs/MappingConfig.cs create mode 100644 app/server/TrackingService/src/TrackingService.Application/Configs/TrackingProfile.cs diff --git a/app/server/TrackingService/src/TrackingService.API/AppCommandHandler.cs b/app/server/TrackingService/src/TrackingService.API/AppCommandHandler.cs index dfd6ef937..f38225074 100644 --- a/app/server/TrackingService/src/TrackingService.API/AppCommandHandler.cs +++ b/app/server/TrackingService/src/TrackingService.API/AppCommandHandler.cs @@ -6,7 +6,7 @@ namespace TrackingService.API; public static class AppCommandHandler { - public static async Task TryHandleAsync(this WebApplicationBuilder builder, string[] args) + public static Task TryHandleAsync(this WebApplicationBuilder builder, string[] args) { var uniqueArgs = args .Where(COMMAND_ARGS.All.Contains) @@ -14,7 +14,7 @@ public static async Task TryHandleAsync(this WebApplicationBuilder builder .ToArray(); if (uniqueArgs.Length == 0) { - return false; + return Task.FromResult(false); } builder.Services.AddMinimalInfrastructureServices(); @@ -31,6 +31,6 @@ public static async Task TryHandleAsync(this WebApplicationBuilder builder break; } } - return true; + return Task.FromResult(true); } } \ No newline at end of file diff --git a/app/server/TrackingService/src/TrackingService.API/Configs/MappingConfig.cs b/app/server/TrackingService/src/TrackingService.API/Configs/MappingConfig.cs deleted file mode 100644 index 1d1411895..000000000 --- a/app/server/TrackingService/src/TrackingService.API/Configs/MappingConfig.cs +++ /dev/null @@ -1,17 +0,0 @@ -using AutoMapper; - -namespace TrackingService.API.Configs; - -public class MappingConfig -{ - public static MapperConfiguration RegisterMaps() - { - var mappingConfig = new MapperConfiguration(config => - { - - - }); - - return mappingConfig; - } -} diff --git a/app/server/TrackingService/src/TrackingService.API/Controllers/TrackingController.cs b/app/server/TrackingService/src/TrackingService.API/Controllers/TrackingController.cs index b0a6420a1..97e45a080 100644 --- a/app/server/TrackingService/src/TrackingService.API/Controllers/TrackingController.cs +++ b/app/server/TrackingService/src/TrackingService.API/Controllers/TrackingController.cs @@ -34,7 +34,7 @@ public async Task GetUserViewRecipeDetailHistory([FromBody] GetUs Skip = getUserViewRecipeDetailHistoryDTO.Skip, }); result.ThrowIfFailure(); - return Ok(result); + return Ok(result.Value); } [HttpPost("search-user-view-recipe-detail-history")] @@ -52,7 +52,7 @@ public async Task SearchUserViewRecipeDetailHistory([FromBody] Se Keyword = searchUserViewRecipeDetailHistoryDTO.Keyword }); result.ThrowIfFailure(); - return Ok(result); + return Ok(result.Value); } [HttpGet("get-user-search-recipe-history")] @@ -68,7 +68,7 @@ public async Task GetUserSearchRecipe() AccountId = Guid.Parse(subjectId!), }); result.ThrowIfFailure(); - return Ok(result); + return Ok(result.Value); } [HttpGet("get-user-search-user-history")] @@ -84,7 +84,7 @@ public async Task GetUserSearchUser() AccountId = Guid.Parse(subjectId!), }); result.ThrowIfFailure(); - return Ok(result); + return Ok(result.Value); } [HttpPost("delete-user-search-user-history")] @@ -101,7 +101,7 @@ public async Task DeleteUserSearchUser([FromBody] DeleteUserSearc Keyword = deleteUserSearchUserKeywordDTO.Keyword, }); result.ThrowIfFailure(); - return Ok(result); + return Ok(result.Value); } [HttpPost("delete-user-search-recipe-history")] @@ -118,6 +118,6 @@ public async Task DeleteUserSearchRecipe([FromBody] DeleteUserSea Keyword = deleteUserSearchRecipeKeywordDTO.Keyword, }); result.ThrowIfFailure(); - return Ok(result); + return Ok(result.Value); } } diff --git a/app/server/TrackingService/src/TrackingService.API/DependenciesInjection.cs b/app/server/TrackingService/src/TrackingService.API/DependenciesInjection.cs index 3cb00df2e..5edbe38a3 100644 --- a/app/server/TrackingService/src/TrackingService.API/DependenciesInjection.cs +++ b/app/server/TrackingService/src/TrackingService.API/DependenciesInjection.cs @@ -1,6 +1,4 @@ -using AutoMapper; -using TrackingService.API.Configs; -using TrackingService.Infrastructure; +using TrackingService.Infrastructure; using TrackingService.Application; using Contract.Utilities; using TrackingService.API.Extensions; @@ -24,9 +22,9 @@ public static WebApplicationBuilder AddAPIServices(this WebApplicationBuilder bu services.AddSwaggerServices(); // Register automapper - IMapper mapper = MappingConfig.RegisterMaps().CreateMapper(); - services.AddSingleton(mapper); - services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); + services.AddAutoMapper( + cfg => { }, + AppDomain.CurrentDomain.GetAssemblies()); services.AddCommonAPIServices(); diff --git a/app/server/TrackingService/src/TrackingService.Application/Configs/MappingConfig.cs b/app/server/TrackingService/src/TrackingService.Application/Configs/MappingConfig.cs deleted file mode 100644 index 031c0c443..000000000 --- a/app/server/TrackingService/src/TrackingService.Application/Configs/MappingConfig.cs +++ /dev/null @@ -1,23 +0,0 @@ -using AutoMapper; -using Google.Protobuf.Collections; -using TrackingService.Application.Configs.MapperConverters; -using TrackingService.Domain.Responses; - -namespace TrackingService.Application.Configs; - -public class MappingConfig -{ - public static MapperConfiguration RegisterMaps() - { - var mappingConfig = new MapperConfiguration(config => - { - //Grpc - config.CreateMap(typeof(List<>), typeof(RepeatedField<>)).ConvertUsing(typeof(ListToRepeatedFieldConverter<,>)); - config.CreateMap(typeof(RepeatedField<>), typeof(List<>)).ConvertUsing(typeof(RepeatedFieldToListConverter<,>)); - }); - - - - return mappingConfig; - } -} diff --git a/app/server/TrackingService/src/TrackingService.Application/Configs/TrackingProfile.cs b/app/server/TrackingService/src/TrackingService.Application/Configs/TrackingProfile.cs new file mode 100644 index 000000000..fa0d59139 --- /dev/null +++ b/app/server/TrackingService/src/TrackingService.Application/Configs/TrackingProfile.cs @@ -0,0 +1,15 @@ +using AutoMapper; +using Google.Protobuf.Collections; +using TrackingService.Application.Configs.MapperConverters; + +namespace TrackingService.Application.Configs; + +public class TrackingProfile : Profile +{ + public TrackingProfile() + { + //Grpc + CreateMap(typeof(List<>), typeof(RepeatedField<>)).ConvertUsing(typeof(ListToRepeatedFieldConverter<,>)); + CreateMap(typeof(RepeatedField<>), typeof(List<>)).ConvertUsing(typeof(RepeatedFieldToListConverter<,>)); + } +} \ No newline at end of file diff --git a/app/server/TrackingService/src/TrackingService.Application/DependencyInjection.cs b/app/server/TrackingService/src/TrackingService.Application/DependencyInjection.cs index 806223296..cf1a9c98c 100644 --- a/app/server/TrackingService/src/TrackingService.Application/DependencyInjection.cs +++ b/app/server/TrackingService/src/TrackingService.Application/DependencyInjection.cs @@ -15,9 +15,9 @@ public static IServiceCollection AddApplicationServices(this IServiceCollection { services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly())); // Register automapper - IMapper mapper = MappingConfig.RegisterMaps().CreateMapper(); - services.AddSingleton(mapper); - services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); + services.AddAutoMapper( + cfg => { }, + AppDomain.CurrentDomain.GetAssemblies()); //Grpc services.AddGrpcClientService(); diff --git a/app/server/TrackingService/src/TrackingService.Application/TrackingService.Application.csproj b/app/server/TrackingService/src/TrackingService.Application/TrackingService.Application.csproj index 144bd9568..aef2cb90d 100644 --- a/app/server/TrackingService/src/TrackingService.Application/TrackingService.Application.csproj +++ b/app/server/TrackingService/src/TrackingService.Application/TrackingService.Application.csproj @@ -6,7 +6,7 @@ enable - + diff --git a/app/server/TrackingService/src/TrackingService.Application/UserViewRecipeDetails/Queries/SearchUserViewRecipeDetaiQueryHandler.cs b/app/server/TrackingService/src/TrackingService.Application/UserViewRecipeDetails/Queries/SearchUserViewRecipeDetaiQueryHandler.cs index 51064b691..43816cfa6 100644 --- a/app/server/TrackingService/src/TrackingService.Application/UserViewRecipeDetails/Queries/SearchUserViewRecipeDetaiQueryHandler.cs +++ b/app/server/TrackingService/src/TrackingService.Application/UserViewRecipeDetails/Queries/SearchUserViewRecipeDetaiQueryHandler.cs @@ -1,5 +1,6 @@ using AutoMapper; using Google.Protobuf.Collections; +using Microsoft.EntityFrameworkCore; using RecipeProto; using TrackingService.Domain.Entities; using TrackingService.Domain.Errors; @@ -43,8 +44,12 @@ public SearchUserViewRecipeDetaiQueryHandler(GrpcRecipe.GrpcRecipeClient grpcRec } var viewsQuery = _context.UserViewRecipeDetails.Where(v => v.AccountId == accountId).OrderByDescending(v => v.UpdatedAt).AsQueryable(); - var views = viewsQuery.ToHashSet(); - var viewsMap = viewsQuery.ToDictionary(v => v.RecipeId.ToString()); + var views = await viewsQuery.ToListAsync(cancellationToken); + var viewsMap = views + .GroupBy(v => v.RecipeId) + .ToDictionary( + g => g.Key.ToString(), + g => g.OrderByDescending(x => x.UpdatedAt).First()); if (views == null || views.Count == 0) { From 53cb664b8f00f45fd330430ac1d07807362a12d5 Mon Sep 17 00:00:00 2001 From: Carl-Johnsons Date: Fri, 12 Jun 2026 15:28:17 +0700 Subject: [PATCH 14/14] chore: config automapper license --- .../DTOs/IdentityProfile.cs | 16 +++++++++ .../DTOs/MappingConfig.cs | 21 ----------- .../DuendeIdentityServer.csproj | 3 -- .../DuendeIdentityServer/HostingExtensions.cs | 7 ++-- .../Configs/IdentityProfile.cs | 14 ++++++++ .../Configs/MappingConfig.cs | 19 ---------- .../DependencyInjection.cs | 7 ++-- .../DependencyInjection.cs | 5 ++- .../DependenciesInjection.cs | 5 ++- .../DependencyInjection.cs | 5 ++- .../DependenciesInjection.cs | 5 ++- .../DependencyInjection.cs | 5 ++- .../Configs/MappingConfig.cs | 35 ------------------- .../Configs/UploadProfile.cs | 29 +++++++++++++++ .../DependenciesInjection.cs | 5 ++- .../UserService.API/DependenciesInjection.cs | 5 ++- .../DependencyInjection.cs | 5 ++- 17 files changed, 99 insertions(+), 92 deletions(-) create mode 100644 app/server/IdentityService/src/DuendeIdentityServer/DTOs/IdentityProfile.cs delete mode 100755 app/server/IdentityService/src/DuendeIdentityServer/DTOs/MappingConfig.cs create mode 100644 app/server/IdentityService/src/IdentityService.Application/Configs/IdentityProfile.cs delete mode 100644 app/server/IdentityService/src/IdentityService.Application/Configs/MappingConfig.cs delete mode 100644 app/server/UploadFileService/src/UploadFileService.API/Configs/MappingConfig.cs create mode 100644 app/server/UploadFileService/src/UploadFileService.API/Configs/UploadProfile.cs diff --git a/app/server/IdentityService/src/DuendeIdentityServer/DTOs/IdentityProfile.cs b/app/server/IdentityService/src/DuendeIdentityServer/DTOs/IdentityProfile.cs new file mode 100644 index 000000000..795c7adbb --- /dev/null +++ b/app/server/IdentityService/src/DuendeIdentityServer/DTOs/IdentityProfile.cs @@ -0,0 +1,16 @@ +using AutoMapper; +using Contract.DTOs.UserDTO; +using IdentityService.Application.Account.Commands; + +namespace DuendeIdentityServer.DTOs; + +public class IdentityProfile : Profile +{ + public IdentityProfile() + { + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + } +} diff --git a/app/server/IdentityService/src/DuendeIdentityServer/DTOs/MappingConfig.cs b/app/server/IdentityService/src/DuendeIdentityServer/DTOs/MappingConfig.cs deleted file mode 100755 index d6a56746a..000000000 --- a/app/server/IdentityService/src/DuendeIdentityServer/DTOs/MappingConfig.cs +++ /dev/null @@ -1,21 +0,0 @@ -using AutoMapper; -using Contract.DTOs.UserDTO; -using IdentityService.Application.Account.Commands; - -namespace DuendeIdentityServer.DTOs; - -public class MappingConfig -{ - public static MapperConfiguration RegisterMaps() - { - var mappingConfig = new MapperConfiguration(config => - { - config.CreateMap().ReverseMap(); - config.CreateMap().ReverseMap(); - config.CreateMap().ReverseMap(); - config.CreateMap().ReverseMap(); - }, null); - - return mappingConfig; - } -} \ No newline at end of file diff --git a/app/server/IdentityService/src/DuendeIdentityServer/DuendeIdentityServer.csproj b/app/server/IdentityService/src/DuendeIdentityServer/DuendeIdentityServer.csproj index a94b09b17..27cc8e3fa 100755 --- a/app/server/IdentityService/src/DuendeIdentityServer/DuendeIdentityServer.csproj +++ b/app/server/IdentityService/src/DuendeIdentityServer/DuendeIdentityServer.csproj @@ -15,9 +15,6 @@ - - - diff --git a/app/server/IdentityService/src/DuendeIdentityServer/HostingExtensions.cs b/app/server/IdentityService/src/DuendeIdentityServer/HostingExtensions.cs index 9d82a9de9..04906f9ee 100755 --- a/app/server/IdentityService/src/DuendeIdentityServer/HostingExtensions.cs +++ b/app/server/IdentityService/src/DuendeIdentityServer/HostingExtensions.cs @@ -44,10 +44,11 @@ public static WebApplication ConfigureServices(this WebApplicationBuilder builde }); // Register automapper - // IMapper mapper = MappingConfig.RegisterMaps().CreateMapper(); - // services.AddSingleton(mapper); services.AddAutoMapper( - cfg => { }, + cfg => + { + cfg.LicenseKey = DotNetEnv.Env.GetString("LUCKYPENNYSOFTWARE_LICENSE_KEY", "Not Found"); + }, AppDomain.CurrentDomain.GetAssemblies()); services.AddCommonAPIWithoutAuthServices(); diff --git a/app/server/IdentityService/src/IdentityService.Application/Configs/IdentityProfile.cs b/app/server/IdentityService/src/IdentityService.Application/Configs/IdentityProfile.cs new file mode 100644 index 000000000..180893106 --- /dev/null +++ b/app/server/IdentityService/src/IdentityService.Application/Configs/IdentityProfile.cs @@ -0,0 +1,14 @@ +using AutoMapper; +using Google.Protobuf.Collections; +using IdentityService.Application.Configs.MapperConverters; + +namespace IdentityService.Application.Configs; + +public class IdentityProfile : Profile +{ + public IdentityProfile() + { + CreateMap(typeof(List<>), typeof(RepeatedField<>)).ConvertUsing(typeof(ListToRepeatedFieldConverter<,>)); + CreateMap(typeof(RepeatedField<>), typeof(List<>)).ConvertUsing(typeof(RepeatedFieldToListConverter<,>)); + } +} diff --git a/app/server/IdentityService/src/IdentityService.Application/Configs/MappingConfig.cs b/app/server/IdentityService/src/IdentityService.Application/Configs/MappingConfig.cs deleted file mode 100644 index 937ffd1f5..000000000 --- a/app/server/IdentityService/src/IdentityService.Application/Configs/MappingConfig.cs +++ /dev/null @@ -1,19 +0,0 @@ -using AutoMapper; -using Google.Protobuf.Collections; -using IdentityService.Application.Configs.MapperConverters; - -namespace IdentityService.Application.Configs; - -public class MappingConfig -{ - public static MapperConfiguration RegisterMaps() - { - var mappingConfig = new MapperConfiguration(config => - { - config.CreateMap(typeof(List<>), typeof(RepeatedField<>)).ConvertUsing(typeof(ListToRepeatedFieldConverter<,>)); - config.CreateMap(typeof(RepeatedField<>), typeof(List<>)).ConvertUsing(typeof(RepeatedFieldToListConverter<,>)); - }, null); - - return mappingConfig; - } -} diff --git a/app/server/IdentityService/src/IdentityService.Application/DependencyInjection.cs b/app/server/IdentityService/src/IdentityService.Application/DependencyInjection.cs index e7f89d7d7..cf05e8450 100644 --- a/app/server/IdentityService/src/IdentityService.Application/DependencyInjection.cs +++ b/app/server/IdentityService/src/IdentityService.Application/DependencyInjection.cs @@ -15,10 +15,11 @@ public static IServiceCollection AddApplicationServices(this IServiceCollection services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly())); services.AddGrpcClientServices(); // Register automapper - // IMapper mapper = MappingConfig.RegisterMaps().CreateMapper(); - // services.AddSingleton(mapper); services.AddAutoMapper( - cfg => { }, + cfg => + { + cfg.LicenseKey = DotNetEnv.Env.GetString("LUCKYPENNYSOFTWARE_LICENSE_KEY", "Not Found"); + }, AppDomain.CurrentDomain.GetAssemblies()); return services; diff --git a/app/server/NotificationService/src/NotificationService.Application/DependencyInjection.cs b/app/server/NotificationService/src/NotificationService.Application/DependencyInjection.cs index 44b788b96..ed754816e 100644 --- a/app/server/NotificationService/src/NotificationService.Application/DependencyInjection.cs +++ b/app/server/NotificationService/src/NotificationService.Application/DependencyInjection.cs @@ -12,7 +12,10 @@ public static IServiceCollection AddApplicationServices(this IServiceCollection { // Register automapper services.AddAutoMapper( - cfg => { }, + cfg => + { + cfg.LicenseKey = DotNetEnv.Env.GetString("LUCKYPENNYSOFTWARE_LICENSE_KEY", "Not Found"); + }, AppDomain.CurrentDomain.GetAssemblies()); services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly())); services.AddGrpcClientService(); diff --git a/app/server/RecipeService/src/RecipeService.API/DependenciesInjection.cs b/app/server/RecipeService/src/RecipeService.API/DependenciesInjection.cs index 0e1eb7be2..f09668052 100644 --- a/app/server/RecipeService/src/RecipeService.API/DependenciesInjection.cs +++ b/app/server/RecipeService/src/RecipeService.API/DependenciesInjection.cs @@ -25,7 +25,10 @@ public static WebApplicationBuilder AddAPIServices(this WebApplicationBuilder bu // Register automapper services.AddAutoMapper( - cfg => { }, + cfg => + { + cfg.LicenseKey = DotNetEnv.Env.GetString("LUCKYPENNYSOFTWARE_LICENSE_KEY", "Not Found"); + }, AppDomain.CurrentDomain.GetAssemblies()); services.AddCommonAPIServices(); diff --git a/app/server/RecipeService/src/RecipeService.Application/DependencyInjection.cs b/app/server/RecipeService/src/RecipeService.Application/DependencyInjection.cs index 990786769..fd30e6f5d 100644 --- a/app/server/RecipeService/src/RecipeService.Application/DependencyInjection.cs +++ b/app/server/RecipeService/src/RecipeService.Application/DependencyInjection.cs @@ -19,7 +19,10 @@ public static IServiceCollection AddApplicationServices(this IServiceCollection services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly())); // Register automapper services.AddAutoMapper( - cfg => { }, + cfg => + { + cfg.LicenseKey = DotNetEnv.Env.GetString("LUCKYPENNYSOFTWARE_LICENSE_KEY", "Not Found"); + }, AppDomain.CurrentDomain.GetAssemblies()); //Grpc services.AddGrpcClientService(); diff --git a/app/server/TrackingService/src/TrackingService.API/DependenciesInjection.cs b/app/server/TrackingService/src/TrackingService.API/DependenciesInjection.cs index 5edbe38a3..72124f74d 100644 --- a/app/server/TrackingService/src/TrackingService.API/DependenciesInjection.cs +++ b/app/server/TrackingService/src/TrackingService.API/DependenciesInjection.cs @@ -23,7 +23,10 @@ public static WebApplicationBuilder AddAPIServices(this WebApplicationBuilder bu // Register automapper services.AddAutoMapper( - cfg => { }, + cfg => + { + cfg.LicenseKey = DotNetEnv.Env.GetString("LUCKYPENNYSOFTWARE_LICENSE_KEY", "Not Found"); + }, AppDomain.CurrentDomain.GetAssemblies()); services.AddCommonAPIServices(); diff --git a/app/server/TrackingService/src/TrackingService.Application/DependencyInjection.cs b/app/server/TrackingService/src/TrackingService.Application/DependencyInjection.cs index cf1a9c98c..4491fec9b 100644 --- a/app/server/TrackingService/src/TrackingService.Application/DependencyInjection.cs +++ b/app/server/TrackingService/src/TrackingService.Application/DependencyInjection.cs @@ -16,7 +16,10 @@ public static IServiceCollection AddApplicationServices(this IServiceCollection services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly())); // Register automapper services.AddAutoMapper( - cfg => { }, + cfg => + { + cfg.LicenseKey = DotNetEnv.Env.GetString("LUCKYPENNYSOFTWARE_LICENSE_KEY", "Not Found"); + }, AppDomain.CurrentDomain.GetAssemblies()); //Grpc diff --git a/app/server/UploadFileService/src/UploadFileService.API/Configs/MappingConfig.cs b/app/server/UploadFileService/src/UploadFileService.API/Configs/MappingConfig.cs deleted file mode 100644 index 00f12a8ea..000000000 --- a/app/server/UploadFileService/src/UploadFileService.API/Configs/MappingConfig.cs +++ /dev/null @@ -1,35 +0,0 @@ -using AutoMapper; -using Contract.DTOs.UploadFileDTO; -using Google.Protobuf; -using Google.Protobuf.Collections; -using UploadFileProto; -using UploadFileService.API.Configs.MapperConverters; -using UploadFileService.Domain.Responses; - -namespace UploadFileService.API.Configs; - -public class MappingConfig -{ - public static MapperConfiguration RegisterMaps() - { - var mappingConfig = new MapperConfiguration(config => - { - config.CreateMap().ReverseMap(); - // Grpc mapping - config.CreateMap(typeof(List<>), typeof(RepeatedField<>)).ConvertUsing(typeof(ListToRepeatedFieldConverter<,>)); - config.CreateMap(typeof(RepeatedField<>), typeof(List<>)).ConvertUsing(typeof(RepeatedFieldToListConverter<,>)); - - config.CreateMap() - .ForMember(dest => dest.Stream, otp => otp - .MapFrom(src => src.Stream.ToByteArray())) - .ReverseMap() - .ForMember(dest => dest.Stream, otp => otp - .MapFrom(src => ByteString.CopyFrom(src.Stream))); - - config.CreateMap().ReverseMap(); - }, null); - //mappingConfig.AssertConfigurationIsValid(); - - return mappingConfig; - } -} diff --git a/app/server/UploadFileService/src/UploadFileService.API/Configs/UploadProfile.cs b/app/server/UploadFileService/src/UploadFileService.API/Configs/UploadProfile.cs new file mode 100644 index 000000000..d88381370 --- /dev/null +++ b/app/server/UploadFileService/src/UploadFileService.API/Configs/UploadProfile.cs @@ -0,0 +1,29 @@ +using AutoMapper; +using Contract.DTOs.UploadFileDTO; +using Google.Protobuf; +using Google.Protobuf.Collections; +using UploadFileProto; +using UploadFileService.API.Configs.MapperConverters; +using UploadFileService.Domain.Responses; + +namespace UploadFileService.API.Configs; + +public class UploadProfile : Profile +{ + public UploadProfile() + { + CreateMap().ReverseMap(); + // Grpc mapping + CreateMap(typeof(List<>), typeof(RepeatedField<>)).ConvertUsing(typeof(ListToRepeatedFieldConverter<,>)); + CreateMap(typeof(RepeatedField<>), typeof(List<>)).ConvertUsing(typeof(RepeatedFieldToListConverter<,>)); + + CreateMap() + .ForMember(dest => dest.Stream, otp => otp + .MapFrom(src => src.Stream.ToByteArray())) + .ReverseMap() + .ForMember(dest => dest.Stream, otp => otp + .MapFrom(src => ByteString.CopyFrom(src.Stream))); + + CreateMap().ReverseMap(); + } +} diff --git a/app/server/UploadFileService/src/UploadFileService.API/DependenciesInjection.cs b/app/server/UploadFileService/src/UploadFileService.API/DependenciesInjection.cs index 52cf89fd3..71c7023da 100644 --- a/app/server/UploadFileService/src/UploadFileService.API/DependenciesInjection.cs +++ b/app/server/UploadFileService/src/UploadFileService.API/DependenciesInjection.cs @@ -25,7 +25,10 @@ public static WebApplicationBuilder AddAPIServices(this WebApplicationBuilder bu // Register automapper services.AddAutoMapper( - cfg => { }, + cfg => + { + cfg.LicenseKey = DotNetEnv.Env.GetString("LUCKYPENNYSOFTWARE_LICENSE_KEY", "Not Found"); + }, AppDomain.CurrentDomain.GetAssemblies()); services.AddCommonAPIServices(); diff --git a/app/server/UserService/src/UserService.API/DependenciesInjection.cs b/app/server/UserService/src/UserService.API/DependenciesInjection.cs index dc8e38b74..170f56649 100644 --- a/app/server/UserService/src/UserService.API/DependenciesInjection.cs +++ b/app/server/UserService/src/UserService.API/DependenciesInjection.cs @@ -20,7 +20,10 @@ public static WebApplicationBuilder AddAPIServices(this WebApplicationBuilder bu builder.ConfigureCommonAPIServices(); services.AddAutoMapper( - cfg => { }, + cfg => + { + cfg.LicenseKey = DotNetEnv.Env.GetString("LUCKYPENNYSOFTWARE_LICENSE_KEY", "Not Found"); + }, AppDomain.CurrentDomain.GetAssemblies()); services.AddInfrastructureServices(); diff --git a/app/server/UserService/src/UserService.Application/DependencyInjection.cs b/app/server/UserService/src/UserService.Application/DependencyInjection.cs index 68f83001e..a13412be9 100644 --- a/app/server/UserService/src/UserService.Application/DependencyInjection.cs +++ b/app/server/UserService/src/UserService.Application/DependencyInjection.cs @@ -15,7 +15,10 @@ public static IServiceCollection AddApplicationServices(this IServiceCollection services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly())); // Register automapper services.AddAutoMapper( - cfg => { }, + cfg => + { + cfg.LicenseKey = DotNetEnv.Env.GetString("LUCKYPENNYSOFTWARE_LICENSE_KEY", "Not Found"); + }, AppDomain.CurrentDomain.GetAssemblies()); services.AddGrpcClientService(); return services;