diff --git a/.azure/azure-pipelines.yml b/.azure/azure-pipelines.yml index 2e9e1067..ea985097 100644 --- a/.azure/azure-pipelines.yml +++ b/.azure/azure-pipelines.yml @@ -12,9 +12,9 @@ steps: displayName: 'docker compose -f ./docker-compose/docker-compose.tests.yml up -d' - task: UseDotNet@2 - displayName: 'install .net sdk 7.x' + displayName: 'install .net sdk 8.x' inputs: - version: 7.x + version: 8.x installationPath: $(Agent.ToolsDirectory)/dotnet - script: | diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 2921c280..c02e3edf 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -21,7 +21,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v3 with: - dotnet-version: 7.0.x + dotnet-version: 8.0.x - name: docker compose -f ./docker-compose/docker-compose.tests.yml up -d run: docker compose -f ./docker-compose/docker-compose.tests.yml up -d diff --git a/.github/workflows/build_test_and_publish.yml b/.github/workflows/build_test_and_publish.yml index 32bcb452..d81816e8 100644 --- a/.github/workflows/build_test_and_publish.yml +++ b/.github/workflows/build_test_and_publish.yml @@ -32,7 +32,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v3 with: - dotnet-version: 7.0.x + dotnet-version: 8.0.x - name: Setup NuGet uses: nuget/setup-nuget@v1 diff --git a/plugins/OnlineSales.Plugin.EmailSync/Data/EmailSyncDbContext.cs b/plugins/OnlineSales.Plugin.EmailSync/Data/EmailSyncDbContext.cs index 1aa31e8b..dd9b9ee9 100644 --- a/plugins/OnlineSales.Plugin.EmailSync/Data/EmailSyncDbContext.cs +++ b/plugins/OnlineSales.Plugin.EmailSync/Data/EmailSyncDbContext.cs @@ -7,6 +7,7 @@ using EntityFrameworkCore.EncryptColumn.Util; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; +using Npgsql; using OnlineSales.Data; using OnlineSales.Interfaces; using OnlineSales.Plugin.EmailSync.Entities; @@ -22,11 +23,11 @@ public EmailSyncDbContext() { } - public EmailSyncDbContext(DbContextOptions options, IConfiguration configuration, IHttpContextHelper httpContextHelper) - : base(options, configuration, httpContextHelper) + public EmailSyncDbContext(DbContextOptions options, IConfiguration configuration, IHttpContextHelper httpContextHelper, NpgsqlDataSource dataSource) + : base(options, configuration, httpContextHelper, dataSource) { var key = configuration.GetSection("EmailSync:EncryptionKey").Get(); - if (key == null ) + if (key == null) { throw new ArgumentNullException(key); } @@ -44,6 +45,6 @@ protected override void OnModelCreating(ModelBuilder builder) if (encryptionProvider != null) { builder.UseEncryption(encryptionProvider); - } + } } } \ No newline at end of file diff --git a/plugins/OnlineSales.Plugin.EmailSync/OnlineSales.Plugin.EmailSync.csproj b/plugins/OnlineSales.Plugin.EmailSync/OnlineSales.Plugin.EmailSync.csproj index 6f41b8ff..9d2982b5 100644 --- a/plugins/OnlineSales.Plugin.EmailSync/OnlineSales.Plugin.EmailSync.csproj +++ b/plugins/OnlineSales.Plugin.EmailSync/OnlineSales.Plugin.EmailSync.csproj @@ -1,7 +1,7 @@  - net7.0 + net8.0 true enable enable diff --git a/plugins/OnlineSales.Plugin.ReverseProxy/OnlineSales.Plugin.ReverseProxy.csproj b/plugins/OnlineSales.Plugin.ReverseProxy/OnlineSales.Plugin.ReverseProxy.csproj index 653fd398..8827ea22 100644 --- a/plugins/OnlineSales.Plugin.ReverseProxy/OnlineSales.Plugin.ReverseProxy.csproj +++ b/plugins/OnlineSales.Plugin.ReverseProxy/OnlineSales.Plugin.ReverseProxy.csproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 enable true enable diff --git a/plugins/OnlineSales.Plugin.SendGrid/Data/SendgridDbContext.cs b/plugins/OnlineSales.Plugin.SendGrid/Data/SendgridDbContext.cs index ecb511a4..6dd8dacc 100644 --- a/plugins/OnlineSales.Plugin.SendGrid/Data/SendgridDbContext.cs +++ b/plugins/OnlineSales.Plugin.SendGrid/Data/SendgridDbContext.cs @@ -4,6 +4,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; +using Npgsql; using OnlineSales.Data; using OnlineSales.Interfaces; using OnlineSales.Plugin.SendGrid.Entities; @@ -17,8 +18,8 @@ public SendgridDbContext() { } - public SendgridDbContext(DbContextOptions options, IConfiguration configuration, IHttpContextHelper httpContextHelper) - : base(options, configuration, httpContextHelper) + public SendgridDbContext(DbContextOptions options, IConfiguration configuration, IHttpContextHelper httpContextHelper, NpgsqlDataSource dataSource) + : base(options, configuration, httpContextHelper, dataSource) { } diff --git a/plugins/OnlineSales.Plugin.SendGrid/OnlineSales.Plugin.SendGrid.csproj b/plugins/OnlineSales.Plugin.SendGrid/OnlineSales.Plugin.SendGrid.csproj index 3be59b76..7aac69d3 100644 --- a/plugins/OnlineSales.Plugin.SendGrid/OnlineSales.Plugin.SendGrid.csproj +++ b/plugins/OnlineSales.Plugin.SendGrid/OnlineSales.Plugin.SendGrid.csproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 true enable enable diff --git a/plugins/OnlineSales.Plugin.Sms/Data/SmsDbContext.cs b/plugins/OnlineSales.Plugin.Sms/Data/SmsDbContext.cs index 93a142ec..1c4cb8c8 100644 --- a/plugins/OnlineSales.Plugin.Sms/Data/SmsDbContext.cs +++ b/plugins/OnlineSales.Plugin.Sms/Data/SmsDbContext.cs @@ -4,6 +4,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; +using Npgsql; using OnlineSales.Data; using OnlineSales.Plugin.Sms.Entities; @@ -11,8 +12,8 @@ namespace OnlineSales.Plugin.Sms.Data; public class SmsDbContext : PluginDbContextBase { - public SmsDbContext(DbContextOptions options, IConfiguration configuration, IHttpContextHelper httpContextHelper) - : base(options, configuration, httpContextHelper) + public SmsDbContext(DbContextOptions options, IConfiguration configuration, IHttpContextHelper httpContextHelper, NpgsqlDataSource dataSource) + : base(options, configuration, httpContextHelper, dataSource) { } diff --git a/plugins/OnlineSales.Plugin.Sms/Exceptions/AwsSnsException.cs b/plugins/OnlineSales.Plugin.Sms/Exceptions/AwsSnsException.cs index 8f325c9c..8b14cf15 100644 --- a/plugins/OnlineSales.Plugin.Sms/Exceptions/AwsSnsException.cs +++ b/plugins/OnlineSales.Plugin.Sms/Exceptions/AwsSnsException.cs @@ -27,10 +27,5 @@ public AwsSnsException(string? message, Exception? innerException) : base(message, innerException) { } - - protected AwsSnsException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } } } \ No newline at end of file diff --git a/plugins/OnlineSales.Plugin.Sms/Exceptions/GetshoutoutException.cs b/plugins/OnlineSales.Plugin.Sms/Exceptions/GetshoutoutException.cs index cd722cad..07236ecb 100644 --- a/plugins/OnlineSales.Plugin.Sms/Exceptions/GetshoutoutException.cs +++ b/plugins/OnlineSales.Plugin.Sms/Exceptions/GetshoutoutException.cs @@ -22,9 +22,4 @@ public GetshoutoutException(string? message, Exception? innerException) : base(message, innerException) { } - - protected GetshoutoutException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } } \ No newline at end of file diff --git a/plugins/OnlineSales.Plugin.Sms/Exceptions/NotifyLkException.cs b/plugins/OnlineSales.Plugin.Sms/Exceptions/NotifyLkException.cs index 74511bb7..0ffd49d2 100644 --- a/plugins/OnlineSales.Plugin.Sms/Exceptions/NotifyLkException.cs +++ b/plugins/OnlineSales.Plugin.Sms/Exceptions/NotifyLkException.cs @@ -22,10 +22,5 @@ public NotifyLkException(string? message, Exception? innerException) : base(message, innerException) { } - - protected NotifyLkException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } } } \ No newline at end of file diff --git a/plugins/OnlineSales.Plugin.Sms/Exceptions/SMSPluginException.cs b/plugins/OnlineSales.Plugin.Sms/Exceptions/SMSPluginException.cs index 721d643b..0e5d2aa5 100644 --- a/plugins/OnlineSales.Plugin.Sms/Exceptions/SMSPluginException.cs +++ b/plugins/OnlineSales.Plugin.Sms/Exceptions/SMSPluginException.cs @@ -27,10 +27,5 @@ public SmsPluginException(string? message, Exception? innerException) : base(message, innerException) { } - - protected SmsPluginException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } } } \ No newline at end of file diff --git a/plugins/OnlineSales.Plugin.Sms/Exceptions/SmscException.cs b/plugins/OnlineSales.Plugin.Sms/Exceptions/SmscException.cs index f1038765..76d8865c 100644 --- a/plugins/OnlineSales.Plugin.Sms/Exceptions/SmscException.cs +++ b/plugins/OnlineSales.Plugin.Sms/Exceptions/SmscException.cs @@ -27,10 +27,5 @@ public SmscException(string? message, Exception? innerException) : base(message, innerException) { } - - protected SmscException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } } } \ No newline at end of file diff --git a/plugins/OnlineSales.Plugin.Sms/Exceptions/TwilioException.cs b/plugins/OnlineSales.Plugin.Sms/Exceptions/TwilioException.cs index bfef540b..46073d01 100644 --- a/plugins/OnlineSales.Plugin.Sms/Exceptions/TwilioException.cs +++ b/plugins/OnlineSales.Plugin.Sms/Exceptions/TwilioException.cs @@ -22,10 +22,5 @@ public TwilioException(string? message, Exception? innerException) : base(message, innerException) { } - - protected TwilioException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } } } \ No newline at end of file diff --git a/plugins/OnlineSales.Plugin.Sms/Exceptions/UnknownCountryCodeException.cs b/plugins/OnlineSales.Plugin.Sms/Exceptions/UnknownCountryCodeException.cs index 1fe8ac17..f818cf58 100644 --- a/plugins/OnlineSales.Plugin.Sms/Exceptions/UnknownCountryCodeException.cs +++ b/plugins/OnlineSales.Plugin.Sms/Exceptions/UnknownCountryCodeException.cs @@ -22,10 +22,5 @@ public UnknownCountryCodeException(string? message, Exception? innerException) : base(message, innerException) { } - - protected UnknownCountryCodeException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } } } \ No newline at end of file diff --git a/plugins/OnlineSales.Plugin.Sms/OnlineSales.Plugin.Sms.csproj b/plugins/OnlineSales.Plugin.Sms/OnlineSales.Plugin.Sms.csproj index d2c02d6a..653b15ea 100644 --- a/plugins/OnlineSales.Plugin.Sms/OnlineSales.Plugin.Sms.csproj +++ b/plugins/OnlineSales.Plugin.Sms/OnlineSales.Plugin.Sms.csproj @@ -1,7 +1,7 @@  - net7.0 + net8.0 true enable enable diff --git a/plugins/OnlineSales.Plugin.Sms/Services/SmscService.cs b/plugins/OnlineSales.Plugin.Sms/Services/SmscService.cs index f08e248c..0a4a1b16 100644 --- a/plugins/OnlineSales.Plugin.Sms/Services/SmscService.cs +++ b/plugins/OnlineSales.Plugin.Sms/Services/SmscService.cs @@ -2,12 +2,10 @@ // Licensed under the MIT license. See LICENSE file in the samples root for full license information. // -using System.Reflection; using System.Web; using Newtonsoft.Json; using OnlineSales.Plugin.Sms.Configuration; using OnlineSales.Plugin.Sms.Exceptions; -using Serilog; namespace OnlineSales.Plugin.Sms.Services; diff --git a/plugins/OnlineSales.Plugin.TestPlugin/Data/TestPluginDbContext.cs b/plugins/OnlineSales.Plugin.TestPlugin/Data/TestPluginDbContext.cs index d2383219..44436f5d 100644 --- a/plugins/OnlineSales.Plugin.TestPlugin/Data/TestPluginDbContext.cs +++ b/plugins/OnlineSales.Plugin.TestPlugin/Data/TestPluginDbContext.cs @@ -2,10 +2,12 @@ // Licensed under the MIT license. See LICENSE file in the samples root for full license information. // +using System.Data.Common; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.Extensions.Configuration; +using Npgsql; using OnlineSales.Data; using OnlineSales.Interfaces; using OnlineSales.Plugin.TestPlugin.Entities; @@ -23,8 +25,8 @@ public TestPluginDbContext() migrations = new SortedSet(); } - public TestPluginDbContext(DbContextOptions options, IConfiguration configuration, IHttpContextHelper httpContextHelper) - : base(options, configuration, httpContextHelper) + public TestPluginDbContext(DbContextOptions options, IConfiguration configuration, IHttpContextHelper httpContextHelper, NpgsqlDataSource dataSource) + : base(options, configuration, httpContextHelper, dataSource) { migrations = new SortedSet(Database.GetPendingMigrations()); } @@ -69,6 +71,6 @@ private string FindMigration(string name) throw new TestDbContextException($"Cannot find migration with name containig '{name}'"); } - return migration; + return migration; } } \ No newline at end of file diff --git a/plugins/OnlineSales.Plugin.TestPlugin/OnlineSales.Plugin.TestPlugin.csproj b/plugins/OnlineSales.Plugin.TestPlugin/OnlineSales.Plugin.TestPlugin.csproj index 833d552d..8b9e5ea8 100644 --- a/plugins/OnlineSales.Plugin.TestPlugin/OnlineSales.Plugin.TestPlugin.csproj +++ b/plugins/OnlineSales.Plugin.TestPlugin/OnlineSales.Plugin.TestPlugin.csproj @@ -1,7 +1,7 @@  - net7.0 + net8.0 true enable enable diff --git a/plugins/OnlineSales.Plugin.Vsto/Data/VstoDbContext.cs b/plugins/OnlineSales.Plugin.Vsto/Data/VstoDbContext.cs index 1ebc5f9c..8db54c2f 100644 --- a/plugins/OnlineSales.Plugin.Vsto/Data/VstoDbContext.cs +++ b/plugins/OnlineSales.Plugin.Vsto/Data/VstoDbContext.cs @@ -4,6 +4,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; +using Npgsql; using OnlineSales.Data; using OnlineSales.Plugin.Vsto.Entities; @@ -16,8 +17,8 @@ public VstoDbContext() { } - public VstoDbContext(DbContextOptions options, IConfiguration configuration, IHttpContextHelper httpContextHelper) - : base(options, configuration, httpContextHelper) + public VstoDbContext(DbContextOptions options, IConfiguration configuration, IHttpContextHelper httpContextHelper, NpgsqlDataSource dataSource) + : base(options, configuration, httpContextHelper, dataSource) { } diff --git a/plugins/OnlineSales.Plugin.Vsto/OnlineSales.Plugin.Vsto.csproj b/plugins/OnlineSales.Plugin.Vsto/OnlineSales.Plugin.Vsto.csproj index 37637d89..6152e08d 100644 --- a/plugins/OnlineSales.Plugin.Vsto/OnlineSales.Plugin.Vsto.csproj +++ b/plugins/OnlineSales.Plugin.Vsto/OnlineSales.Plugin.Vsto.csproj @@ -1,7 +1,7 @@  - net7.0 + net8.0 true enable enable diff --git a/src/OnlineSales/Controllers/ActivityLogController.cs b/src/OnlineSales/Controllers/ActivityLogController.cs index f0def350..1363ce5c 100644 --- a/src/OnlineSales/Controllers/ActivityLogController.cs +++ b/src/OnlineSales/Controllers/ActivityLogController.cs @@ -14,12 +14,12 @@ namespace OnlineSales.Controllers; [Authorize(Roles = "Admin")] [Route("api/[controller]")] public class ActivityLogController : ControllerBase -{ +{ private readonly IMapper mapper; private readonly ESOnlyQueryProviderFactory queryProviderFactory; public ActivityLogController(IMapper mapper, ESOnlyQueryProviderFactory queryProviderFactory) - { + { this.mapper = mapper; this.queryProviderFactory = queryProviderFactory; } @@ -33,8 +33,8 @@ public virtual async Task>> Get([FromQu var qp = queryProviderFactory.BuildQueryProvider(); var result = await qp.GetResult(); - Response.Headers.Add(ResponseHeaderNames.TotalCount, result.TotalCount.ToString()); - Response.Headers.Add(ResponseHeaderNames.AccessControlExposeHeader, ResponseHeaderNames.TotalCount); + Response.Headers.Append(ResponseHeaderNames.TotalCount, result.TotalCount.ToString()); + Response.Headers.Append(ResponseHeaderNames.AccessControlExposeHeader, ResponseHeaderNames.TotalCount); return Ok(mapper.Map>(result.Records)); } -} +} \ No newline at end of file diff --git a/src/OnlineSales/Controllers/BaseController.cs b/src/OnlineSales/Controllers/BaseController.cs index 1709c757..2ca34e8c 100644 --- a/src/OnlineSales/Controllers/BaseController.cs +++ b/src/OnlineSales/Controllers/BaseController.cs @@ -1,249 +1,249 @@ -// -// Licensed under the MIT license. See LICENSE file in the samples root for full license information. -// - -using System.Collections; -using System.Reflection; -using AutoMapper; -using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; -using OnlineSales.Data; -using OnlineSales.Entities; -using OnlineSales.Infrastructure; - -namespace OnlineSales.Controllers -{ - public class BaseController : ControllerBase - where T : BaseEntityWithId, new() - where TC : class - where TU : class - where TD : class - { - protected readonly DbSet dbSet; - protected readonly PgDbContext dbContext; - protected readonly IMapper mapper; - protected readonly QueryProviderFactory queryProviderFactory; - - public BaseController(PgDbContext dbContext, IMapper mapper, EsDbContext esDbContext, QueryProviderFactory queryProviderFactory) - { - this.dbContext = dbContext; - this.mapper = mapper; - - dbSet = dbContext.Set(); - this.queryProviderFactory = queryProviderFactory; - } - - // GET api/{entity}s/5 - [HttpGet("{id}")] - // [EnableQuery] - [ProducesResponseType(StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status401Unauthorized)] - [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)] - [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)] - public virtual async Task> GetOne(int id) - { - var result = await FindOrThrowNotFound(id); - - var resultConverted = mapper.Map(result); - - return Ok(resultConverted); - } - - // POST api/{entity}s - [HttpPost] - [ProducesResponseType(StatusCodes.Status201Created)] - [ProducesResponseType(StatusCodes.Status401Unauthorized)] - [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status422UnprocessableEntity)] - [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)] - public virtual async Task> Post([FromBody] TC value) - { - var newValue = mapper.Map(value); - var result = await dbSet.AddAsync(newValue); - await dbContext.SaveChangesAsync(); - - var resultsToClient = mapper.Map(newValue); - - return CreatedAtAction(nameof(GetOne), new { id = result.Entity.Id }, resultsToClient); - } - - // PUT api/{entity}s/5 - [HttpPatch("{id}")] - [ProducesResponseType(StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status401Unauthorized)] - [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status422UnprocessableEntity)] - [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)] - public virtual async Task> Patch(int id, [FromBody] TU value) - { - var existingEntity = await FindOrThrowNotFound(id); - return await Patch(existingEntity, value); - } - - // DELETE api/{entity}s/5 - [HttpDelete("{id}")] - [ProducesResponseType(StatusCodes.Status204NoContent)] - [ProducesResponseType(StatusCodes.Status401Unauthorized)] - [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status422UnprocessableEntity)] - [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)] - public virtual async Task Delete(int id) - { - var existingEntity = await FindOrThrowNotFound(id); - - dbContext.Remove(existingEntity); - - await dbContext.SaveChangesAsync(); - - return NoContent(); - } - - [HttpGet] - [ProducesResponseType(StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status401Unauthorized)] - [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)] - public virtual async Task>> Get([FromQuery] string? query) - { - var qp = queryProviderFactory.BuildQueryProvider(); - - var result = await qp.GetResult(); - Response.Headers.Add(ResponseHeaderNames.TotalCount, result.TotalCount.ToString()); - Response.Headers.Add(ResponseHeaderNames.AccessControlExposeHeader, ResponseHeaderNames.TotalCount); - var res = mapper.Map>(result.Records); - RemoveSecondLevelObjects(res); - return Ok(res); - } - - [HttpGet("export")] - [Produces("text/csv", "text/json")] - [ProducesResponseType(StatusCodes.Status401Unauthorized)] - [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)] - public virtual async Task>> Export([FromQuery] string? query) +// +// Licensed under the MIT license. See LICENSE file in the samples root for full license information. +// + +using System.Collections; +using System.Reflection; +using AutoMapper; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using OnlineSales.Data; +using OnlineSales.Entities; +using OnlineSales.Infrastructure; + +namespace OnlineSales.Controllers +{ + public class BaseController : ControllerBase + where T : BaseEntityWithId, new() + where TC : class + where TU : class + where TD : class + { + protected readonly DbSet dbSet; + protected readonly PgDbContext dbContext; + protected readonly IMapper mapper; + protected readonly QueryProviderFactory queryProviderFactory; + + public BaseController(PgDbContext dbContext, IMapper mapper, EsDbContext esDbContext, QueryProviderFactory queryProviderFactory) + { + this.dbContext = dbContext; + this.mapper = mapper; + + dbSet = dbContext.Set(); + this.queryProviderFactory = queryProviderFactory; + } + + // GET api/{entity}s/5 + [HttpGet("{id}")] + // [EnableQuery] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)] + public virtual async Task> GetOne(int id) + { + var result = await FindOrThrowNotFound(id); + + var resultConverted = mapper.Map(result); + + return Ok(resultConverted); + } + + // POST api/{entity}s + [HttpPost] + [ProducesResponseType(StatusCodes.Status201Created)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status422UnprocessableEntity)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)] + public virtual async Task> Post([FromBody] TC value) + { + var newValue = mapper.Map(value); + var result = await dbSet.AddAsync(newValue); + await dbContext.SaveChangesAsync(); + + var resultsToClient = mapper.Map(newValue); + + return CreatedAtAction(nameof(GetOne), new { id = result.Entity.Id }, resultsToClient); + } + + // PUT api/{entity}s/5 + [HttpPatch("{id}")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status422UnprocessableEntity)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)] + public virtual async Task> Patch(int id, [FromBody] TU value) + { + var existingEntity = await FindOrThrowNotFound(id); + return await Patch(existingEntity, value); + } + + // DELETE api/{entity}s/5 + [HttpDelete("{id}")] + [ProducesResponseType(StatusCodes.Status204NoContent)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status422UnprocessableEntity)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)] + public virtual async Task Delete(int id) + { + var existingEntity = await FindOrThrowNotFound(id); + + dbContext.Remove(existingEntity); + + await dbContext.SaveChangesAsync(); + + return NoContent(); + } + + [HttpGet] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)] + public virtual async Task>> Get([FromQuery] string? query) + { + var qp = queryProviderFactory.BuildQueryProvider(); + + var result = await qp.GetResult(); + Response.Headers.Append(ResponseHeaderNames.TotalCount, result.TotalCount.ToString()); + Response.Headers.Append(ResponseHeaderNames.AccessControlExposeHeader, ResponseHeaderNames.TotalCount); + var res = mapper.Map>(result.Records); + RemoveSecondLevelObjects(res); + return Ok(res); + } + + [HttpGet("export")] + [Produces("text/csv", "text/json")] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)] + public virtual async Task>> Export([FromQuery] string? query) { - var qp = queryProviderFactory.BuildQueryProvider(int.MaxValue); - - var result = await qp.GetResult(); - Response.Headers.Add(ResponseHeaderNames.TotalCount, result.TotalCount.ToString()); - Response.Headers.Add(ResponseHeaderNames.AccessControlExposeHeader, ResponseHeaderNames.TotalCount); - var res = mapper.Map>(result.Records); - RemoveSecondLevelObjects(res); + var qp = queryProviderFactory.BuildQueryProvider(int.MaxValue); + + var result = await qp.GetResult(); + Response.Headers.Append(ResponseHeaderNames.TotalCount, result.TotalCount.ToString()); + Response.Headers.Append(ResponseHeaderNames.AccessControlExposeHeader, ResponseHeaderNames.TotalCount); + var res = mapper.Map>(result.Records); + RemoveSecondLevelObjects(res); return Ok(res); } - protected async Task FindOrThrowNotFound(int id) - { - var existingEntity = await (from p in dbSet - where p.Id == id - select p).FirstOrDefaultAsync(); - - if (existingEntity == null) - { - throw new EntityNotFoundException(typeof(T).Name, id.ToString()); - } - - return existingEntity; - } - - protected async Task> Patch(T existingEntity, TU value) - { - mapper.Map(value, existingEntity); - await dbContext.SaveChangesAsync(); - - var resultsToClient = mapper.Map(existingEntity); - - return Ok(resultsToClient); - } - - private static void RemoveSecondLevelObjects(IList data) - { - var refs = SecondLevelDTOs.Data; - - foreach (var item in data) - { - foreach (var r in refs) - { - var propertyObject = r.Key.GetValue(item); - if (propertyObject != null) - { - if (r.Key.PropertyType.GetInterface("IEnumerable") != null && r.Key.PropertyType.IsGenericType) - { - var e = propertyObject as IEnumerable; - foreach (var obj in e!) - { - foreach (var p in r.Value) - { - p.SetValue(obj, null); - } - } - } - else - { - foreach (var p in r.Value) - { - p.SetValue(propertyObject, null); - } - } - } - } - } - } - - private sealed class SecondLevelDTOs - { - public static readonly Dictionary> Data = InitReferences(); - - private static Dictionary> InitReferences() - { - bool IsNullableProperty(PropertyInfo pi) - { - var context = new NullabilityInfoContext(); - var info = context.Create(pi); - return info.WriteState == NullabilityState.Nullable; - } - - bool IsDto(Type type) - { - return type.IsClass && type.Namespace != null && type.Namespace!.StartsWith("OnlineSales.DTOs"); - } - - bool IsNeedToSave(PropertyInfo pi) - { - return IsNullableProperty(pi) && - (IsDto(pi.PropertyType) || (pi.PropertyType.GetInterface("IEnumerable") != null && pi.PropertyType.IsGenericType && IsDto(pi.PropertyType.GetGenericArguments()[0]))); - } - - Type GetType(PropertyInfo pi) - { - if (pi.PropertyType.GetInterface("IEnumerable") != null && pi.PropertyType.IsGenericType) - { - return pi.PropertyType.GetGenericArguments()[0]; - } - else - { - return pi.PropertyType; - } - } - - var res = new Dictionary>(); - var properties = typeof(TD).GetProperties(); - foreach (var property in properties) - { - var pType = GetType(property); - var nestedProperties = pType.GetProperties(); - foreach (var nestedProperty in nestedProperties.Where(np => IsNeedToSave(np))) - { - List temp; - if (res.TryGetValue(property, out temp!)) - { - temp.Add(nestedProperty); - } - else - { - temp = new List() { nestedProperty }; - res.Add(property, temp); - } - } - } - - return res; + protected async Task FindOrThrowNotFound(int id) + { + var existingEntity = await (from p in dbSet + where p.Id == id + select p).FirstOrDefaultAsync(); + + if (existingEntity == null) + { + throw new EntityNotFoundException(typeof(T).Name, id.ToString()); + } + + return existingEntity; + } + + protected async Task> Patch(T existingEntity, TU value) + { + mapper.Map(value, existingEntity); + await dbContext.SaveChangesAsync(); + + var resultsToClient = mapper.Map(existingEntity); + + return Ok(resultsToClient); + } + + private static void RemoveSecondLevelObjects(IList data) + { + var refs = SecondLevelDTOs.Data; + + foreach (var item in data) + { + foreach (var r in refs) + { + var propertyObject = r.Key.GetValue(item); + if (propertyObject != null) + { + if (r.Key.PropertyType.GetInterface("IEnumerable") != null && r.Key.PropertyType.IsGenericType) + { + var e = propertyObject as IEnumerable; + foreach (var obj in e!) + { + foreach (var p in r.Value) + { + p.SetValue(obj, null); + } + } + } + else + { + foreach (var p in r.Value) + { + p.SetValue(propertyObject, null); + } + } + } + } + } + } + + private sealed class SecondLevelDTOs + { + public static readonly Dictionary> Data = InitReferences(); + + private static Dictionary> InitReferences() + { + bool IsNullableProperty(PropertyInfo pi) + { + var context = new NullabilityInfoContext(); + var info = context.Create(pi); + return info.WriteState == NullabilityState.Nullable; + } + + bool IsDto(Type type) + { + return type.IsClass && type.Namespace != null && type.Namespace!.StartsWith("OnlineSales.DTOs"); + } + + bool IsNeedToSave(PropertyInfo pi) + { + return IsNullableProperty(pi) && + (IsDto(pi.PropertyType) || (pi.PropertyType.GetInterface("IEnumerable") != null && pi.PropertyType.IsGenericType && IsDto(pi.PropertyType.GetGenericArguments()[0]))); + } + + Type GetType(PropertyInfo pi) + { + if (pi.PropertyType.GetInterface("IEnumerable") != null && pi.PropertyType.IsGenericType) + { + return pi.PropertyType.GetGenericArguments()[0]; + } + else + { + return pi.PropertyType; + } + } + + var res = new Dictionary>(); + var properties = typeof(TD).GetProperties(); + foreach (var property in properties) + { + var pType = GetType(property); + var nestedProperties = pType.GetProperties(); + foreach (var nestedProperty in nestedProperties.Where(np => IsNeedToSave(np))) + { + List temp; + if (res.TryGetValue(property, out temp!)) + { + temp.Add(nestedProperty); + } + else + { + temp = new List() { nestedProperty }; + res.Add(property, temp); + } + } + } + + return res; } - } - } + } + } } \ No newline at end of file diff --git a/src/OnlineSales/Controllers/UsersController.cs b/src/OnlineSales/Controllers/UsersController.cs index 3d9e0a9d..121d6d47 100644 --- a/src/OnlineSales/Controllers/UsersController.cs +++ b/src/OnlineSales/Controllers/UsersController.cs @@ -37,8 +37,8 @@ public async Task> GetAll() { var allUsers = await userManager.Users.ToListAsync(); var resultsToClient = mapper.Map(allUsers).ToArray(); - Response.Headers.Add(ResponseHeaderNames.TotalCount, resultsToClient.Count().ToString()); - Response.Headers.Add(ResponseHeaderNames.AccessControlExposeHeader, ResponseHeaderNames.TotalCount); + Response.Headers.Append(ResponseHeaderNames.TotalCount, resultsToClient.Count().ToString()); + Response.Headers.Append(ResponseHeaderNames.AccessControlExposeHeader, ResponseHeaderNames.TotalCount); return Ok(resultsToClient); } diff --git a/src/OnlineSales/Data/EsDbContext.cs b/src/OnlineSales/Data/EsDbContext.cs index faca56ab..559fa05c 100644 --- a/src/OnlineSales/Data/EsDbContext.cs +++ b/src/OnlineSales/Data/EsDbContext.cs @@ -2,11 +2,8 @@ // Licensed under the MIT license. See LICENSE file in the samples root for full license information. // -using System; -using System.Reflection; -using Microsoft.EntityFrameworkCore.Metadata.Internal; -using Nest; -using OnlineSales.Configuration; +using Nest; +using OnlineSales.Configuration; using OnlineSales.DataAnnotations; using OnlineSales.Elastic; using OnlineSales.Entities; @@ -23,18 +20,18 @@ public class EsDbContext : ElasticDbContext public EsDbContext(IConfiguration configuration) { - elasticConfig = configuration.GetSection("Elastic").Get(); - - if (elasticConfig == null) - { - throw new MissingConfigurationException("Elastic configuration is mandatory."); - } - - var connectionSettings = new ConnectionSettings(new Uri(elasticConfig.Url)); - - connectionSettings.DefaultMappingFor(m => m - .IndexName($"{elasticConfig!.IndexPrefix}-logs")); - + elasticConfig = configuration.GetSection("Elastic").Get(); + + if (elasticConfig == null) + { + throw new MissingConfigurationException("Elastic configuration is mandatory."); + } + + var connectionSettings = new ConnectionSettings(new Uri(elasticConfig.Url)); + + connectionSettings.DefaultMappingFor(m => m + .IndexName($"{elasticConfig!.IndexPrefix}-logs")); + var assembly = typeof(EsDbContext).Assembly; entityTypes = @@ -45,7 +42,7 @@ public EsDbContext(IConfiguration configuration) var migrationsIndexName = ElasticHelper.GetIndexName(elasticConfig!.IndexPrefix, typeof(ElasticMigration)); - connectionSettings.DefaultMappingFor(m => m + connectionSettings.DefaultMappingFor(m => m .IndexName(migrationsIndexName)); foreach (var entityType in entityTypes) @@ -54,8 +51,8 @@ public EsDbContext(IConfiguration configuration) connectionSettings.DefaultMappingFor(entityType, m => m .IndexName(indexName)); - } - + } + elasticClient = new ElasticClient(connectionSettings); } @@ -63,5 +60,5 @@ public EsDbContext(IConfiguration configuration) public override string IndexPrefix => elasticConfig!.IndexPrefix; - protected override List EntityTypes => entityTypes; + protected override List EntityTypes => entityTypes; } \ No newline at end of file diff --git a/src/OnlineSales/Data/PgDbContext.cs b/src/OnlineSales/Data/PgDbContext.cs index 9b49c539..a187898a 100644 --- a/src/OnlineSales/Data/PgDbContext.cs +++ b/src/OnlineSales/Data/PgDbContext.cs @@ -8,6 +8,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql; using OnlineSales.Configuration; using OnlineSales.DataAnnotations; using OnlineSales.Entities; @@ -22,6 +23,7 @@ public class PgDbContext : IdentityDbContext public readonly IConfiguration Configuration; private readonly IHttpContextHelper? httpContextHelper; + private readonly NpgsqlDataSource dataSource; /// /// Initializes a new instance of the class. @@ -39,6 +41,17 @@ public PgDbContext() .AddUserSecrets(typeof(Program).Assembly) .Build(); + var postgresConfig = Configuration.GetSection("Postgres").Get(); + + if (postgresConfig == null) + { + throw new MissingConfigurationException("Postgres configuration is mandatory."); + } + + var dataSourceBuilder = new NpgsqlDataSourceBuilder(postgresConfig.ConnectionString); + dataSourceBuilder.EnableDynamicJson(); + dataSource = dataSourceBuilder.Build(); + Console.WriteLine("PgDbContext initialized"); } catch (Exception ex) @@ -48,11 +61,12 @@ public PgDbContext() } } - public PgDbContext(DbContextOptions options, IConfiguration configuration, IHttpContextHelper httpContextHelper) + public PgDbContext(DbContextOptions options, IConfiguration configuration, IHttpContextHelper httpContextHelper, NpgsqlDataSource dataSource) : base(options) { Configuration = configuration; this.httpContextHelper = httpContextHelper; + this.dataSource = dataSource; } public bool IsImportRequest { get; set; } @@ -202,18 +216,11 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { Console.WriteLine("Configuring PgDbContext..."); - var postgresConfig = Configuration.GetSection("Postgres").Get(); - - if (postgresConfig == null) - { - throw new MissingConfigurationException("Postgres configuration is mandatory."); - } - optionsBuilder.UseNpgsql( - postgresConfig.ConnectionString, + dataSource, b => b.MigrationsHistoryTable("_migrations")) - .UseSnakeCaseNamingConvention() - .ReplaceService(); + .UseSnakeCaseNamingConvention() + .ReplaceService(); Console.WriteLine("PgDbContext successfully configured"); } diff --git a/src/OnlineSales/Data/PluginDbContextBase.cs b/src/OnlineSales/Data/PluginDbContextBase.cs index aa36b48a..0a8f572f 100644 --- a/src/OnlineSales/Data/PluginDbContextBase.cs +++ b/src/OnlineSales/Data/PluginDbContextBase.cs @@ -2,8 +2,9 @@ // Licensed under the MIT license. See LICENSE file in the samples root for full license information. // -using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; +using Npgsql; using OnlineSales.Interfaces; namespace OnlineSales.Data; @@ -15,8 +16,8 @@ protected PluginDbContextBase() { } - protected PluginDbContextBase(DbContextOptions options, IConfiguration configuration, IHttpContextHelper httpContextHelper) - : base(options, configuration, httpContextHelper) + protected PluginDbContextBase(DbContextOptions options, IConfiguration configuration, IHttpContextHelper httpContextHelper, NpgsqlDataSource dataSource) + : base(options, configuration, httpContextHelper, dataSource) { } diff --git a/src/OnlineSales/DataAnnotations/CurrencyCodeAttribute.cs b/src/OnlineSales/DataAnnotations/CurrencyCodeAttribute.cs index 4b8a8546..eb9ea3a3 100644 --- a/src/OnlineSales/DataAnnotations/CurrencyCodeAttribute.cs +++ b/src/OnlineSales/DataAnnotations/CurrencyCodeAttribute.cs @@ -5,7 +5,6 @@ using System.ComponentModel.DataAnnotations; using System.Globalization; using System.Text; -using Npgsql.Internal.TypeHandlers.NetworkHandlers; namespace OnlineSales.DataAnnotations; diff --git a/src/OnlineSales/Dockerfile b/src/OnlineSales/Dockerfile index 8d65ade7..5eb23b13 100644 --- a/src/OnlineSales/Dockerfile +++ b/src/OnlineSales/Dockerfile @@ -1,10 +1,10 @@ #See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. -FROM mcr.microsoft.com/dotnet/aspnet:7.0-alpine AS base +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base WORKDIR /app EXPOSE 80 -FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build WORKDIR /src COPY ["src/OnlineSales/OnlineSales.csproj", "src/OnlineSales/"] RUN dotnet restore "src/OnlineSales/OnlineSales.csproj" diff --git a/src/OnlineSales/Entities/DealPipeline.cs b/src/OnlineSales/Entities/DealPipeline.cs index b9e23e7a..b0bba40e 100644 --- a/src/OnlineSales/Entities/DealPipeline.cs +++ b/src/OnlineSales/Entities/DealPipeline.cs @@ -4,7 +4,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using Newtonsoft.Json; +using System.Text.Json.Serialization; using OnlineSales.DataAnnotations; namespace OnlineSales.Entities; diff --git a/src/OnlineSales/Exceptions/EmailException.cs b/src/OnlineSales/Exceptions/EmailException.cs index 06c71ede..eecc6f40 100644 --- a/src/OnlineSales/Exceptions/EmailException.cs +++ b/src/OnlineSales/Exceptions/EmailException.cs @@ -22,9 +22,4 @@ public EmailException(string? message, Exception? innerException) : base(message, innerException) { } - - protected EmailException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } } \ No newline at end of file diff --git a/src/OnlineSales/Exceptions/MissingConfigurationException.cs b/src/OnlineSales/Exceptions/MissingConfigurationException.cs index 7c78bb45..f7e22d77 100644 --- a/src/OnlineSales/Exceptions/MissingConfigurationException.cs +++ b/src/OnlineSales/Exceptions/MissingConfigurationException.cs @@ -1,30 +1,25 @@ -// -// Licensed under the MIT license. See LICENSE file in the samples root for full license information. -// - -using System.Runtime.Serialization; - -namespace OnlineSales.Exceptions; - -[Serializable] -public class MissingConfigurationException : Exception -{ - public MissingConfigurationException() - { - } - - public MissingConfigurationException(string? message) - : base(message) - { - } - - public MissingConfigurationException(string? message, Exception? innerException) - : base(message, innerException) - { - } - - protected MissingConfigurationException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } +// +// Licensed under the MIT license. See LICENSE file in the samples root for full license information. +// + +using System.Runtime.Serialization; + +namespace OnlineSales.Exceptions; + +[Serializable] +public class MissingConfigurationException : Exception +{ + public MissingConfigurationException() + { + } + + public MissingConfigurationException(string? message) + : base(message) + { + } + + public MissingConfigurationException(string? message, Exception? innerException) + : base(message, innerException) + { + } } \ No newline at end of file diff --git a/src/OnlineSales/Exceptions/PluginDbContextException.cs b/src/OnlineSales/Exceptions/PluginDbContextException.cs index 48f84969..12a877cc 100644 --- a/src/OnlineSales/Exceptions/PluginDbContextException.cs +++ b/src/OnlineSales/Exceptions/PluginDbContextException.cs @@ -25,10 +25,5 @@ public PluginDbContextException(string? message, Type? unregisteredDbContext, Ex UnregisteredDbContext = unregisteredDbContext; } - protected PluginDbContextException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - public Type? UnregisteredDbContext { get; private set; } } \ No newline at end of file diff --git a/src/OnlineSales/Exceptions/PluginDbContextNotFoundException.cs b/src/OnlineSales/Exceptions/PluginDbContextNotFoundException.cs index d0d4b22b..02d9886b 100644 --- a/src/OnlineSales/Exceptions/PluginDbContextNotFoundException.cs +++ b/src/OnlineSales/Exceptions/PluginDbContextNotFoundException.cs @@ -25,9 +25,4 @@ public PluginDbContextNotFoundException(Type? unregisteredDbContext, Exception? : base(HardcodedMessage, unregisteredDbContext, innerException) { } - - protected PluginDbContextNotFoundException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } } \ No newline at end of file diff --git a/src/OnlineSales/Exceptions/PluginDbContextTooManyException.cs b/src/OnlineSales/Exceptions/PluginDbContextTooManyException.cs index a74afbb8..91a348fd 100644 --- a/src/OnlineSales/Exceptions/PluginDbContextTooManyException.cs +++ b/src/OnlineSales/Exceptions/PluginDbContextTooManyException.cs @@ -25,9 +25,4 @@ public PluginDbContextTooManyException(Type? unregisteredDbContext, Exception? i : base(HardcodedMessage, unregisteredDbContext, innerException) { } - - protected PluginDbContextTooManyException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } } \ No newline at end of file diff --git a/src/OnlineSales/Exceptions/QueryException.cs b/src/OnlineSales/Exceptions/QueryException.cs index 0e443d26..49b66142 100644 --- a/src/OnlineSales/Exceptions/QueryException.cs +++ b/src/OnlineSales/Exceptions/QueryException.cs @@ -19,11 +19,6 @@ public QueryException(IEnumerable innerExceptions) FailedCommands = innerExceptions.SelectMany(e => e.FailedCommands).ToList(); } - protected QueryException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - public List> FailedCommands { get; init; } = new List>(); } } \ No newline at end of file diff --git a/src/OnlineSales/Exceptions/SyncEmailLogTaskException.cs b/src/OnlineSales/Exceptions/SyncEmailLogTaskException.cs index 44dbf784..ba2bf05b 100644 --- a/src/OnlineSales/Exceptions/SyncEmailLogTaskException.cs +++ b/src/OnlineSales/Exceptions/SyncEmailLogTaskException.cs @@ -22,10 +22,5 @@ public SyncEmailLogTaskException(string? message, Exception? innerException) : base(message, innerException) { } - - protected SyncEmailLogTaskException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } } -} +} \ No newline at end of file diff --git a/src/OnlineSales/Exceptions/TooManyRequestsException.cs b/src/OnlineSales/Exceptions/TooManyRequestsException.cs index bb142a0a..5c124d45 100644 --- a/src/OnlineSales/Exceptions/TooManyRequestsException.cs +++ b/src/OnlineSales/Exceptions/TooManyRequestsException.cs @@ -22,9 +22,4 @@ public TooManyRequestsException(string? message, Exception? innerException) : base(message, innerException) { } - - protected TooManyRequestsException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } -} +} \ No newline at end of file diff --git a/src/OnlineSales/Exceptions/UnauthorizedException.cs b/src/OnlineSales/Exceptions/UnauthorizedException.cs index c61c4d51..d709b836 100644 --- a/src/OnlineSales/Exceptions/UnauthorizedException.cs +++ b/src/OnlineSales/Exceptions/UnauthorizedException.cs @@ -13,9 +13,4 @@ public UnauthorizedException() : base("Failed to login") { } - - protected UnauthorizedException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } } \ No newline at end of file diff --git a/src/OnlineSales/OnlineSales.csproj b/src/OnlineSales/OnlineSales.csproj index 679ed745..fb27333c 100644 --- a/src/OnlineSales/OnlineSales.csproj +++ b/src/OnlineSales/OnlineSales.csproj @@ -1,7 +1,7 @@  - net7.0 + net8.0 enable enable OnlineSales @@ -38,31 +38,31 @@ - - + + - + - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + - + - + diff --git a/src/OnlineSales/Program.cs b/src/OnlineSales/Program.cs index f7dce45a..119fc953 100644 --- a/src/OnlineSales/Program.cs +++ b/src/OnlineSales/Program.cs @@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Mvc.Formatters; using Microsoft.EntityFrameworkCore; using Microsoft.OpenApi.Models; +using Npgsql; using OnlineSales.Configuration; using OnlineSales.Data; using OnlineSales.Entities; @@ -51,6 +52,8 @@ public static async Task Main(string[] args) }); ConfigureLogs(builder); + + ConfigurePgDataSource(builder); PluginManager.Init(builder.Configuration); builder.Configuration.AddUserSecrets(typeof(Program).Assembly); @@ -89,7 +92,7 @@ public static async Task Main(string[] args) builder.Services.AddDbContext(); builder.Services.AddSingleton(); - + ConfigureQuartz(builder); ConfigureImageUpload(builder); ConfigureFileUpload(builder); @@ -204,6 +207,22 @@ public static async Task CreateDefaultIdentity(IServiceScope scope) } } + private static void ConfigurePgDataSource(WebApplicationBuilder builder) + { + var postgresConfig = builder.Configuration.GetSection("Postgres").Get(); + + if (postgresConfig == null) + { + throw new MissingConfigurationException("Postgres configuration is mandatory."); + } + + var dataSourceBuilder = new NpgsqlDataSourceBuilder(postgresConfig.ConnectionString); + dataSourceBuilder.EnableDynamicJson(); + var dataSource = dataSourceBuilder.Build(); + + builder.Services.AddSingleton(dataSource); + } + private static void ConfigureImportSizeLimit(WebApplicationBuilder builder) { var maxImportSizeConfig = builder.Configuration.GetValue("ApiSettings:MaxImportSize"); diff --git a/src/OnlineSales/Properties/launchSettings.json b/src/OnlineSales/Properties/launchSettings.json index 16b1213a..ec664f13 100644 --- a/src/OnlineSales/Properties/launchSettings.json +++ b/src/OnlineSales/Properties/launchSettings.json @@ -12,8 +12,7 @@ "OnlineSales": { "commandName": "Project", "launchBrowser": true, - "launchUrl": "swagger", - "applicationUrl": "http://localhost:45437", + "applicationUrl": "http://localhost:16305", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } diff --git a/tests/OnlineSales.Tests/Environment/TestAuthenticationHandler.cs b/tests/OnlineSales.Tests/Environment/TestAuthenticationHandler.cs new file mode 100644 index 00000000..824ab9fe --- /dev/null +++ b/tests/OnlineSales.Tests/Environment/TestAuthenticationHandler.cs @@ -0,0 +1,42 @@ +// +// Licensed under the MIT license. See LICENSE file in the samples root for full license information. +// + +using System.Security.Claims; +using System.Text.Encodings.Web; +using Microsoft.AspNetCore.Authentication; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace OnlineSales.Tests.Environment; + +public class TestAuthenticationHandler : AuthenticationHandler +{ + public const string SchemeName = "TestScheme"; + + public TestAuthenticationHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder) + : base(options, logger, encoder) + { + } + + protected override Task HandleAuthenticateAsync() + { + AuthenticateResult result; + + if (Context.Request.Headers["Authorization"] == "Bearer Success") + { + var claims = new[] { new Claim(ClaimTypes.Name, "Test user") }; + var identity = new ClaimsIdentity(claims, "Test"); + var principal = new ClaimsPrincipal(identity); + var ticket = new AuthenticationTicket(principal, SchemeName); + + result = AuthenticateResult.Success(ticket); + } + else + { + result = AuthenticateResult.Fail("Invalid Bearer Token"); + } + + return Task.FromResult(result); + } +} \ No newline at end of file diff --git a/tests/OnlineSales.Tests/OnlineSales.Tests.csproj b/tests/OnlineSales.Tests/OnlineSales.Tests.csproj index 5d68a414..dd487238 100644 --- a/tests/OnlineSales.Tests/OnlineSales.Tests.csproj +++ b/tests/OnlineSales.Tests/OnlineSales.Tests.csproj @@ -1,7 +1,7 @@  - net7.0 + net8.0 enable enable @@ -25,7 +25,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - +