From 0ad0c6b5c311ca6f2cd0f2e5677b116c4edd3756 Mon Sep 17 00:00:00 2001 From: "mike.p6x@gmail.com" Date: Fri, 6 Sep 2024 10:16:14 +0700 Subject: [PATCH 1/9] Fix nswag-regen.ps1 --- src/api/server/appsettings.Development.json | 2 +- src/api/server/appsettings.json | 2 +- .../blazor/infrastructure/Api/ApiClient.cs | 141 +++++++++--------- src/apps/blazor/infrastructure/Api/nswag.json | 2 +- .../infrastructure/Directory.Packages.props | 1 + .../infrastructure/Infrastructure.csproj | 8 +- 6 files changed, 82 insertions(+), 74 deletions(-) diff --git a/src/api/server/appsettings.Development.json b/src/api/server/appsettings.Development.json index e4ff07d0c..4272824c8 100644 --- a/src/api/server/appsettings.Development.json +++ b/src/api/server/appsettings.Development.json @@ -1,7 +1,7 @@ { "DatabaseOptions": { "Provider": "postgresql", - "ConnectionString": "Server=192.168.1.110;Database=fullstackherodb;User Id=postgres;Password=password" + "ConnectionString": "Server=localhost;Database=fullstackhero;Port=5432;User Id=pgadmin;Password=123DBP@ssw0rd;" }, "OriginOptions": { "OriginUrl": "https://localhost:7000" diff --git a/src/api/server/appsettings.json b/src/api/server/appsettings.json index 76c1d234b..b9834c54e 100644 --- a/src/api/server/appsettings.json +++ b/src/api/server/appsettings.json @@ -1,7 +1,7 @@ { "DatabaseOptions": { "Provider": "postgresql", - "ConnectionString": "Server=localhost;Database=fullstackhero;Port=5433;User Id=pgadmin;Password=pgadmin;" + "ConnectionString": "Server=localhost;Database=fullstackhero;Port=5432;User Id=pgadmin;Password=123DBP@ssw0rd;" }, "OriginOptions": { "OriginUrl": "https://localhost:7000" diff --git a/src/apps/blazor/infrastructure/Api/ApiClient.cs b/src/apps/blazor/infrastructure/Api/ApiClient.cs index 385805c41..2b5b78ccb 100644 --- a/src/apps/blazor/infrastructure/Api/ApiClient.cs +++ b/src/apps/blazor/infrastructure/Api/ApiClient.cs @@ -1,6 +1,6 @@ //---------------------- // -// Generated using the NSwag toolchain v14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0)) (http://NSwag.org) +// Generated using the NSwag toolchain v14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0)) (http://NSwag.org) // //---------------------- @@ -10,6 +10,7 @@ #pragma warning disable 114 // Disable "CS0114 '{derivedDto}.RaisePropertyChanged(String)' hides inherited member 'dtoBase.RaisePropertyChanged(String)'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword." #pragma warning disable 472 // Disable "CS0472 The result of the expression is always 'false' since a value of type 'Int32' is never equal to 'null' of type 'Int32?' #pragma warning disable 612 // Disable "CS0612 '...' is obsolete" +#pragma warning disable 649 // Disable "CS0649 Field is never assigned to, and will always have its default value null" #pragma warning disable 1573 // Disable "CS1573 Parameter '...' has no matching param tag in the XML comment for ... #pragma warning disable 1591 // Disable "CS1591 Missing XML comment for publicly visible type or member ..." #pragma warning disable 8073 // Disable "CS8073 The result of the expression is always 'false' since a value of type 'T' is never equal to 'null' of type 'T?'" @@ -17,13 +18,13 @@ #pragma warning disable 8603 // Disable "CS8603 Possible null reference return" #pragma warning disable 8604 // Disable "CS8604 Possible null reference argument for parameter" #pragma warning disable 8625 // Disable "CS8625 Cannot convert null literal to non-nullable reference type" -#pragma warning disable CS8765 // Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes). +#pragma warning disable 8765 // Disable "CS8765 Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes)." namespace FSH.Starter.Blazor.Infrastructure.Api { using System = global::System; - [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial interface IApiClient { /// @@ -867,17 +868,19 @@ public partial interface IApiClient } - [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class ApiClient : IApiClient { private System.Net.Http.HttpClient _httpClient; private static System.Lazy _settings = new System.Lazy(CreateSerializerSettings, true); + private System.Text.Json.JsonSerializerOptions _instanceSettings; #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. public ApiClient(System.Net.Http.HttpClient httpClient) #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. { _httpClient = httpClient; + Initialize(); } private static System.Text.Json.JsonSerializerOptions CreateSerializerSettings() @@ -887,10 +890,12 @@ private static System.Text.Json.JsonSerializerOptions CreateSerializerSettings() return settings; } - protected System.Text.Json.JsonSerializerOptions JsonSerializerSettings { get { return _settings.Value; } } + protected System.Text.Json.JsonSerializerOptions JsonSerializerSettings { get { return _instanceSettings ?? _settings.Value; } } static partial void UpdateJsonSerializerSettings(System.Text.Json.JsonSerializerOptions settings); + partial void Initialize(); + partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, string url); partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder); partial void ProcessResponse(System.Net.Http.HttpClient client, System.Net.Http.HttpResponseMessage response); @@ -933,7 +938,7 @@ public virtual async System.Threading.Tasks.Task CreatePr { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -1141,7 +1146,7 @@ public virtual async System.Threading.Tasks.Task UpdatePr { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -1341,7 +1346,7 @@ public virtual async System.Threading.Tasks.Task Searc { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -1712,7 +1717,7 @@ public virtual async System.Threading.Tasks.Task CreateOrUpdateRoleEndp { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -1907,7 +1912,7 @@ public virtual async System.Threading.Tasks.Task UpdateRolePermissionsEndpointAs { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -2000,7 +2005,7 @@ public virtual async System.Threading.Tasks.Task CreateTen { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -2281,7 +2286,7 @@ public virtual async System.Threading.Tasks.Task Up { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -2575,7 +2580,7 @@ public virtual async System.Threading.Tasks.Task CreateTodoE { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -2783,7 +2788,7 @@ public virtual async System.Threading.Tasks.Task UpdateTodoE { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -2983,7 +2988,7 @@ public virtual async System.Threading.Tasks.Task GetTodoListEn { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -3086,7 +3091,7 @@ public virtual async System.Threading.Tasks.Task RefreshTokenEndp if (tenant == null) throw new System.ArgumentNullException("tenant"); request_.Headers.TryAddWithoutValidation("tenant", ConvertToString(tenant, System.Globalization.CultureInfo.InvariantCulture)); - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -3187,7 +3192,7 @@ public virtual async System.Threading.Tasks.Task TokenGenerationE if (tenant == null) throw new System.ArgumentNullException("tenant"); request_.Headers.TryAddWithoutValidation("tenant", ConvertToString(tenant, System.Globalization.CultureInfo.InvariantCulture)); - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -3284,7 +3289,7 @@ public virtual async System.Threading.Tasks.Task RegisterU { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -3385,7 +3390,7 @@ public virtual async System.Threading.Tasks.Task SelfRegis if (tenant == null) throw new System.ArgumentNullException("tenant"); request_.Headers.TryAddWithoutValidation("tenant", ConvertToString(tenant, System.Globalization.CultureInfo.InvariantCulture)); - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -3482,7 +3487,7 @@ public virtual async System.Threading.Tasks.Task UpdateUserEndpointAsync(UpdateU { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -3939,7 +3944,7 @@ public virtual async System.Threading.Tasks.Task ForgotPasswordEndpointAsync(str if (tenant == null) throw new System.ArgumentNullException("tenant"); request_.Headers.TryAddWithoutValidation("tenant", ConvertToString(tenant, System.Globalization.CultureInfo.InvariantCulture)); - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -4030,7 +4035,7 @@ public virtual async System.Threading.Tasks.Task ChangePasswordEndpointAsync(Cha { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -4125,7 +4130,7 @@ public virtual async System.Threading.Tasks.Task ResetPasswordEndpointAsync(stri if (tenant == null) throw new System.ArgumentNullException("tenant"); request_.Headers.TryAddWithoutValidation("tenant", ConvertToString(tenant, System.Globalization.CultureInfo.InvariantCulture)); - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -4309,7 +4314,7 @@ public virtual async System.Threading.Tasks.Task ToggleUserStatusEndpointAsync(s { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -4405,7 +4410,7 @@ public virtual async System.Threading.Tasks.Task AssignRolesToUserEndpointAsync( { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -4764,7 +4769,7 @@ private string ConvertToString(object? value, System.Globalization.CultureInfo c } } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class ActivateTenantResponse { @@ -4773,7 +4778,7 @@ public partial class ActivateTenantResponse } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class AssignUserRoleCommand { @@ -4782,7 +4787,7 @@ public partial class AssignUserRoleCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class AuditTrail { @@ -4815,7 +4820,7 @@ public partial class AuditTrail } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class ChangePasswordCommand { @@ -4830,7 +4835,7 @@ public partial class ChangePasswordCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class CreateOrUpdateRoleCommand { @@ -4845,7 +4850,7 @@ public partial class CreateOrUpdateRoleCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class CreateProductCommand { @@ -4860,7 +4865,7 @@ public partial class CreateProductCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class CreateProductResponse { @@ -4869,7 +4874,7 @@ public partial class CreateProductResponse } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class CreateTenantCommand { @@ -4890,7 +4895,7 @@ public partial class CreateTenantCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class CreateTenantResponse { @@ -4899,7 +4904,7 @@ public partial class CreateTenantResponse } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class CreateTodoCommand { @@ -4911,7 +4916,7 @@ public partial class CreateTodoCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class CreateTodoResponse { @@ -4920,7 +4925,7 @@ public partial class CreateTodoResponse } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class DisableTenantResponse { @@ -4929,7 +4934,7 @@ public partial class DisableTenantResponse } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class FileUploadCommand { @@ -4944,7 +4949,7 @@ public partial class FileUploadCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class Filter { @@ -4965,7 +4970,7 @@ public partial class Filter } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class ForgotPasswordCommand { @@ -4974,7 +4979,7 @@ public partial class ForgotPasswordCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class GetTodoResponse { @@ -4989,7 +4994,7 @@ public partial class GetTodoResponse } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class PaginationFilter { @@ -5013,7 +5018,7 @@ public partial class PaginationFilter } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class ProductResponse { @@ -5031,7 +5036,7 @@ public partial class ProductResponse } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class ProductResponsePagedList { @@ -5058,7 +5063,7 @@ public partial class ProductResponsePagedList } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class RefreshTokenCommand { @@ -5070,7 +5075,7 @@ public partial class RefreshTokenCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class RegisterUserCommand { @@ -5097,7 +5102,7 @@ public partial class RegisterUserCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class RegisterUserResponse { @@ -5106,7 +5111,7 @@ public partial class RegisterUserResponse } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class ResetPasswordCommand { @@ -5121,7 +5126,7 @@ public partial class ResetPasswordCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class RoleDto { @@ -5139,7 +5144,7 @@ public partial class RoleDto } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class Search { @@ -5151,7 +5156,7 @@ public partial class Search } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class TenantDetail { @@ -5178,7 +5183,7 @@ public partial class TenantDetail } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class TodoDto { @@ -5193,7 +5198,7 @@ public partial class TodoDto } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class TodoDtoPagedList { @@ -5220,7 +5225,7 @@ public partial class TodoDtoPagedList } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class ToggleUserStatusCommand { @@ -5232,7 +5237,7 @@ public partial class ToggleUserStatusCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class TokenGenerationCommand { @@ -5244,7 +5249,7 @@ public partial class TokenGenerationCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class TokenResponse { @@ -5259,7 +5264,7 @@ public partial class TokenResponse } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class UpdatePermissionsCommand { @@ -5271,7 +5276,7 @@ public partial class UpdatePermissionsCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class UpdateProductCommand { @@ -5289,7 +5294,7 @@ public partial class UpdateProductCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class UpdateProductResponse { @@ -5298,7 +5303,7 @@ public partial class UpdateProductResponse } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class UpdateTodoCommand { @@ -5313,7 +5318,7 @@ public partial class UpdateTodoCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class UpdateTodoResponse { @@ -5322,7 +5327,7 @@ public partial class UpdateTodoResponse } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class UpdateUserCommand { @@ -5349,7 +5354,7 @@ public partial class UpdateUserCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class UpgradeSubscriptionCommand { @@ -5361,7 +5366,7 @@ public partial class UpgradeSubscriptionCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class UpgradeSubscriptionResponse { @@ -5373,7 +5378,7 @@ public partial class UpgradeSubscriptionResponse } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class UserDetail { @@ -5406,7 +5411,7 @@ public partial class UserDetail } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class UserRoleDetail { @@ -5426,7 +5431,7 @@ public partial class UserRoleDetail - [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class ApiException : System.Exception { public int StatusCode { get; private set; } @@ -5449,7 +5454,7 @@ public override string ToString() } } - [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class ApiException : ApiException { public TResult Result { get; private set; } diff --git a/src/apps/blazor/infrastructure/Api/nswag.json b/src/apps/blazor/infrastructure/Api/nswag.json index ac898f089..4d3fb1c43 100644 --- a/src/apps/blazor/infrastructure/Api/nswag.json +++ b/src/apps/blazor/infrastructure/Api/nswag.json @@ -1,5 +1,5 @@ { - "runtime": "WinX64", + "runtime": "Net80", "defaultVariables": null, "documentGenerator": { "fromDocument": { diff --git a/src/apps/blazor/infrastructure/Directory.Packages.props b/src/apps/blazor/infrastructure/Directory.Packages.props index 8f0da76cb..658dc2b3b 100644 --- a/src/apps/blazor/infrastructure/Directory.Packages.props +++ b/src/apps/blazor/infrastructure/Directory.Packages.props @@ -10,6 +10,7 @@ + diff --git a/src/apps/blazor/infrastructure/Infrastructure.csproj b/src/apps/blazor/infrastructure/Infrastructure.csproj index 82ba64361..b99bdfbfa 100644 --- a/src/apps/blazor/infrastructure/Infrastructure.csproj +++ b/src/apps/blazor/infrastructure/Infrastructure.csproj @@ -16,6 +16,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + @@ -23,9 +27,7 @@ - + From 3f406e90ed7b09e2c91675dd1f9b704ae036c223 Mon Sep 17 00:00:00 2001 From: "mike.p6x" Date: Thu, 26 Sep 2024 10:56:13 +0700 Subject: [PATCH 2/9] 20240926_01_change_EntityTable_layout --- src/Directory.Packages.props | 4 +- src/api/framework/Core/DataIO/IExcelReader.cs | 10 + src/api/framework/Core/DataIO/IExcelWriter.cs | 7 + .../framework/Core/Storage/File/FileType.cs | 11 +- .../Infrastructure/DataIO/ExcelReader.cs | 155 +++++++ .../Infrastructure/DataIO/ExcelWriter.cs | 50 +++ .../Infrastructure/DataIO/Extensions.cs | 15 + .../framework/Infrastructure/Extensions.cs | 2 + .../Infrastructure/Infrastructure.csproj | 2 + .../Export/v1/ExportProductsCommand.cs | 8 + .../Export/v1/ExportProductsHandler.cs | 28 ++ .../Import/v1/ImportProductsCommand.cs | 6 + .../Import/v1/ImportProductsHandler.cs | 34 ++ .../Search/v1/SearchProductsCommand.cs | 2 +- .../Search/v1/SearchProductsHandler.cs | 6 +- .../Catalog.Infrastructure/CatalogModule.cs | 2 + .../Endpoints/v1/ExportProductsEndpoint.cs | 35 ++ .../Endpoints/v1/ImportProductsEndpoint.cs | 30 ++ .../Shared/Authorization/FshPermissions.cs | 20 +- .../Features/GetList/v1/GetTodoListHandler.cs | 4 +- .../Features/GetList/v1/GetTodoListRequest.cs | 2 +- src/api/modules/Todo/Todo.csproj | 3 + src/api/server/Server.csproj | 3 - src/api/server/appsettings.Development.json | 68 --- src/api/server/appsettings.json | 8 +- .../Dialogs/DeleteConfirmation.razor | 2 +- .../Dialogs/DialogComfirmation.razor | 46 ++ .../Dialogs/DialogNotification.razor | 28 ++ .../Components/Dialogs/FileUpload.razor | 68 +++ .../Components/EntityTable/AddEditModal.razor | 6 +- .../EntityTable/AddEditModal.razor.cs | 5 +- .../EntityTable/EntityClientTableContext.cs | 25 +- .../EntityTable/EntityServerTableContext.cs | 20 +- .../Components/EntityTable/EntityTable.razor | 424 +++++++++++++----- .../EntityTable/EntityTable.razor.cs | 233 +++++++++- .../EntityTable/EntityTableContext.cs | 24 + .../Components/EntityTable/IImportModal.cs | 7 + .../Components/EntityTable/ImportModal.razor | 47 ++ .../EntityTable/ImportModal.razor.cs | 92 ++++ .../client/Pages/Catalog/Products.razor | 1 + .../client/Pages/Catalog/Products.razor.cs | 23 +- .../blazor/infrastructure/Api/ApiClient.cs | 323 +++++++++++++ src/apps/blazor/shared/AppConstants.cs | 31 +- src/apps/blazor/shared/FshActions.cs | 1 + src/apps/blazor/shared/FshPermissions.cs | 19 +- 45 files changed, 1723 insertions(+), 217 deletions(-) create mode 100644 src/api/framework/Core/DataIO/IExcelReader.cs create mode 100644 src/api/framework/Core/DataIO/IExcelWriter.cs create mode 100644 src/api/framework/Infrastructure/DataIO/ExcelReader.cs create mode 100644 src/api/framework/Infrastructure/DataIO/ExcelWriter.cs create mode 100644 src/api/framework/Infrastructure/DataIO/Extensions.cs create mode 100644 src/api/modules/Catalog/Catalog.Application/Products/Export/v1/ExportProductsCommand.cs create mode 100644 src/api/modules/Catalog/Catalog.Application/Products/Export/v1/ExportProductsHandler.cs create mode 100644 src/api/modules/Catalog/Catalog.Application/Products/Import/v1/ImportProductsCommand.cs create mode 100644 src/api/modules/Catalog/Catalog.Application/Products/Import/v1/ImportProductsHandler.cs create mode 100644 src/api/modules/Catalog/Catalog.Infrastructure/Endpoints/v1/ExportProductsEndpoint.cs create mode 100644 src/api/modules/Catalog/Catalog.Infrastructure/Endpoints/v1/ImportProductsEndpoint.cs delete mode 100644 src/api/server/appsettings.Development.json create mode 100644 src/apps/blazor/client/Components/Dialogs/DialogComfirmation.razor create mode 100644 src/apps/blazor/client/Components/Dialogs/DialogNotification.razor create mode 100644 src/apps/blazor/client/Components/Dialogs/FileUpload.razor create mode 100644 src/apps/blazor/client/Components/EntityTable/IImportModal.cs create mode 100644 src/apps/blazor/client/Components/EntityTable/ImportModal.razor create mode 100644 src/apps/blazor/client/Components/EntityTable/ImportModal.razor.cs diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 095e903f9..1fe995a68 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -13,6 +13,8 @@ + + @@ -36,7 +38,7 @@ - + diff --git a/src/api/framework/Core/DataIO/IExcelReader.cs b/src/api/framework/Core/DataIO/IExcelReader.cs new file mode 100644 index 000000000..5d8ba8d29 --- /dev/null +++ b/src/api/framework/Core/DataIO/IExcelReader.cs @@ -0,0 +1,10 @@ +using FSH.Framework.Core.Storage.File; +using FSH.Framework.Core.Storage.File.Features; + +namespace FSH.Framework.Core.DataIO; + +public interface IExcelReader +{ + + Task> ToListAsync(FileUploadCommand request, FileType supportedFileType, string sheetName = "Sheet1"); +} diff --git a/src/api/framework/Core/DataIO/IExcelWriter.cs b/src/api/framework/Core/DataIO/IExcelWriter.cs new file mode 100644 index 000000000..f8ea51a51 --- /dev/null +++ b/src/api/framework/Core/DataIO/IExcelWriter.cs @@ -0,0 +1,7 @@ +namespace FSH.Framework.Core.DataIO; + +public interface IExcelWriter +{ + Stream WriteToStream(IList data); + Stream WriteToTemplate(T data, string templateFile); +} diff --git a/src/api/framework/Core/Storage/File/FileType.cs b/src/api/framework/Core/Storage/File/FileType.cs index 267968aaa..72a204bff 100644 --- a/src/api/framework/Core/Storage/File/FileType.cs +++ b/src/api/framework/Core/Storage/File/FileType.cs @@ -5,5 +5,14 @@ namespace FSH.Framework.Core.Storage.File; public enum FileType { [Description(".jpg,.png,.jpeg")] - Image + Image, + + [Description(".xls,.xlsx")] + Excel, + + [Description(".zip")] + QuizMedia, + + [Description(".pdf,.doc,.zip,.rar")] + Doc } diff --git a/src/api/framework/Infrastructure/DataIO/ExcelReader.cs b/src/api/framework/Infrastructure/DataIO/ExcelReader.cs new file mode 100644 index 000000000..1ce7b32d3 --- /dev/null +++ b/src/api/framework/Infrastructure/DataIO/ExcelReader.cs @@ -0,0 +1,155 @@ +using System.Text.RegularExpressions; +using ClosedXML.Excel; +using FSH.Framework.Core.DataIO; +using FSH.Framework.Core.Exceptions; +using FSH.Framework.Core.Storage.File; +using FSH.Framework.Core.Storage.File.Features; + +namespace FSH.Framework.Infrastructure.DataIO; + +public class ExcelReader : IExcelReader +{ + public async Task> ToListAsync(FileUploadCommand request, FileType supportedFileType, string sheetName = "Sheet1") + { + string base64Data = Regex.Match(request.Data, string.Format("data:{0}/(?.+?),(?.+)", supportedFileType.ToString().ToLower())).Groups["data"].Value; + var streamData = new MemoryStream(Convert.FromBase64String(base64Data)); + + List list = []; + Type typeOfObject = typeof(T); + + using (IXLWorkbook workbook = new XLWorkbook(streamData)) + { + // Read the first Sheet from Excel file. + var worksheet = workbook.Worksheets.FirstOrDefault(w => w.Name == sheetName) + ?? throw new NotFoundException(string.Format("Sheet with name {0} does not exist!", sheetName)); + + if (worksheet != null) + { + var properties = typeOfObject.GetProperties(); + + // header column texts + var columns = worksheet.FirstRow().Cells().Select((v, i) => new { v.Value, Index = i + 1 }); + + // indexing in closedxml starts with 1 not from 0 + // Skip first row which is used for column header texts + foreach (IXLRow row in worksheet.RowsUsed().Skip(1)) + { + T item = (T)Activator.CreateInstance(typeOfObject); + + foreach (var prop in properties) + { + try + { + var propertyType = prop.PropertyType; + var col = columns.SingleOrDefault(c => c.Value.ToString() == prop.Name); + if (col == null) continue; + + object? obj = GetObjectByDataType(propertyType, row.Cell(col.Index).Value); + + // object? obj = GetObjByDataType(propertyType, row.Cell(col.Index).Value); + if(obj != null) prop.SetValue(item, obj); + } + catch + { + // if any error + // return await Task.FromResult(new List()); + } + } + + if (item != null) list.Add(item); + } + } + } + + return await Task.FromResult(list); + } + + private static object? GetObjectByDataType(Type propertyType, XLCellValue cellValue) + { + if (cellValue.ToString() == "null" || cellValue.IsBlank) + { + return null; + } + + object? val; + if (propertyType.IsEnum) + { + val = Convert.ToInt32(cellValue.GetNumber()); + return Enum.ToObject(propertyType, val); + } + else if (propertyType == typeof(Guid) || propertyType == typeof(Guid?)) + { + val = Guid.Parse(cellValue.ToString()); + } + else if (propertyType == typeof(int) || propertyType == typeof(int?)) + { + val = Convert.ToInt32(cellValue.GetNumber()); + } + else if (propertyType == typeof(decimal)) + { + val = Convert.ToDecimal(cellValue.GetNumber()); + } + else if (propertyType == typeof(long)) + { + val = Convert.ToInt64(cellValue.GetNumber()); + } + else if (propertyType == typeof(bool) || propertyType == typeof(bool?)) + { + val = Convert.ToBoolean(cellValue.GetBoolean()); + } + else if (propertyType == typeof(DateTime) || propertyType == typeof(DateTime?)) + { + val = Convert.ToDateTime(cellValue.GetDateTime()); + } + else + { + val = cellValue.ToString(); + } + + return Convert.ChangeType(val, Nullable.GetUnderlyingType(propertyType) ?? propertyType); + } + + // private static object? GetObjByDataType(Type propertyType, object o) + // { + // object? val; + // if (o.ToString() == "null" || o.ToString()?.Length == 0) + // { + // return null; + // } + // else + // if (propertyType.IsEnum) + // { + // val = Convert.ToInt32(o); + // return Enum.ToObject(propertyType, val); + // } + // else if (propertyType == typeof(Guid) || propertyType == typeof(Guid?)) + // { + // val = Guid.Parse(o.ToString()); + // } + // else if (propertyType == typeof(int) || propertyType == typeof(int?)) + // { + // val = Convert.ToInt32(o); + // } + // else if (propertyType == typeof(decimal)) + // { + // val = Convert.ToDecimal(o); + // } + // else if (propertyType == typeof(long)) + // { + // val = Convert.ToInt64(o); + // } + // else if (propertyType == typeof(bool) || propertyType == typeof(bool?)) + // { + // val = Convert.ToBoolean(o); + // } + // else if (propertyType == typeof(DateTime) || propertyType == typeof(DateTime?)) + // { + // val = Convert.ToDateTime(o); + // } + // else + // { + // val = o.ToString(); + // } + // return Convert.ChangeType(val, Nullable.GetUnderlyingType(propertyType) ?? propertyType); + // } +} diff --git a/src/api/framework/Infrastructure/DataIO/ExcelWriter.cs b/src/api/framework/Infrastructure/DataIO/ExcelWriter.cs new file mode 100644 index 000000000..8e69ed0a3 --- /dev/null +++ b/src/api/framework/Infrastructure/DataIO/ExcelWriter.cs @@ -0,0 +1,50 @@ +using ClosedXML.Excel; +using ClosedXML.Report; +using System.ComponentModel; +using System.Data; +using FSH.Framework.Core.DataIO; + +namespace FSH.Framework.Infrastructure.DataIO; + + +public class ExcelWriter : IExcelWriter +{ + public Stream WriteToStream(IList data) + { + var properties = TypeDescriptor.GetProperties(typeof(T)); + var table = new DataTable("Sheet1", "table"); // "Sheet1" = typeof(T).Name + foreach (PropertyDescriptor prop in properties) + table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType); + foreach (var item in data) + { + var row = table.NewRow(); + foreach (PropertyDescriptor prop in properties) + row[prop.Name] = prop.GetValue(item) ?? DBNull.Value; + table.Rows.Add(row); + } + + using var wb = new XLWorkbook(); + wb.Worksheets.Add(table); + Stream stream = new MemoryStream(); + wb.SaveAs(stream); + stream.Seek(0, SeekOrigin.Begin); + return stream; + } + + public Stream WriteToTemplate(T data, string templateFile) + { + var template = new XLTemplate(templateFile); + template.AddVariable(data); + template.Generate(); + + // save to file on API server + const string outputFile = @".\Output\AssetDeliveryFrom.xlsx"; + template.SaveAs(outputFile); + + // or get bytes to return excel file from web api + Stream stream = new MemoryStream(); + template.Workbook.SaveAs(stream); + stream.Seek(0, SeekOrigin.Begin); + return stream; + } +} diff --git a/src/api/framework/Infrastructure/DataIO/Extensions.cs b/src/api/framework/Infrastructure/DataIO/Extensions.cs new file mode 100644 index 000000000..716c54fee --- /dev/null +++ b/src/api/framework/Infrastructure/DataIO/Extensions.cs @@ -0,0 +1,15 @@ +using FSH.Framework.Core.DataIO; +using Microsoft.Extensions.DependencyInjection; + +namespace FSH.Framework.Infrastructure.DataIO; + +internal static class Extensions +{ + internal static IServiceCollection ConfigureDataImportExport(this IServiceCollection services) + { + services.AddTransient(); + services.AddTransient(); + + return services; + } +} diff --git a/src/api/framework/Infrastructure/Extensions.cs b/src/api/framework/Infrastructure/Extensions.cs index 865bce172..ba4cf259e 100644 --- a/src/api/framework/Infrastructure/Extensions.cs +++ b/src/api/framework/Infrastructure/Extensions.cs @@ -8,6 +8,7 @@ using FSH.Framework.Infrastructure.Behaviours; using FSH.Framework.Infrastructure.Caching; using FSH.Framework.Infrastructure.Cors; +using FSH.Framework.Infrastructure.DataIO; using FSH.Framework.Infrastructure.Exceptions; using FSH.Framework.Infrastructure.Identity; using FSH.Framework.Infrastructure.Jobs; @@ -49,6 +50,7 @@ public static WebApplicationBuilder ConfigureFshFramework(this WebApplicationBui builder.Services.AddExceptionHandler(); builder.Services.AddProblemDetails(); builder.Services.AddHealthChecks(); + builder.Services.ConfigureDataImportExport(); builder.Services.AddOptions().BindConfiguration(nameof(OriginOptions)); // Define module assemblies diff --git a/src/api/framework/Infrastructure/Infrastructure.csproj b/src/api/framework/Infrastructure/Infrastructure.csproj index 020cf21d3..a713d6f59 100644 --- a/src/api/framework/Infrastructure/Infrastructure.csproj +++ b/src/api/framework/Infrastructure/Infrastructure.csproj @@ -18,6 +18,8 @@ + + diff --git a/src/api/modules/Catalog/Catalog.Application/Products/Export/v1/ExportProductsCommand.cs b/src/api/modules/Catalog/Catalog.Application/Products/Export/v1/ExportProductsCommand.cs new file mode 100644 index 000000000..d6490b8be --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Application/Products/Export/v1/ExportProductsCommand.cs @@ -0,0 +1,8 @@ +using System.Net; +using FSH.Framework.Core.Paging; +using FSH.Framework.Core.Storage.File.Features; +using MediatR; + +namespace FSH.Starter.WebApi.Catalog.Application.Products.Export.v1; + +public record ExportProductsCommand(BaseFilter Filter) : IRequest; diff --git a/src/api/modules/Catalog/Catalog.Application/Products/Export/v1/ExportProductsHandler.cs b/src/api/modules/Catalog/Catalog.Application/Products/Export/v1/ExportProductsHandler.cs new file mode 100644 index 000000000..c524d57cf --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Application/Products/Export/v1/ExportProductsHandler.cs @@ -0,0 +1,28 @@ +using FSH.Framework.Core.DataIO; +using FSH.Framework.Core.Persistence; +using FSH.Framework.Core.Specifications; +using FSH.Starter.WebApi.Catalog.Application.Products.Get.v1; +using FSH.Starter.WebApi.Catalog.Domain; +using MediatR; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.IO; + +namespace FSH.Starter.WebApi.Catalog.Application.Products.Export.v1; + +public class ExportProductsHandler( + [FromKeyedServices("catalog:products")] IReadRepository repository, IExcelWriter excelWriter) + : IRequestHandler +{ + public async Task Handle(ExportProductsCommand request, CancellationToken cancellationToken) + { + ArgumentNullException.ThrowIfNull(request); + + var spec = new EntitiesByBaseFilterSpec(request.Filter); + var items = await repository.ListAsync(spec, cancellationToken); + + var response = excelWriter.WriteToStream(items); + + return response; + } +} diff --git a/src/api/modules/Catalog/Catalog.Application/Products/Import/v1/ImportProductsCommand.cs b/src/api/modules/Catalog/Catalog.Application/Products/Import/v1/ImportProductsCommand.cs new file mode 100644 index 000000000..8fcc2df0b --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Application/Products/Import/v1/ImportProductsCommand.cs @@ -0,0 +1,6 @@ +using FSH.Framework.Core.Storage.File.Features; +using MediatR; + +namespace FSH.Starter.WebApi.Catalog.Application.Products.Import.v1; + +public record ImportProductsCommand(FileUploadCommand UploadFile) : IRequest; diff --git a/src/api/modules/Catalog/Catalog.Application/Products/Import/v1/ImportProductsHandler.cs b/src/api/modules/Catalog/Catalog.Application/Products/Import/v1/ImportProductsHandler.cs new file mode 100644 index 000000000..134fb9539 --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Application/Products/Import/v1/ImportProductsHandler.cs @@ -0,0 +1,34 @@ +using FSH.Framework.Core.DataIO; +using FSH.Framework.Core.Exceptions; +using FSH.Framework.Core.Persistence; +using FSH.Framework.Core.Storage.File; +using FSH.Starter.WebApi.Catalog.Domain; +using MediatR; +using Microsoft.Extensions.DependencyInjection; + +namespace FSH.Starter.WebApi.Catalog.Application.Products.Import.v1; + +public class ImportProductsHandler( + [FromKeyedServices("catalog:products")] IRepository repository, IExcelReader excelReader) + : IRequestHandler +{ + public async Task Handle(ImportProductsCommand request, CancellationToken cancellationToken) + { + ArgumentNullException.ThrowIfNull(request); + + var items = await excelReader.ToListAsync(request.UploadFile, FileType.Excel); + + if (items == null || items.Count == 0) throw new CustomException("Excel file error or empty!"); + + try + { + await repository.UpdateRangeAsync(items, cancellationToken); + } + catch (Exception) + { + throw new CustomException("Internal error!"); + } + + return items.Count; + } +} diff --git a/src/api/modules/Catalog/Catalog.Application/Products/Search/v1/SearchProductsCommand.cs b/src/api/modules/Catalog/Catalog.Application/Products/Search/v1/SearchProductsCommand.cs index 79664dcef..de5b07b52 100644 --- a/src/api/modules/Catalog/Catalog.Application/Products/Search/v1/SearchProductsCommand.cs +++ b/src/api/modules/Catalog/Catalog.Application/Products/Search/v1/SearchProductsCommand.cs @@ -4,4 +4,4 @@ namespace FSH.Starter.WebApi.Catalog.Application.Products.Search.v1; -public record SearchProductsCommand(PaginationFilter filter) : IRequest>; +public record SearchProductsCommand(PaginationFilter Filter) : IRequest>; diff --git a/src/api/modules/Catalog/Catalog.Application/Products/Search/v1/SearchProductsHandler.cs b/src/api/modules/Catalog/Catalog.Application/Products/Search/v1/SearchProductsHandler.cs index 51a3b03d7..4530dae05 100644 --- a/src/api/modules/Catalog/Catalog.Application/Products/Search/v1/SearchProductsHandler.cs +++ b/src/api/modules/Catalog/Catalog.Application/Products/Search/v1/SearchProductsHandler.cs @@ -6,7 +6,6 @@ using MediatR; using Microsoft.Extensions.DependencyInjection; - namespace FSH.Starter.WebApi.Catalog.Application.Products.Search.v1; public sealed class SearchProductsHandler( [FromKeyedServices("catalog:products")] IReadRepository repository) @@ -16,12 +15,11 @@ public async Task> Handle(SearchProductsCommand reque { ArgumentNullException.ThrowIfNull(request); - var spec = new EntitiesByPaginationFilterSpec(request.filter); + var spec = new EntitiesByPaginationFilterSpec(request.Filter); var items = await repository.ListAsync(spec, cancellationToken).ConfigureAwait(false); var totalCount = await repository.CountAsync(spec, cancellationToken).ConfigureAwait(false); - return new PagedList(items, request.filter.PageNumber, request.filter.PageSize, totalCount); + return new PagedList(items, request.Filter.PageNumber, request.Filter.PageSize, totalCount); } } - diff --git a/src/api/modules/Catalog/Catalog.Infrastructure/CatalogModule.cs b/src/api/modules/Catalog/Catalog.Infrastructure/CatalogModule.cs index e9f3a4eec..5e2303d29 100644 --- a/src/api/modules/Catalog/Catalog.Infrastructure/CatalogModule.cs +++ b/src/api/modules/Catalog/Catalog.Infrastructure/CatalogModule.cs @@ -23,6 +23,8 @@ public override void AddRoutes(IEndpointRouteBuilder app) productGroup.MapGetProductListEndpoint(); productGroup.MapProductUpdateEndpoint(); productGroup.MapProductDeleteEndpoint(); + productGroup.MapExportProductsEndpoint(); + productGroup.MapImportProductsEndpoint(); } } public static WebApplicationBuilder RegisterCatalogServices(this WebApplicationBuilder builder) diff --git a/src/api/modules/Catalog/Catalog.Infrastructure/Endpoints/v1/ExportProductsEndpoint.cs b/src/api/modules/Catalog/Catalog.Infrastructure/Endpoints/v1/ExportProductsEndpoint.cs new file mode 100644 index 000000000..ae63381d5 --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Infrastructure/Endpoints/v1/ExportProductsEndpoint.cs @@ -0,0 +1,35 @@ +using FSH.Framework.Core.Paging; +using FSH.Framework.Infrastructure.Auth.Policy; +using FSH.Starter.WebApi.Catalog.Application.Products.Export.v1; +using MediatR; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.HttpResults; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Routing; + +namespace FSH.Starter.WebApi.Catalog.Infrastructure.Endpoints.v1; + +public static class ExportProductsEndpoint +{ + internal static RouteHandlerBuilder MapExportProductsEndpoint(this IEndpointRouteBuilder endpoints) + { + return endpoints + .MapPost("/export", async Task (ISender mediator, [FromBody] BaseFilter filter) => + { + var fileStream = await mediator.Send(new ExportProductsCommand(filter)); + var response = TypedResults.File(fileStream, "application/octet-stream", "ProductExports"); + return response; + + //return TypedResults.File(fileStream, "application/octet-stream", "ProductExports"); + //return TypedResults.File(fileStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "ProductExports.xlsx"); + }) + .WithName(nameof(ExportProductsEndpoint)) + .WithSummary("Exports a list of products") + .WithDescription("Exports a list of products with filtering support") + .Produces () + .RequirePermission("Permissions.Products.Export") + .MapToApiVersion(1); + } +} + diff --git a/src/api/modules/Catalog/Catalog.Infrastructure/Endpoints/v1/ImportProductsEndpoint.cs b/src/api/modules/Catalog/Catalog.Infrastructure/Endpoints/v1/ImportProductsEndpoint.cs new file mode 100644 index 000000000..23e835c4f --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Infrastructure/Endpoints/v1/ImportProductsEndpoint.cs @@ -0,0 +1,30 @@ +using FSH.Framework.Core.Storage.File.Features; +using FSH.Framework.Infrastructure.Auth.Policy; +using FSH.Starter.WebApi.Catalog.Application.Products.Import.v1; +using MediatR; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; + +namespace FSH.Starter.WebApi.Catalog.Infrastructure.Endpoints.v1; + +public static class ImportProductsEndpoint +{ + internal static RouteHandlerBuilder MapImportProductsEndpoint(this IEndpointRouteBuilder endpoints) + { + return endpoints + .MapPost("/Import", async (FileUploadCommand uploadFile, ISender mediator) => + { + await mediator.Send(new ImportProductsCommand(uploadFile)); + return Results.NoContent(); + + }) + .WithName(nameof(ImportProductsEndpoint)) + .WithSummary("Imports a list of entities") + .WithDescription("Imports a list of entities from excel files") + .Produces(StatusCodes.Status200OK) + .RequirePermission("Permissions.Products.Import") + .MapToApiVersion(1); + } +} + diff --git a/src/api/modules/Shared/Authorization/FshPermissions.cs b/src/api/modules/Shared/Authorization/FshPermissions.cs index d32a1fef1..fb3671087 100644 --- a/src/api/modules/Shared/Authorization/FshPermissions.cs +++ b/src/api/modules/Shared/Authorization/FshPermissions.cs @@ -10,6 +10,7 @@ public static class FshAction public const string Update = nameof(Update); public const string Delete = nameof(Delete); public const string Export = nameof(Export); + public const string Import = nameof(Import); public const string Generate = nameof(Generate); public const string Clean = nameof(Clean); public const string UpgradeSubscription = nameof(UpgradeSubscription); @@ -32,11 +33,16 @@ public static class FshResource public static class FshPermissions { private static readonly FshPermission[] allPermissions = - { + { //tenants new("View Tenants", FshAction.View, FshResource.Tenants, IsRoot: true), + new("Search Tenants", FshAction.Search, FshResource.Tenants, IsRoot: true), new("Create Tenants", FshAction.Create, FshResource.Tenants, IsRoot: true), new("Update Tenants", FshAction.Update, FshResource.Tenants, IsRoot: true), + new("Delete Tenants", FshAction.Delete, FshResource.Tenants, IsRoot: true), + new("Export Tenants", FshAction.Export, FshResource.Tenants, IsRoot: true), + new("Import Tenants", FshAction.Import, FshResource.Tenants, IsRoot: true), + new("Upgrade Tenant Subscription", FshAction.UpgradeSubscription, FshResource.Tenants, IsRoot: true), //identity @@ -46,12 +52,19 @@ public static class FshPermissions new("Update Users", FshAction.Update, FshResource.Users), new("Delete Users", FshAction.Delete, FshResource.Users), new("Export Users", FshAction.Export, FshResource.Users), + new("Import Users", FshAction.Import, FshResource.Users), + new("View UserRoles", FshAction.View, FshResource.UserRoles), new("Update UserRoles", FshAction.Update, FshResource.UserRoles), + new("View Roles", FshAction.View, FshResource.Roles), + new("Search Roles", FshAction.Search, FshResource.Roles), new("Create Roles", FshAction.Create, FshResource.Roles), new("Update Roles", FshAction.Update, FshResource.Roles), new("Delete Roles", FshAction.Delete, FshResource.Roles), + new("Export Roles", FshAction.Export, FshResource.Roles), + new("Import Roles", FshAction.Import, FshResource.Roles), + new("View RoleClaims", FshAction.View, FshResource.RoleClaims), new("Update RoleClaims", FshAction.Update, FshResource.RoleClaims), @@ -62,6 +75,7 @@ public static class FshPermissions new("Update Products", FshAction.Update, FshResource.Products), new("Delete Products", FshAction.Delete, FshResource.Products), new("Export Products", FshAction.Export, FshResource.Products), + new("Import Products", FshAction.Import, FshResource.Products), //todos new("View Todos", FshAction.View, FshResource.Todos, IsBasic: true), @@ -69,7 +83,9 @@ public static class FshPermissions new("Create Todos", FshAction.Create, FshResource.Todos), new("Update Todos", FshAction.Update, FshResource.Todos), new("Delete Todos", FshAction.Delete, FshResource.Todos), - + new("Export Todos", FshAction.Export, FshResource.Todos), + new("Import Todos", FshAction.Import, FshResource.Todos), + //audit new("View Audit Trails", FshAction.View, FshResource.AuditTrails), }; diff --git a/src/api/modules/Todo/Features/GetList/v1/GetTodoListHandler.cs b/src/api/modules/Todo/Features/GetList/v1/GetTodoListHandler.cs index 960a3a7aa..d9ad5479e 100644 --- a/src/api/modules/Todo/Features/GetList/v1/GetTodoListHandler.cs +++ b/src/api/modules/Todo/Features/GetList/v1/GetTodoListHandler.cs @@ -15,11 +15,11 @@ public async Task> Handle(GetTodoListRequest request, Cancell { ArgumentNullException.ThrowIfNull(request); - var spec = new EntitiesByPaginationFilterSpec(request.filter); + var spec = new EntitiesByPaginationFilterSpec(request.Filter); var items = await repository.ListAsync(spec, cancellationToken).ConfigureAwait(false); var totalCount = await repository.CountAsync(spec, cancellationToken).ConfigureAwait(false); - return new PagedList(items, request.filter.PageNumber, request.filter.PageSize, totalCount); + return new PagedList(items, request.Filter.PageNumber, request.Filter.PageSize, totalCount); } } diff --git a/src/api/modules/Todo/Features/GetList/v1/GetTodoListRequest.cs b/src/api/modules/Todo/Features/GetList/v1/GetTodoListRequest.cs index 84bd7b679..349fb44a8 100644 --- a/src/api/modules/Todo/Features/GetList/v1/GetTodoListRequest.cs +++ b/src/api/modules/Todo/Features/GetList/v1/GetTodoListRequest.cs @@ -2,4 +2,4 @@ using MediatR; namespace FSH.Starter.WebApi.Todo.Features.GetList.v1; -public record GetTodoListRequest(PaginationFilter filter) : IRequest>; +public record GetTodoListRequest(PaginationFilter Filter) : IRequest>; diff --git a/src/api/modules/Todo/Todo.csproj b/src/api/modules/Todo/Todo.csproj index d6a587372..f9bfc820a 100644 --- a/src/api/modules/Todo/Todo.csproj +++ b/src/api/modules/Todo/Todo.csproj @@ -7,4 +7,7 @@ + + + diff --git a/src/api/server/Server.csproj b/src/api/server/Server.csproj index d98578232..4bfe8f355 100644 --- a/src/api/server/Server.csproj +++ b/src/api/server/Server.csproj @@ -23,9 +23,6 @@ - - Always - Always diff --git a/src/api/server/appsettings.Development.json b/src/api/server/appsettings.Development.json deleted file mode 100644 index 4272824c8..000000000 --- a/src/api/server/appsettings.Development.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "DatabaseOptions": { - "Provider": "postgresql", - "ConnectionString": "Server=localhost;Database=fullstackhero;Port=5432;User Id=pgadmin;Password=123DBP@ssw0rd;" - }, - "OriginOptions": { - "OriginUrl": "https://localhost:7000" - }, - "CacheOptions": { - "Redis": "" - }, - "HangfireOptions": { - "Username": "admin", - "Password": "Secure1234!Me", - "Route": "/jobs" - }, - "JwtOptions": { - "Key": "QsJbczCNysv/5SGh+U7sxedX8C07TPQPBdsnSDKZ/aE=", - "TokenExpirationInMinutes": 60, - "RefreshTokenExpirationInDays": 7 - }, - "MailOptions": { - "From": "mukesh@fullstackhero.net", - "Host": "smtp.ethereal.email", - "Port": 587, - "UserName": "sherman.oconnell47@ethereal.email", - "Password": "KbuTCFv4J6Fy7256vh", - "DisplayName": "Mukesh Murugan" - }, - "CorsOptions": { - "AllowedOrigins": [ - "https://localhost:7100", - "http://localhost:7100", - "http://localhost:5010" - ] - }, - "Serilog": { - "Using": [ - "Serilog.Sinks.Console" - ], - "MinimumLevel": { - "Default": "Debug" - }, - "WriteTo": [ - { - "Name": "Console" - } - ] - }, - "RateLimitOptions": { - "EnableRateLimiting": false, - "PermitLimit": 5, - "WindowInSeconds": 10, - "RejectionStatusCode": 429 - }, - "SecurityHeaderOptions": { - "Enable": true, - "Headers": { - "XContentTypeOptions": "nosniff", - "ReferrerPolicy": "no-referrer", - "XXSSProtection": "1; mode=block", - "XFrameOptions": "DENY", - "ContentSecurityPolicy": "block-all-mixed-content; style-src 'self' 'unsafe-inline'; font-src 'self'; form-action 'self'; frame-ancestors 'self'; img-src 'self' data:; script-src 'self' 'unsafe-inline'", - "PermissionsPolicy": "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()", - "StrictTransportSecurity": "max-age=31536000" - } - } -} \ No newline at end of file diff --git a/src/api/server/appsettings.json b/src/api/server/appsettings.json index b9834c54e..0d7463514 100644 --- a/src/api/server/appsettings.json +++ b/src/api/server/appsettings.json @@ -1,7 +1,11 @@ { +// "DatabaseOptions": { +// "Provider": "postgresql", +// "ConnectionString": "Server=localhost;Database=fullstackhero;Port=5432;User Id=pgadmin;Password=123DBP@ssw0rd;" +// }, "DatabaseOptions": { - "Provider": "postgresql", - "ConnectionString": "Server=localhost;Database=fullstackhero;Port=5432;User Id=pgadmin;Password=123DBP@ssw0rd;" + "Provider": "mssql", + "ConnectionString": "Server=localhost,1433;Database=FshDb2;User Id=sa;Password=123DBP@ssw0rd;TrustServerCertificate=True" }, "OriginOptions": { "OriginUrl": "https://localhost:7000" diff --git a/src/apps/blazor/client/Components/Dialogs/DeleteConfirmation.razor b/src/apps/blazor/client/Components/Dialogs/DeleteConfirmation.razor index da39f6413..49c3c8273 100644 --- a/src/apps/blazor/client/Components/Dialogs/DeleteConfirmation.razor +++ b/src/apps/blazor/client/Components/Dialogs/DeleteConfirmation.razor @@ -10,7 +10,7 @@ Cancel - Confirm + Confirm diff --git a/src/apps/blazor/client/Components/Dialogs/DialogComfirmation.razor b/src/apps/blazor/client/Components/Dialogs/DialogComfirmation.razor new file mode 100644 index 000000000..50da1f60b --- /dev/null +++ b/src/apps/blazor/client/Components/Dialogs/DialogComfirmation.razor @@ -0,0 +1,46 @@ + + + + + @TitleText + + + + @ContentText + + + Cance + @ButtonText + + + +@code { + + [CascadingParameter] MudDialogInstance MudDialog { get; set; } = default!; + + /// + /// + /// + [Parameter] public string? ContentText { get; set; } + /// + /// + /// + [Parameter] public string? ButtonText { get; set; } + /// + /// + /// + [Parameter] public Color ButtonColor { get; set; } + + /// + /// + /// + [Parameter] public string? TitleIcon { get; set; } + /// + /// + /// + [Parameter] public string? TitleText { get; set; } + + private void Submit() => MudDialog.Close(DialogResult.Ok(true)); + private void Cancel() => MudDialog.Cancel(); + +} \ No newline at end of file diff --git a/src/apps/blazor/client/Components/Dialogs/DialogNotification.razor b/src/apps/blazor/client/Components/Dialogs/DialogNotification.razor new file mode 100644 index 000000000..73eeea708 --- /dev/null +++ b/src/apps/blazor/client/Components/Dialogs/DialogNotification.razor @@ -0,0 +1,28 @@ + + + + + @TitleText + + + + @ContentText + + + @ButtonText + + + +@code { + +[CascadingParameter] MudDialogInstance MudDialog { get; set; } = default!; + +[Parameter] public string? ContentText { get; set; } +[Parameter] public string? ButtonText { get; set; } +[Parameter] public Color ButtonColor { get; set; } + +[Parameter] public string? TitleIcon { get; set; } +[Parameter] public string? TitleText { get; set; } + +private void Submit() => MudDialog.Close(DialogResult.Ok(true)); +} \ No newline at end of file diff --git a/src/apps/blazor/client/Components/Dialogs/FileUpload.razor b/src/apps/blazor/client/Components/Dialogs/FileUpload.razor new file mode 100644 index 000000000..3096518f6 --- /dev/null +++ b/src/apps/blazor/client/Components/Dialogs/FileUpload.razor @@ -0,0 +1,68 @@ + + + + + File Upload + + + + @ContentText + + + Cancel + Choose File + + @if (file != null) + { + Upload + } + else + { + Upload] + } + + + +@code +{ + [CascadingParameter] MudDialogInstance MudDialog { get; set; } = default!; + [Parameter] public string? ContentText { get; set; } + [Parameter] public string? MimeType { get; set; } + public IBrowserFile? file { get; set; } + + void Cancel() => MudDialog.Cancel(); + private async Task Submit() + { if(file != null) + { + var buffer = new byte[file.Size]; + await file.OpenReadStream(file.Size).ReadAsync(buffer); + MudDialog.Close(DialogResult.Ok (buffer)); + } + } + + private void OnInputFileChange(InputFileChangeEventArgs e) + { + if (e.File.Size >=512000) + { + Toast.Add("File have size too big!", Severity.Error); + file = null; + } + else + { + file = e.File; + } + } +} diff --git a/src/apps/blazor/client/Components/EntityTable/AddEditModal.razor b/src/apps/blazor/client/Components/EntityTable/AddEditModal.razor index 4d18b0f3c..d1ff8cb6b 100644 --- a/src/apps/blazor/client/Components/EntityTable/AddEditModal.razor +++ b/src/apps/blazor/client/Components/EntityTable/AddEditModal.razor @@ -28,18 +28,18 @@ - + Cancel @if (IsCreate) { - + Save } else { - + Update } diff --git a/src/apps/blazor/client/Components/EntityTable/AddEditModal.razor.cs b/src/apps/blazor/client/Components/EntityTable/AddEditModal.razor.cs index 7ac2136db..a69ed8037 100644 --- a/src/apps/blazor/client/Components/EntityTable/AddEditModal.razor.cs +++ b/src/apps/blazor/client/Components/EntityTable/AddEditModal.razor.cs @@ -28,6 +28,7 @@ public partial class AddEditModal : IAddEditModal private MudDialogInstance MudDialog { get; set; } = default!; private FshValidation? _customValidation; + private bool _buttonStatus; public void ForceRender() => StateHasChanged(); @@ -38,10 +39,12 @@ OnInitializedFunc is not null private async Task SaveAsync() { + _buttonStatus = true; if (await ApiHelper.ExecuteCallGuardedAsync( () => SaveFunc(RequestModel), Toast, _customValidation, SuccessMessage)) { MudDialog.Close(); } + _buttonStatus = false; } -} \ No newline at end of file +} diff --git a/src/apps/blazor/client/Components/EntityTable/EntityClientTableContext.cs b/src/apps/blazor/client/Components/EntityTable/EntityClientTableContext.cs index b9d84fa8e..b7c293e33 100644 --- a/src/apps/blazor/client/Components/EntityTable/EntityClientTableContext.cs +++ b/src/apps/blazor/client/Components/EntityTable/EntityClientTableContext.cs @@ -1,4 +1,7 @@ -namespace FSH.Starter.Blazor.Client.Components.EntityTable; +using System.Net; +using FSH.Starter.Blazor.Infrastructure.Api; + +namespace FSH.Starter.Blazor.Client.Components.EntityTable; /// /// Initialization Context for the EntityTable Component. @@ -17,6 +20,16 @@ public class EntityClientTableContext /// (the supplied string is the search string entered). /// public Func SearchFunc { get; } + + /// + /// A function that exports the specified data from the API. + /// + public Func>? ExportFunc { get; } + + /// + /// A function that import the specified data from the API. + /// + public Func? ImportFunc { get; } public EntityClientTableContext( List> fields, @@ -28,6 +41,8 @@ public EntityClientTableContext( Func>? getDetailsFunc = null, Func? updateFunc = null, Func? deleteFunc = null, + Func>? exportFunc = null, + Func? importFunc = null, string? entityName = null, string? entityNamePlural = null, string? entityResource = null, @@ -36,7 +51,9 @@ public EntityClientTableContext( string? updateAction = null, string? deleteAction = null, string? exportAction = null, + string? importAction = null, Func? editFormInitializedFunc = null, + Func? importFormInitializedFunc = null, Func? hasExtraActionsFunc = null, Func? canUpdateEntityFunc = null, Func? canDeleteEntityFunc = null) @@ -56,12 +73,16 @@ public EntityClientTableContext( updateAction, deleteAction, exportAction, + importAction, editFormInitializedFunc, + importFormInitializedFunc, hasExtraActionsFunc, canUpdateEntityFunc, canDeleteEntityFunc) { LoadDataFunc = loadDataFunc; SearchFunc = searchFunc; + ExportFunc = exportFunc; + ImportFunc = importFunc; } -} \ No newline at end of file +} diff --git a/src/apps/blazor/client/Components/EntityTable/EntityServerTableContext.cs b/src/apps/blazor/client/Components/EntityTable/EntityServerTableContext.cs index c2fb79527..fb9af79c5 100644 --- a/src/apps/blazor/client/Components/EntityTable/EntityServerTableContext.cs +++ b/src/apps/blazor/client/Components/EntityTable/EntityServerTableContext.cs @@ -14,6 +14,16 @@ public class EntityServerTableContext /// and returns a PaginatedResult of TEntity. /// public Func>> SearchFunc { get; } + + /// + /// A function that exports the specified data from the API. + /// + public Func>? ExportFunc { get; } + + /// + /// A function that import the specified data from the API. + /// + public Func? ImportFunc { get; } public bool EnableAdvancedSearch { get; } @@ -27,6 +37,8 @@ public EntityServerTableContext( Func>? getDetailsFunc = null, Func? updateFunc = null, Func? deleteFunc = null, + Func>? exportFunc = null, + Func? importFunc = null, string? entityName = null, string? entityNamePlural = null, string? entityResource = null, @@ -35,7 +47,9 @@ public EntityServerTableContext( string? updateAction = null, string? deleteAction = null, string? exportAction = null, + string? importAction = null, Func? editFormInitializedFunc = null, + Func? importFormInitializedFunc = null, Func? hasExtraActionsFunc = null, Func? canUpdateEntityFunc = null, Func? canDeleteEntityFunc = null) @@ -55,12 +69,16 @@ public EntityServerTableContext( updateAction, deleteAction, exportAction, + importAction, editFormInitializedFunc, + importFormInitializedFunc, hasExtraActionsFunc, canUpdateEntityFunc, canDeleteEntityFunc) { SearchFunc = searchFunc; + ExportFunc = exportFunc; + ImportFunc = importFunc; EnableAdvancedSearch = enableAdvancedSearch; } -} \ No newline at end of file +} diff --git a/src/apps/blazor/client/Components/EntityTable/EntityTable.razor b/src/apps/blazor/client/Components/EntityTable/EntityTable.razor index cad1b9b48..eab8388c1 100644 --- a/src/apps/blazor/client/Components/EntityTable/EntityTable.razor +++ b/src/apps/blazor/client/Components/EntityTable/EntityTable.razor @@ -2,7 +2,7 @@ @typeparam TId @typeparam TRequest -@inject IJSRuntime JS +@inject IJSRuntime Js