Skip to content

Commit d6085bc

Browse files
Merge pull request #3 from maurogioberti/poc-advanced-features
[Enhancement & Security Update]: Feature Improvements, Logging and Authorization
2 parents f715841 + 49c828f commit d6085bc

File tree

51 files changed

+742
-147
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+742
-147
lines changed

Poc.TextProcessor.Business.Logic/TextSortLogic.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ public class TextSortLogic(ITextSortRepository textSortRepository, ITextSortMapp
1515
{
1616
private readonly ITextSortRepository _textSortRepository = textSortRepository;
1717
private readonly ITextSortMapper _textSortMapper = textSortMapper;
18-
private readonly Dictionary<SortOption, ITextSortingStrategy> sortingStrategies = new()
18+
private readonly Dictionary<SortOption, Func<ITextSortingStrategy>> sortingStrategies = new()
1919
{
20-
{ SortOption.AlphabeticAsc, new AlphabeticAscendingSort() },
21-
{ SortOption.AlphabeticDesc, new AlphabeticDescendingSort() },
22-
{ SortOption.LengthAsc, new LengthAscendingSort() },
20+
{ SortOption.AlphabeticAsc, () => new AlphabeticAscendingSort() },
21+
{ SortOption.AlphabeticDesc, () => new AlphabeticDescendingSort() },
22+
{ SortOption.LengthAsc, () => new LengthAscendingSort() },
2323
};
2424

2525
public SortCollection List()
@@ -30,8 +30,9 @@ public SortCollection List()
3030

3131
public string Sort(string textContent, SortOption orderOption)
3232
{
33-
if (sortingStrategies.TryGetValue(orderOption, out var textSortingStrategy))
33+
if (sortingStrategies.TryGetValue(orderOption, out var textSortingStrategyFactory))
3434
{
35+
var textSortingStrategy = textSortingStrategyFactory.Invoke();
3536
var words = SplitText(textContent);
3637
return textSortingStrategy.SortedContent(words);
3738
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace Poc.TextProcessor.CrossCutting.Configurations.Database
2+
{
3+
public static class DatabaseFrameworks
4+
{
5+
public const string EntityFramework = "EntityFramework";
6+
public const string NHibernate = "NHibernate";
7+
}
8+
}

Poc.TextProcessor.CrossCutting.Configurations/Database/DatabaseSettings.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
public static class DatabaseSettings
44
{
55
public const string Provider = "DatabaseProvider";
6+
public const string Framework = "DatabaseFramework";
67
public const string SqlServer = "SqlServer";
78
public const string Sqlite = "Sqlite";
89
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace Poc.TextProcessor.CrossCutting.Configurations.Database
2+
{
3+
public static class NHibernateSettings
4+
{
5+
public const string MappingAssembly = "Poc.TextProcessor.ResourceAccess.Entities";
6+
}
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace Poc.TextProcessor.CrossCutting.Configurations
2+
{
3+
public static class Logs
4+
{
5+
public const string Directory = "logs";
6+
}
7+
}

Poc.TextProcessor.CrossCutting.Globalization/Messages.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ public class Messages
77
public const string InputFieldEmpty = "Please enter text in the input field.";
88
public const string SortFieldEmpty = "Please select a sort option from the dropdown.";
99
public const string UnexpectedError = "There was an issue processing your request. Please try again later or contact support if the problem persists.";
10-
public const string InvalidDatabaseProvider = "Invalid database provider";
10+
public const string InvalidDatabaseProvider = "Invalid database Provider.";
11+
public const string InvalidDatabaseFramework = "Invalid database Framework.";
12+
public const string UnexpectedExceptionError = "An exception occurred while processing the request.";
1113
}
1214
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using Poc.TextProcessor.CrossCutting.Configurations;
2+
using Poc.TextProcessor.CrossCutting.Utils.Date;
3+
using Serilog;
4+
using Serilog.Formatting.Compact;
5+
6+
namespace Poc.TextProcessor.CrossCutting.Logging
7+
{
8+
public static class Logging
9+
{
10+
private static readonly DateTime CurrentDateTime = DateTimeManager.ApplicationServerDateTime;
11+
public static string LogFilePath => $"{Utils.IO.Path.CurrentDirectory}/{Logs.Directory}_{CurrentDateTime.ToString(Culture.FileDateFormat)}.json";
12+
13+
public static void Initialize()
14+
{
15+
Log.Logger = new LoggerConfiguration()
16+
.MinimumLevel.Debug()
17+
.WriteTo.Console()
18+
.WriteTo.File(new CompactJsonFormatter(), LogFilePath, rollingInterval: RollingInterval.Day)
19+
.CreateLogger();
20+
}
21+
22+
public static void LogError(Exception exception, string message) => Log.Error(exception, message);
23+
24+
25+
//TODO: Improve Logging // Use a better implementation
26+
// Consider adding methods for other log levels if needed
27+
// public static void LogError(string message) => Log.Error(message);
28+
// public static void LogInformation(string message) => Log.Information(message);
29+
// public static void LogWarning(string message) => Log.Warning(message);
30+
// public static void LogDebug(string message) => Log.Debug(message);
31+
}
32+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net8.0</TargetFramework>
5+
<ImplicitUsings>enable</ImplicitUsings>
6+
<Nullable>enable</Nullable>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="Serilog" Version="3.1.1" />
11+
<PackageReference Include="Serilog.Formatting.Compact" Version="2.0.0" />
12+
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
13+
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
14+
</ItemGroup>
15+
16+
<ItemGroup>
17+
<ProjectReference Include="..\Poc.TextProcessor.CrossCutting.Configurations\Poc.TextProcessor.CrossCutting.Configurations.csproj" />
18+
<ProjectReference Include="..\Poc.TextProcessor.CrossCutting.Utils\Poc.TextProcessor.CrossCutting.Utils.csproj" />
19+
</ItemGroup>
20+
21+
</Project>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System.Globalization;
2+
3+
namespace Poc.TextProcessor.CrossCutting.Utils.Date
4+
{
5+
public static class Culture
6+
{
7+
public const string DateTimeFormat = "dd-MM-yyyy hh:mm:ss";
8+
public const string DateFormat = "dd-MM-yyyy";
9+
public const string FileDateFormat = "yyyyMMdd";
10+
public const string UtcDateTimeFormat = "yyyy-MM-dd hh:mm:ss";
11+
public const string TimeFormat = "hh:mm:ss";
12+
public const string DataBaseDateFormat = "yyyy-MM-dd";
13+
14+
public static CultureInfo Info = CultureInfo.InvariantCulture;
15+
}
16+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
namespace Poc.TextProcessor.CrossCutting.Utils.Date
2+
{
3+
public static class DateTimeManager
4+
{
5+
private static readonly string _timestampMask = "yyyyMMddHHmmssffff";
6+
7+
/// <summary>
8+
/// Get App Server Date Time.
9+
/// </summary>
10+
public static DateTime ApplicationServerDateTime => DateTime.Now;
11+
12+
/// <summary>
13+
/// Get App Server Date Time expressed as the Coordinated Universal Time (UTC).
14+
/// </summary>
15+
public static DateTime ApplicationServerDateTimeUtc => DateTime.UtcNow;
16+
17+
public static string TimeStamp(DateTime date)
18+
{
19+
return date.ToString(_timestampMask);
20+
}
21+
22+
public static string TimeStamp(string date)
23+
{
24+
return Convert.ToDateTime(date).ToString(_timestampMask);
25+
}
26+
}
27+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace Poc.TextProcessor.CrossCutting.Utils.IO
2+
{
3+
public static class Path
4+
{
5+
public static string CurrentDirectory => $"{AppDomain.CurrentDomain.BaseDirectory}{AppDomain.CurrentDomain.RelativeSearchPath}";
6+
}
7+
}

Poc.TextProcessor.CrossCutting.Utils/AutoMap.cs renamed to Poc.TextProcessor.CrossCutting.Utils/Mapper/AutoMap.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using AutoMapper;
22

3-
namespace Poc.TextProcessor.CrossCutting.Utils
3+
namespace Poc.TextProcessor.CrossCutting.Utils.Mapper
44
{
55
/// <summary>
66
/// The AutoMap class provides methods for mapping objects of one type to objects of another type.

Poc.TextProcessor.IntegrityAssurance/Poc.TextProcessor.IntegrityAssurance.Tests/Endpoints/Text/OrderedTextTests.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,15 @@ public class OrderedTextTests : TestsBase
99
private const string AlphabeticAscendingOrder = "AlphabeticAsc";
1010
private const string AlphabeticDescendingOrder = "AlphabeticDesc";
1111
private const string LengthAscendingOrder = "LengthAsc";
12+
private const string NotExpectedOrder = "None";
1213

1314
[TestCase(AlphabeticAscendingOrder)]
1415
[TestCase(AlphabeticDescendingOrder)]
1516
[TestCase(LengthAscendingOrder)]
16-
public async Task OrderedText_When_Called_Should_Return_Ok(string orderOption)
17+
public async Task OrderedText_When_Called_Should_Return_Ok(string sortOption)
1718
{
1819
var text = _fixture.Create<string>();
19-
var request = new RestRequest(Core.Settings.Endpoints.Text.OrderedTextEndpoint(text, orderOption), Method.Get);
20+
var request = new RestRequest(Core.Settings.Endpoints.Text.OrderedTextEndpoint(text, sortOption), Method.Get);
2021
var response = await _client.ExecuteAsync<string>(request);
2122
var orderedText = response.Data;
2223

@@ -42,5 +43,15 @@ public async Task OrderedText_When_Invalid_Input_Should_Return_NotFound()
4243

4344
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NotFound));
4445
}
46+
47+
[Test]
48+
public async Task OrderedText_When_Invalid_SortOption_Should_Return_InternalServerError()
49+
{
50+
var text = _fixture.Create<string>();
51+
var request = new RestRequest(Core.Settings.Endpoints.Text.OrderedTextEndpoint(text, NotExpectedOrder), Method.Get);
52+
var response = await _client.ExecuteAsync<string>(request);
53+
54+
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.InternalServerError));
55+
}
4556
}
4657
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"BaseURL": "https://localhost:44382/"
2+
"BaseURL": "http://localhost:5162/"
33
}

Poc.TextProcessor.Presentation.Desktop/App.xaml.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
using Poc.TextProcessor.Business.Logic;
44
using Poc.TextProcessor.Business.Logic.Abstractions;
55
using Poc.TextProcessor.CrossCutting.Configurations;
6-
using Poc.TextProcessor.ResourceAccess.Database.Providers.EntityFramework.Configuration;
6+
using Poc.TextProcessor.CrossCutting.Logging;
7+
using Poc.TextProcessor.ResourceAccess.Database.Providers.Configuration;
78
using Poc.TextProcessor.ResourceAccess.Mappers;
89
using Poc.TextProcessor.ResourceAccess.Repositories;
910
using Poc.TextProcessor.ResourceAccess.Repositories.Abstractions;
@@ -29,6 +30,7 @@ protected override void OnStartup(StartupEventArgs e)
2930
ConfigureServices(serviceCollection);
3031
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
3132
_serviceProvider = serviceCollection.BuildServiceProvider();
33+
Logging.Initialize();
3234

3335
var mainWindow = _serviceProvider.GetRequiredService<MainWindow>();
3436
mainWindow.Show();

Poc.TextProcessor.Presentation.Desktop/Poc.TextProcessor.Presentation.Desktop.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929

3030
<ItemGroup>
3131
<ProjectReference Include="..\Poc.TextProcessor.Business.Logic\Poc.TextProcessor.Business.Logic.csproj" />
32-
<ProjectReference Include="..\Poc.TextProcessor.ResourceAccess.Database\Poc.TextProcessor.ResourceAccess.Database.csproj" />
3332
<ProjectReference Include="..\Poc.TextProcessor.ResourceAccess.Mappers.Abstractions\Poc.TextProcessor.ResourceAccess.Mappers.Abstractions.csproj" />
3433
<ProjectReference Include="..\Poc.TextProcessor.ResourceAccess.Mappers\Poc.TextProcessor.ResourceAccess.Mappers.csproj" />
3534
<ProjectReference Include="..\Poc.TextProcessor.ResourceAccess.Repositories.Abstractions\Poc.TextProcessor.ResourceAccess.Repositories.Abstractions.csproj" />

Poc.TextProcessor.Presentation.Desktop/appsettings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@
33
"SqlServerConnection": "Server=localhost;Database=PocTextProcessor;Trusted_Connection=True;TrustServerCertificate=True",
44
"SqliteConnection": "Data Source=..\\Poc.TextProcessor.ResourceAccess.Database\\PocTextProcessor.db;Cache=Shared"
55
},
6-
"DatabaseProvider": "SqlServer" // Specify the database provider: "Sqlite" or "SqlServer"
6+
"DatabaseProvider": "SqlServer", // Specify the database provider: "Sqlite" or "SqlServer"
7+
"DatabaseFramework": "NHibernate" // Specify the database framework: "NHibernate" or "EntityFramework"
78
}

Poc.TextProcessor.Presentation.RestApi/Controllers/TextController.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public IActionResult GetStatistics([FromQuery] string textToAnalyze)
4242
[ResponseOnException(HttpStatusCode.InternalServerError, typeof(SortingException))]
4343
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(string))]
4444
[ProducesResponseType(StatusCodes.Status400BadRequest)]
45+
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
4546
public IActionResult GetOrderedText([FromQuery] string textToOrder, string orderOption)
4647
{
4748
if (Enum.TryParse(orderOption, true, out SortOption orderOptionEnum))

Poc.TextProcessor.Presentation.RestApi/Program.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
using Poc.TextProcessor.Business.Logic;
22
using Poc.TextProcessor.Business.Logic.Abstractions;
3+
using Poc.TextProcessor.CrossCutting.Logging;
34
using Poc.TextProcessor.Presentation.RestApi.Infrastructure.FilterAttributes;
4-
using Poc.TextProcessor.ResourceAccess.Database.Providers.EntityFramework.Configuration;
5+
using Poc.TextProcessor.ResourceAccess.Database.Providers.Configuration;
56
using Poc.TextProcessor.ResourceAccess.Mappers;
67
using Poc.TextProcessor.ResourceAccess.Repositories;
78
using Poc.TextProcessor.ResourceAccess.Repositories.Abstractions;
@@ -54,4 +55,6 @@
5455

5556
app.MapControllers();
5657

57-
app.Run();
58+
app.Run();
59+
60+
Logging.Initialize();

Poc.TextProcessor.Presentation.RestApi/appsettings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@
1010
"SqlServerConnection": "Server=localhost;Database=PocTextProcessor;Trusted_Connection=True;TrustServerCertificate=True",
1111
"SqliteConnection": "Data Source=..\\Poc.TextProcessor.ResourceAccess.Database\\PocTextProcessor.db;Cache=Shared"
1212
},
13-
"DatabaseProvider": "SqlServer" // Specify the database provider: "Sqlite" or "SqlServer"
13+
"DatabaseProvider": "SqlServer", // Specify the database provider: "Sqlite" or "SqlServer"
14+
"DatabaseFramework": "NHibernate" // Specify the database framework: "NHibernate" or "EntityFramework"
1415
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace Poc.TextProcessor.ResourceAccess.Database.Abstractions
2+
{
3+
public interface IDatabaseManagerProvider : IDatabaseReaderProvider, IDatabaseWriterProvider
4+
{
5+
int Execute(string sql, object parameters = null);
6+
Task<int> ExecuteAsync(string sql, object parameters = null);
7+
}
8+
}

Poc.TextProcessor.ResourceAccess.Database/Abstractions/IDatabaseProvider.cs renamed to Poc.TextProcessor.ResourceAccess.Database/Abstractions/IDatabaseReaderProvider.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,13 @@
22

33
namespace Poc.TextProcessor.ResourceAccess.Database.Abstractions
44
{
5-
public interface IDatabaseProvider
5+
public interface IDatabaseReaderProvider
66
{
77
IEnumerable<T> Query<T>(string sql, object parameters = null) where T : class;
88
Task<IEnumerable<T>> QueryAsync<T>(string sql, object parameters = null) where T : class;
9-
int Execute(string sql, object parameters = null);
10-
Task<int> ExecuteAsync(string sql, object parameters = null);
119
IEnumerable<T> Get<T>(Expression<Func<T, bool>> predicate) where T : class;
1210
IEnumerable<T> Get<T>() where T : class;
1311
Task<IEnumerable<T>> GetAsync<T>(Expression<Func<T, bool>> predicate) where T : class;
1412
Task<IEnumerable<T>> GetAsync<T>() where T : class;
15-
T Save<T>(T entity) where T : class;
16-
Task<T> SaveAsync<T>(T entity) where T : class;
1713
}
1814
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace Poc.TextProcessor.ResourceAccess.Database.Abstractions
2+
{
3+
public interface IDatabaseWriterProvider
4+
{
5+
T Save<T>(T entity) where T : class;
6+
Task<T> SaveAsync<T>(T entity) where T : class;
7+
}
8+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using Microsoft.Extensions.Configuration;
2+
using Microsoft.Extensions.DependencyInjection;
3+
using Poc.TextProcessor.CrossCutting.Configurations.Database;
4+
using Poc.TextProcessor.CrossCutting.Globalization;
5+
6+
namespace Poc.TextProcessor.ResourceAccess.Database.Providers.Configuration
7+
{
8+
public static class DatabaseServiceConfiguration
9+
{
10+
public static void ConfigureDatabaseServices(this IServiceCollection services, IConfiguration configuration)
11+
{
12+
// Define strategy based on the Framework ORM
13+
var databaseFramework = configuration.GetValue<string>(DatabaseSettings.Framework);
14+
switch (databaseFramework)
15+
{
16+
case DatabaseFrameworks.EntityFramework:
17+
EntityFramework.Configuration.DatabaseServiceConfiguration.ConfigureDatabaseServices(services, configuration);
18+
break;
19+
case DatabaseFrameworks.NHibernate:
20+
NHibernate.Configuration.DatabaseServiceConfiguration.ConfigureDatabaseServices(services, configuration);
21+
break;
22+
default:
23+
throw new ArgumentException(Messages.InvalidDatabaseFramework);
24+
};
25+
}
26+
}
27+
}

Poc.TextProcessor.ResourceAccess.Database/Poc.TextProcessor.ResourceAccess.Database.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@
2929
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
3030
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.1" />
3131
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
32+
<PackageReference Include="NHibernate" Version="5.5.2" />
33+
<PackageReference Include="System.Data.SqlClient" Version="4.8.6" />
34+
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.118" />
3235
</ItemGroup>
3336

3437
<ItemGroup>

Poc.TextProcessor.ResourceAccess.Database/Providers/EntityFramework/Configuration/DatabaseServiceConfiguration.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ public static void ConfigureDatabaseServices(this IServiceCollection services, I
1313
DatabaseServiceConfigurationHelpers.InitializeDatabaseProvider(configuration, options);
1414
});
1515

16-
services.AddScoped<IDatabaseProvider, EntityFrameworkDatabaseProvider>();
16+
services.AddScoped<IDatabaseReaderProvider, EntityFrameworkReaderProvider>();
17+
services.AddScoped<IDatabaseWriterProvider, EntityFrameworkWriterProvider>();
18+
services.AddScoped<IDatabaseManagerProvider, EntityFrameworkManagerProvider>();
1719
}
1820
}
1921
}

0 commit comments

Comments
 (0)