Project cleanup
This commit is contained in:
parent
48dd53fce4
commit
a6e611ec0d
@ -12,7 +12,7 @@ namespace Persistence.API.Controllers;
|
||||
[Route("api/[controller]")]
|
||||
public class ChangeLogController : ControllerBase, IChangeLogApi
|
||||
{
|
||||
private IChangeLogRepository repository;
|
||||
private readonly IChangeLogRepository repository;
|
||||
|
||||
public ChangeLogController(IChangeLogRepository repository)
|
||||
{
|
||||
|
@ -1,9 +1,9 @@
|
||||
using System.Net;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Persistence.Models;
|
||||
using Persistence.Models.Requests;
|
||||
using Persistence.Repositories;
|
||||
using System.Net;
|
||||
|
||||
namespace Persistence.API.Controllers;
|
||||
|
||||
@ -15,115 +15,115 @@ namespace Persistence.API.Controllers;
|
||||
[Route("api/[controller]")]
|
||||
public class TechMessagesController : ControllerBase
|
||||
{
|
||||
private readonly ITechMessagesRepository techMessagesRepository;
|
||||
private static readonly Dictionary<int, string> categories = new Dictionary<int, string>()
|
||||
{
|
||||
{ 0, "System" },
|
||||
{ 1, "Авария" },
|
||||
{ 2, "Предупреждение" },
|
||||
{ 3, "Инфо" },
|
||||
{ 4, "Прочее" }
|
||||
};
|
||||
private readonly ITechMessagesRepository techMessagesRepository;
|
||||
private static readonly Dictionary<int, string> categories = new()
|
||||
{
|
||||
{ 0, "System" },
|
||||
{ 1, "Авария" },
|
||||
{ 2, "Предупреждение" },
|
||||
{ 3, "Инфо" },
|
||||
{ 4, "Прочее" }
|
||||
};
|
||||
|
||||
public TechMessagesController(ITechMessagesRepository techMessagesRepository)
|
||||
{
|
||||
this.techMessagesRepository = techMessagesRepository;
|
||||
}
|
||||
public TechMessagesController(ITechMessagesRepository techMessagesRepository)
|
||||
{
|
||||
this.techMessagesRepository = techMessagesRepository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получить список технологических сообщений в виде страницы
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<PaginationContainer<TechMessageDto>>> GetPage([FromQuery] PaginationRequest request, CancellationToken token)
|
||||
{
|
||||
var result = await techMessagesRepository.GetPage(request, token);
|
||||
/// <summary>
|
||||
/// Получить список технологических сообщений в виде страницы
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<PaginationContainer<TechMessageDto>>> GetPage([FromQuery] PaginationRequest request, CancellationToken token)
|
||||
{
|
||||
var result = await techMessagesRepository.GetPage(request, token);
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получить статистику по системам
|
||||
/// </summary>
|
||||
/// <param name="autoDrillingSystem"></param>
|
||||
/// <param name="categoryIds"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("statistics")]
|
||||
public async Task<ActionResult<IEnumerable<MessagesStatisticDto>>> GetStatistics([FromQuery] IEnumerable<string> autoDrillingSystem, [FromQuery] IEnumerable<int> categoryIds, CancellationToken token)
|
||||
{
|
||||
var result = await techMessagesRepository.GetStatistics(autoDrillingSystem, categoryIds, token);
|
||||
/// <summary>
|
||||
/// Получить статистику по системам
|
||||
/// </summary>
|
||||
/// <param name="autoDrillingSystem"></param>
|
||||
/// <param name="categoryIds"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("statistics")]
|
||||
public async Task<ActionResult<IEnumerable<MessagesStatisticDto>>> GetStatistics([FromQuery] IEnumerable<string> autoDrillingSystem, [FromQuery] IEnumerable<int> categoryIds, CancellationToken token)
|
||||
{
|
||||
var result = await techMessagesRepository.GetStatistics(autoDrillingSystem, categoryIds, token);
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получить список всех систем
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("systems")]
|
||||
public async Task<ActionResult<Dictionary<string, int>>> GetSystems(CancellationToken token)
|
||||
{
|
||||
var result = await techMessagesRepository.GetSystems(token);
|
||||
/// <summary>
|
||||
/// Получить список всех систем
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("systems")]
|
||||
public async Task<ActionResult<Dictionary<string, int>>> GetSystems(CancellationToken token)
|
||||
{
|
||||
var result = await techMessagesRepository.GetSystems(token);
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получить диапазон дат, для которых есть данные в репозитории
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("range")]
|
||||
public async Task<ActionResult<DatesRangeDto>> GetDatesRangeAsync(CancellationToken token)
|
||||
{
|
||||
var result = await techMessagesRepository.GetDatesRangeAsync(token);
|
||||
/// <summary>
|
||||
/// Получить диапазон дат, для которых есть данные в репозитории
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("range")]
|
||||
public async Task<ActionResult<DatesRangeDto>> GetDatesRangeAsync(CancellationToken token)
|
||||
{
|
||||
var result = await techMessagesRepository.GetDatesRangeAsync(token);
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получить порцию записей, начиная с заданной даты
|
||||
/// </summary>
|
||||
/// <param name="dateBegin"></param>
|
||||
/// <param name="take"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("part")]
|
||||
public async Task<ActionResult<IEnumerable<SetpointLogDto>>> GetPart(DateTimeOffset dateBegin, int take, CancellationToken token)
|
||||
{
|
||||
var result = await techMessagesRepository.GetPart(dateBegin, take, token);
|
||||
/// <summary>
|
||||
/// Получить порцию записей, начиная с заданной даты
|
||||
/// </summary>
|
||||
/// <param name="dateBegin"></param>
|
||||
/// <param name="take"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("part")]
|
||||
public async Task<ActionResult<IEnumerable<SetpointLogDto>>> GetPart(DateTimeOffset dateBegin, int take, CancellationToken token)
|
||||
{
|
||||
var result = await techMessagesRepository.GetPart(dateBegin, take, token);
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Добавить новые технологические сообщения
|
||||
/// </summary>
|
||||
/// <param name="dtos"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[ProducesResponseType(typeof(int), (int)HttpStatusCode.Created)]
|
||||
public async Task<IActionResult> AddRange([FromBody] IEnumerable<TechMessageDto> dtos, CancellationToken token)
|
||||
{
|
||||
var userId = User.GetUserId<Guid>();
|
||||
/// <summary>
|
||||
/// Добавить новые технологические сообщения
|
||||
/// </summary>
|
||||
/// <param name="dtos"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[ProducesResponseType(typeof(int), (int)HttpStatusCode.Created)]
|
||||
public async Task<IActionResult> AddRange([FromBody] IEnumerable<TechMessageDto> dtos, CancellationToken token)
|
||||
{
|
||||
var userId = User.GetUserId<Guid>();
|
||||
|
||||
var result = await techMessagesRepository.AddRange(dtos, userId, token);
|
||||
|
||||
return CreatedAtAction(nameof(AddRange), result);
|
||||
}
|
||||
return CreatedAtAction(nameof(AddRange), result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получить словарь категорий
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet("categories")]
|
||||
public ActionResult<Dictionary<int, string>> GetImportantCategories()
|
||||
{
|
||||
return Ok(categories);
|
||||
}
|
||||
/// <summary>
|
||||
/// Получить словарь категорий
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet("categories")]
|
||||
public ActionResult<Dictionary<int, string>> GetImportantCategories()
|
||||
{
|
||||
return Ok(categories);
|
||||
}
|
||||
}
|
@ -28,12 +28,11 @@ public static class DependencyInjection
|
||||
c.MapType<DateOnly>(() => new OpenApiSchema { Type = "string", Format = "date" });
|
||||
c.MapType<JsonValue>(() => new OpenApiSchema
|
||||
{
|
||||
AnyOf = new OpenApiSchema[]
|
||||
{
|
||||
AnyOf = [
|
||||
new OpenApiSchema {Type = "string", Format = "string" },
|
||||
new OpenApiSchema {Type = "number", Format = "int32" },
|
||||
new OpenApiSchema {Type = "number", Format = "float" },
|
||||
}
|
||||
new OpenApiSchema {Type = "number", Format = "float" }
|
||||
]
|
||||
});
|
||||
|
||||
c.CustomOperationIds(e =>
|
||||
@ -45,8 +44,8 @@ public static class DependencyInjection
|
||||
|
||||
var needUseKeyCloak = configuration.GetSection("NeedUseKeyCloak").Get<bool>();
|
||||
if (needUseKeyCloak)
|
||||
c.AddKeycloackSecurity(configuration);
|
||||
else c.AddDefaultSecurity(configuration);
|
||||
c.AddKeycloakSecurity(configuration);
|
||||
else c.AddDefaultSecurity();
|
||||
|
||||
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
|
||||
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
|
||||
@ -134,12 +133,12 @@ public static class DependencyInjection
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Security (Swagger)
|
||||
private static void AddKeycloackSecurity(this SwaggerGenOptions options, IConfiguration configuration)
|
||||
#region Keycloak
|
||||
private static void AddKeycloakSecurity(this SwaggerGenOptions options, IConfiguration configuration)
|
||||
{
|
||||
options.AddSecurityDefinition("Keycloack", new OpenApiSecurityScheme
|
||||
options.AddSecurityDefinition("Keycloak", new OpenApiSecurityScheme
|
||||
{
|
||||
Description = @"JWT Authorization header using the Bearer scheme. Enter 'Bearer' [space] and then your token in the text input below. Example: 'Bearer 12345abcdef'",
|
||||
Description = @"JWT Authorization header using the Bearer scheme. Enter 'Bearer' [space] and then your token in the text input below. Example: 'Bearer 12345token'",
|
||||
Name = "Authorization",
|
||||
In = ParameterLocation.Header,
|
||||
Type = SecuritySchemeType.OAuth2,
|
||||
@ -147,7 +146,7 @@ public static class DependencyInjection
|
||||
{
|
||||
Implicit = new OpenApiOAuthFlow
|
||||
{
|
||||
AuthorizationUrl = new Uri(configuration["Authentication:AuthorizationUrl"]),
|
||||
AuthorizationUrl = new Uri(configuration["Authentication:AuthorizationUrl"]!),
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -160,7 +159,7 @@ public static class DependencyInjection
|
||||
Reference = new OpenApiReference
|
||||
{
|
||||
Type = ReferenceType.SecurityScheme,
|
||||
Id = "Keycloack"
|
||||
Id = "Keycloak"
|
||||
},
|
||||
Scheme = "Bearer",
|
||||
Name = "Bearer",
|
||||
@ -171,11 +170,11 @@ public static class DependencyInjection
|
||||
});
|
||||
}
|
||||
|
||||
private static void AddDefaultSecurity(this SwaggerGenOptions options, IConfiguration configuration)
|
||||
private static void AddDefaultSecurity(this SwaggerGenOptions options)
|
||||
{
|
||||
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
|
||||
{
|
||||
Description = @"JWT Authorization header using the Bearer scheme. Enter 'Bearer' [space] and then your token in the text input below. Example: 'Bearer 12345abcdef'",
|
||||
Description = @"JWT Authorization header using the Bearer scheme. Enter 'Bearer' [space] and then your token in the text input below. Example: 'Bearer 12345token'",
|
||||
Name = "Authorization",
|
||||
In = ParameterLocation.Header,
|
||||
Type = SecuritySchemeType.ApiKey,
|
||||
|
@ -7,8 +7,7 @@ public static class Extensions
|
||||
{
|
||||
public static T GetUserId<T>(this ClaimsPrincipal principal)
|
||||
{
|
||||
if (principal == null)
|
||||
throw new ArgumentNullException(nameof(principal));
|
||||
ArgumentNullException.ThrowIfNull(principal, nameof(principal));
|
||||
|
||||
var loggedInUserId = principal.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
|
||||
|
@ -4,29 +4,29 @@ using Refit;
|
||||
|
||||
namespace Persistence.Client.Clients
|
||||
{
|
||||
/// <summary>
|
||||
/// Интерфейс клиента для хранения технологических сообщений
|
||||
/// </summary>
|
||||
public interface ITechMessagesClient
|
||||
{
|
||||
private const string BaseRoute = "/api/techMessages";
|
||||
/// <summary>
|
||||
/// Интерфейс клиента для хранения технологических сообщений
|
||||
/// </summary>
|
||||
public interface ITechMessagesClient
|
||||
{
|
||||
private const string BaseRoute = "/api/techMessages";
|
||||
|
||||
[Get($"{BaseRoute}")]
|
||||
Task<IApiResponse<PaginationContainer<TechMessageDto>>> GetPage([Query] PaginationRequest request, CancellationToken token);
|
||||
[Get($"{BaseRoute}")]
|
||||
Task<IApiResponse<PaginationContainer<TechMessageDto>>> GetPage([Query] PaginationRequest request, CancellationToken token);
|
||||
|
||||
[Post($"{BaseRoute}")]
|
||||
Task<IApiResponse<int>> AddRange([Body] IEnumerable<TechMessageDto> dtos, CancellationToken token);
|
||||
[Post($"{BaseRoute}")]
|
||||
Task<IApiResponse<int>> AddRange([Body] IEnumerable<TechMessageDto> dtos, CancellationToken token);
|
||||
|
||||
[Get($"{BaseRoute}/systems")]
|
||||
Task<IApiResponse<IEnumerable<string>>> GetSystems(CancellationToken token);
|
||||
[Get($"{BaseRoute}/systems")]
|
||||
Task<IApiResponse<IEnumerable<string>>> GetSystems(CancellationToken token);
|
||||
|
||||
[Get($"{BaseRoute}/range")]
|
||||
Task<IApiResponse<DatesRangeDto>> GetDatesRangeAsync(CancellationToken token);
|
||||
[Get($"{BaseRoute}/range")]
|
||||
Task<IApiResponse<DatesRangeDto>> GetDatesRangeAsync(CancellationToken token);
|
||||
|
||||
[Get($"{BaseRoute}/part")]
|
||||
Task<IApiResponse<IEnumerable<TechMessageDto>>> GetPart(DateTimeOffset dateBegin, int take, CancellationToken token);
|
||||
[Get($"{BaseRoute}/part")]
|
||||
Task<IApiResponse<IEnumerable<TechMessageDto>>> GetPart(DateTimeOffset dateBegin, int take, CancellationToken token);
|
||||
|
||||
[Get($"{BaseRoute}/statistics")]
|
||||
Task<IApiResponse<IEnumerable<MessagesStatisticDto>>> GetStatistics([Query] string autoDrillingSystem, [Query] int categoryId, CancellationToken token);
|
||||
}
|
||||
[Get($"{BaseRoute}/statistics")]
|
||||
Task<IApiResponse<IEnumerable<MessagesStatisticDto>>> GetStatistics([Query] string autoDrillingSystem, [Query] int categoryId, CancellationToken token);
|
||||
}
|
||||
}
|
||||
|
@ -1,75 +1,74 @@
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Security.Claims;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Persistence.Models.Configurations;
|
||||
using RestSharp;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Security.Claims;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Persistence.Client.Helpers;
|
||||
public static class ApiTokenHelper
|
||||
{
|
||||
public static void Authorize(this HttpClient httpClient, IConfiguration configuration)
|
||||
{
|
||||
var authUser = configuration
|
||||
.GetSection(nameof(AuthUser))
|
||||
.Get<AuthUser>()!;
|
||||
var needUseKeyCloak = configuration
|
||||
.GetSection("NeedUseKeyCloak")
|
||||
.Get<bool>()!;
|
||||
var keycloakGetTokenUrl = configuration.GetSection("KeycloakGetTokenUrl").Get<string>() ?? string.Empty;
|
||||
public static void Authorize(this HttpClient httpClient, IConfiguration configuration)
|
||||
{
|
||||
var authUser = configuration
|
||||
.GetSection(nameof(AuthUser))
|
||||
.Get<AuthUser>()!;
|
||||
var needUseKeyCloak = configuration
|
||||
.GetSection("NeedUseKeyCloak")
|
||||
.Get<bool>()!;
|
||||
var keycloakGetTokenUrl = configuration.GetSection("KeycloakGetTokenUrl").Get<string>() ?? string.Empty;
|
||||
|
||||
var jwtToken = needUseKeyCloak
|
||||
? authUser.CreateKeyCloakJwtToken(keycloakGetTokenUrl)
|
||||
: authUser.CreateDefaultJwtToken();
|
||||
var jwtToken = needUseKeyCloak
|
||||
? authUser.CreateKeyCloakJwtToken(keycloakGetTokenUrl)
|
||||
: authUser.CreateDefaultJwtToken();
|
||||
|
||||
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", jwtToken);
|
||||
}
|
||||
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", jwtToken);
|
||||
}
|
||||
|
||||
private static string CreateDefaultJwtToken(this AuthUser authUser)
|
||||
{
|
||||
var nameIdetifier = Guid.NewGuid().ToString();
|
||||
var claims = new List<Claim>()
|
||||
{
|
||||
new(ClaimTypes.NameIdentifier, nameIdetifier),
|
||||
new("client_id", authUser.ClientId),
|
||||
new("username", authUser.Username),
|
||||
new("password", authUser.Password),
|
||||
new("grant_type", authUser.GrantType),
|
||||
new(ClaimTypes.NameIdentifier.ToString(), Guid.NewGuid().ToString())
|
||||
};
|
||||
private static string CreateDefaultJwtToken(this AuthUser authUser)
|
||||
{
|
||||
var nameIdetifier = Guid.NewGuid().ToString();
|
||||
var claims = new List<Claim>()
|
||||
{
|
||||
new(ClaimTypes.NameIdentifier, nameIdetifier),
|
||||
new("client_id", authUser.ClientId),
|
||||
new("username", authUser.Username),
|
||||
new("password", authUser.Password),
|
||||
new("grant_type", authUser.GrantType)
|
||||
};
|
||||
|
||||
var tokenDescriptor = new SecurityTokenDescriptor
|
||||
{
|
||||
Issuer = JwtParams.Issuer,
|
||||
Audience = JwtParams.Audience,
|
||||
Subject = new ClaimsIdentity(claims),
|
||||
Expires = DateTime.UtcNow.AddHours(1),
|
||||
SigningCredentials = new SigningCredentials(JwtParams.SecurityKey, SecurityAlgorithms.HmacSha256Signature)
|
||||
};
|
||||
var tokenHandler = new JwtSecurityTokenHandler();
|
||||
var token = tokenHandler.CreateToken(tokenDescriptor);
|
||||
return tokenHandler.WriteToken(token);
|
||||
}
|
||||
var tokenDescriptor = new SecurityTokenDescriptor
|
||||
{
|
||||
Issuer = JwtParams.Issuer,
|
||||
Audience = JwtParams.Audience,
|
||||
Subject = new ClaimsIdentity(claims),
|
||||
Expires = DateTime.UtcNow.AddHours(1),
|
||||
SigningCredentials = new SigningCredentials(JwtParams.SecurityKey, SecurityAlgorithms.HmacSha256Signature)
|
||||
};
|
||||
var tokenHandler = new JwtSecurityTokenHandler();
|
||||
var token = tokenHandler.CreateToken(tokenDescriptor);
|
||||
return tokenHandler.WriteToken(token);
|
||||
}
|
||||
|
||||
private static string CreateKeyCloakJwtToken(this AuthUser authUser, string keycloakGetTokenUrl)
|
||||
{
|
||||
var restClient = new RestClient();
|
||||
private static string CreateKeyCloakJwtToken(this AuthUser authUser, string keycloakGetTokenUrl)
|
||||
{
|
||||
var restClient = new RestClient();
|
||||
|
||||
var request = new RestRequest(keycloakGetTokenUrl, Method.Post);
|
||||
request.AddParameter("username", authUser.Username);
|
||||
request.AddParameter("password", authUser.Password);
|
||||
request.AddParameter("client_id", authUser.ClientId);
|
||||
request.AddParameter("grant_type", authUser.GrantType);
|
||||
var request = new RestRequest(keycloakGetTokenUrl, Method.Post);
|
||||
request.AddParameter("username", authUser.Username);
|
||||
request.AddParameter("password", authUser.Password);
|
||||
request.AddParameter("client_id", authUser.ClientId);
|
||||
request.AddParameter("grant_type", authUser.GrantType);
|
||||
|
||||
var keyCloackResponse = restClient.Post(request);
|
||||
if (keyCloackResponse.IsSuccessful && !String.IsNullOrEmpty(keyCloackResponse.Content))
|
||||
{
|
||||
var token = JsonSerializer.Deserialize<JwtToken>(keyCloackResponse.Content)!;
|
||||
return token.AccessToken;
|
||||
}
|
||||
var keycloakResponse = restClient.Post(request);
|
||||
if (keycloakResponse.IsSuccessful && !String.IsNullOrEmpty(keycloakResponse.Content))
|
||||
{
|
||||
var token = JsonSerializer.Deserialize<JwtToken>(keycloakResponse.Content)!;
|
||||
return token.AccessToken;
|
||||
}
|
||||
|
||||
return String.Empty;
|
||||
}
|
||||
return String.Empty;
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ namespace Persistence.Client
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
private static readonly RefitSettings RefitSettings = new(new SystemTextJsonContentSerializer(JsonSerializerOptions));
|
||||
private HttpClient httpClient;
|
||||
private readonly HttpClient httpClient;
|
||||
public PersistenceClientFactory(IHttpClientFactory httpClientFactory, IConfiguration configuration)
|
||||
{
|
||||
this.httpClient = httpClientFactory.CreateClient();
|
||||
|
@ -1,7 +1,6 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Npgsql;
|
||||
|
||||
namespace Persistence.Database.Model;
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Persistence.Models;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Persistence.Database.Model;
|
||||
|
||||
|
@ -3,8 +3,7 @@ using Persistence.Database.Model;
|
||||
using Xunit;
|
||||
|
||||
namespace Persistence.IntegrationTests;
|
||||
public abstract class BaseIntegrationTest : IClassFixture<WebAppFactoryFixture>,
|
||||
IDisposable
|
||||
public abstract class BaseIntegrationTest : IClassFixture<WebAppFactoryFixture>, IDisposable
|
||||
{
|
||||
protected readonly IServiceScope scope;
|
||||
|
||||
@ -21,5 +20,6 @@ public abstract class BaseIntegrationTest : IClassFixture<WebAppFactoryFixture>,
|
||||
{
|
||||
scope.Dispose();
|
||||
dbContext.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ namespace Persistence.IntegrationTests.Controllers;
|
||||
public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
{
|
||||
private readonly IChangeLogClient client;
|
||||
private static Random generatorRandomDigits = new Random();
|
||||
private static readonly Random generatorRandomDigits = new();
|
||||
|
||||
public ChangeLogControllerTest(WebAppFactoryFixture factory) : base(factory)
|
||||
{
|
||||
@ -28,7 +28,7 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
{
|
||||
// arrange
|
||||
var idDiscriminator = Guid.NewGuid();
|
||||
var dtos = Generate(2, DateTimeOffset.UtcNow);
|
||||
var dtos = Generate(2);
|
||||
|
||||
// act
|
||||
var result = await client.ClearAndAddRange(idDiscriminator, dtos);
|
||||
@ -52,7 +52,7 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
|
||||
// assert
|
||||
Assert.Equal(HttpStatusCode.OK, result.StatusCode);
|
||||
Assert.Equal(insertedCount*2, result.Content);
|
||||
Assert.Equal(insertedCount * 2, result.Content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -61,7 +61,7 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
// arrange
|
||||
var count = 1;
|
||||
var idDiscriminator = Guid.NewGuid();
|
||||
var dtos = Generate(count, DateTimeOffset.UtcNow);
|
||||
var dtos = Generate(count);
|
||||
var dto = dtos.FirstOrDefault()!;
|
||||
|
||||
// act
|
||||
@ -78,7 +78,7 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
// arrange
|
||||
var count = 3;
|
||||
var idDiscriminator = Guid.NewGuid();
|
||||
var dtos = Generate(count, DateTimeOffset.UtcNow);
|
||||
var dtos = Generate(count);
|
||||
|
||||
// act
|
||||
var result = await client.AddRange(idDiscriminator, dtos);
|
||||
@ -93,7 +93,7 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
{
|
||||
// arrange
|
||||
var idDiscriminator = Guid.NewGuid();
|
||||
var dtos = Generate(1, DateTimeOffset.UtcNow);
|
||||
var dtos = Generate(1);
|
||||
var dto = dtos.FirstOrDefault()!;
|
||||
var result = await client.Add(idDiscriminator, dto);
|
||||
Assert.Equal(HttpStatusCode.Created, result.StatusCode);
|
||||
@ -102,7 +102,7 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
.Where(x => x.IdDiscriminator == idDiscriminator)
|
||||
.FirstOrDefault();
|
||||
dto = entity.Adapt<DataWithWellDepthAndSectionDto>();
|
||||
dto.DepthEnd = dto.DepthEnd + 10;
|
||||
dto.DepthEnd += 10;
|
||||
|
||||
// act
|
||||
result = await client.Update(dto);
|
||||
@ -143,7 +143,7 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
{
|
||||
// arrange
|
||||
var count = 2;
|
||||
var dtos = Generate(count, DateTimeOffset.UtcNow);
|
||||
var dtos = Generate(count);
|
||||
var entities = dtos.Select(d => d.Adapt<ChangeLog>()).ToArray();
|
||||
dbContext.ChangeLog.AddRange(entities);
|
||||
dbContext.SaveChanges();
|
||||
@ -169,7 +169,7 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
public async Task Delete_returns_success()
|
||||
{
|
||||
// arrange
|
||||
var dtos = Generate(1, DateTimeOffset.UtcNow);
|
||||
var dtos = Generate(1);
|
||||
var dto = dtos.FirstOrDefault()!;
|
||||
var entity = dto.Adapt<ChangeLog>();
|
||||
dbContext.ChangeLog.Add(entity);
|
||||
@ -188,7 +188,7 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
{
|
||||
// arrange
|
||||
var count = 10;
|
||||
var dtos = Generate(count, DateTimeOffset.UtcNow);
|
||||
var dtos = Generate(count);
|
||||
var entities = dtos.Select(d => d.Adapt<ChangeLog>()).ToArray();
|
||||
dbContext.ChangeLog.AddRange(entities);
|
||||
dbContext.SaveChanges();
|
||||
@ -248,8 +248,8 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
|
||||
var filterRequest = new SectionPartRequest()
|
||||
{
|
||||
DepthStart = 0,
|
||||
DepthEnd = 1000,
|
||||
DepthStart = 0,
|
||||
DepthEnd = 1000,
|
||||
};
|
||||
|
||||
var paginationRequest = new PaginationRequest()
|
||||
@ -294,7 +294,7 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
|
||||
foreach (var entity in entities)
|
||||
{
|
||||
entity.DepthEnd = entity.DepthEnd + 10;
|
||||
entity.DepthEnd += 10;
|
||||
}
|
||||
var dtos = entities.Select(e => e.Adapt<DataWithWellDepthAndSectionDto>()).ToArray();
|
||||
await client.UpdateRange(dtos);
|
||||
@ -311,7 +311,7 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
}
|
||||
|
||||
|
||||
private static IEnumerable<DataWithWellDepthAndSectionDto> Generate(int count, DateTimeOffset from)
|
||||
private static IEnumerable<DataWithWellDepthAndSectionDto> Generate(int count)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
yield return new DataWithWellDepthAndSectionDto()
|
||||
@ -334,7 +334,7 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
var maxDayCount = daysRange.Item2;
|
||||
|
||||
Guid idDiscriminator = Guid.NewGuid();
|
||||
var dtos = Generate(count, DateTimeOffset.UtcNow);
|
||||
var dtos = Generate(count);
|
||||
var entities = dtos.Select(d =>
|
||||
{
|
||||
var entity = d.Adapt<ChangeLog>();
|
||||
|
@ -28,7 +28,7 @@ public class DataSaubControllerTest : TimeSeriesBaseControllerTest<DataSaub, Dat
|
||||
WellDepth = 18,
|
||||
};
|
||||
|
||||
private readonly DataSaub entity = new DataSaub()
|
||||
private readonly DataSaub entity = new()
|
||||
{
|
||||
AxialLoad = 1,
|
||||
BitDepth = 2,
|
||||
|
@ -9,11 +9,11 @@ namespace Persistence.IntegrationTests.Controllers
|
||||
{
|
||||
public class SetpointControllerTest : BaseIntegrationTest
|
||||
{
|
||||
private ISetpointClient setpointClient;
|
||||
private readonly ISetpointClient setpointClient;
|
||||
private class TestObject
|
||||
{
|
||||
public string? value1 { get; set; }
|
||||
public int? value2 { get; set; }
|
||||
public string? Value1 { get; set; }
|
||||
public int? Value2 { get; set; }
|
||||
}
|
||||
public SetpointControllerTest(WebAppFactoryFixture factory) : base(factory)
|
||||
{
|
||||
@ -224,8 +224,8 @@ namespace Persistence.IntegrationTests.Controllers
|
||||
var setpointKey = Guid.NewGuid();
|
||||
var setpointValue = new TestObject()
|
||||
{
|
||||
value1 = "1",
|
||||
value2 = 2
|
||||
Value1 = "1",
|
||||
Value2 = 2
|
||||
};
|
||||
|
||||
//act
|
||||
|
@ -1,289 +1,289 @@
|
||||
using System.Net;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Persistence.Client;
|
||||
using Persistence.Client.Clients;
|
||||
using Persistence.Database.Entity;
|
||||
using Persistence.Models;
|
||||
using Persistence.Models.Requests;
|
||||
using System.Net;
|
||||
using Xunit;
|
||||
|
||||
namespace Persistence.IntegrationTests.Controllers
|
||||
{
|
||||
public class TechMessagesControllerTest : BaseIntegrationTest
|
||||
{
|
||||
private static readonly string SystemCacheKey = $"{typeof(Database.Entity.DrillingSystem).FullName}CacheKey";
|
||||
private readonly ITechMessagesClient techMessagesClient;
|
||||
private readonly IMemoryCache memoryCache;
|
||||
public TechMessagesControllerTest(WebAppFactoryFixture factory) : base(factory)
|
||||
{
|
||||
var scope = factory.Services.CreateScope();
|
||||
var persistenceClientFactory = scope.ServiceProvider
|
||||
.GetRequiredService<PersistenceClientFactory>();
|
||||
public class TechMessagesControllerTest : BaseIntegrationTest
|
||||
{
|
||||
private static readonly string SystemCacheKey = $"{typeof(Database.Entity.DrillingSystem).FullName}CacheKey";
|
||||
private readonly ITechMessagesClient techMessagesClient;
|
||||
private readonly IMemoryCache memoryCache;
|
||||
public TechMessagesControllerTest(WebAppFactoryFixture factory) : base(factory)
|
||||
{
|
||||
var scope = factory.Services.CreateScope();
|
||||
var persistenceClientFactory = scope.ServiceProvider
|
||||
.GetRequiredService<PersistenceClientFactory>();
|
||||
|
||||
techMessagesClient = persistenceClientFactory.GetClient<ITechMessagesClient>();
|
||||
memoryCache = scope.ServiceProvider.GetRequiredService<IMemoryCache>();
|
||||
}
|
||||
techMessagesClient = persistenceClientFactory.GetClient<ITechMessagesClient>();
|
||||
memoryCache = scope.ServiceProvider.GetRequiredService<IMemoryCache>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetPage_returns_success()
|
||||
{
|
||||
//arrange
|
||||
memoryCache.Remove(SystemCacheKey);
|
||||
dbContext.CleanupDbSet<TechMessage>();
|
||||
dbContext.CleanupDbSet<Database.Entity.DrillingSystem>();
|
||||
[Fact]
|
||||
public async Task GetPage_returns_success()
|
||||
{
|
||||
//arrange
|
||||
memoryCache.Remove(SystemCacheKey);
|
||||
dbContext.CleanupDbSet<TechMessage>();
|
||||
dbContext.CleanupDbSet<Database.Entity.DrillingSystem>();
|
||||
|
||||
var PaginationRequest = new PaginationRequest()
|
||||
{
|
||||
Skip = 1,
|
||||
Take = 2,
|
||||
SortSettings = nameof(TechMessage.CategoryId)
|
||||
};
|
||||
var PaginationRequest = new PaginationRequest()
|
||||
{
|
||||
Skip = 1,
|
||||
Take = 2,
|
||||
SortSettings = nameof(TechMessage.CategoryId)
|
||||
};
|
||||
|
||||
//act
|
||||
var response = await techMessagesClient.GetPage(PaginationRequest, new CancellationToken());
|
||||
//act
|
||||
var response = await techMessagesClient.GetPage(PaginationRequest, new CancellationToken());
|
||||
|
||||
//assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content);
|
||||
Assert.Empty(response.Content.Items);
|
||||
Assert.Equal(PaginationRequest.Skip, response.Content.Skip);
|
||||
Assert.Equal(PaginationRequest.Take, response.Content.Take);
|
||||
}
|
||||
//assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content);
|
||||
Assert.Empty(response.Content.Items);
|
||||
Assert.Equal(PaginationRequest.Skip, response.Content.Skip);
|
||||
Assert.Equal(PaginationRequest.Take, response.Content.Take);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetPage_AfterSave_returns_success()
|
||||
{
|
||||
//arrange
|
||||
var dtos = await InsertRange();
|
||||
var dtosCount = dtos.Count();
|
||||
var PaginationRequest = new PaginationRequest()
|
||||
{
|
||||
Skip = 0,
|
||||
Take = 2,
|
||||
SortSettings = nameof(TechMessage.CategoryId)
|
||||
};
|
||||
[Fact]
|
||||
public async Task GetPage_AfterSave_returns_success()
|
||||
{
|
||||
//arrange
|
||||
var dtos = await InsertRange();
|
||||
var dtosCount = dtos.Count();
|
||||
var PaginationRequest = new PaginationRequest()
|
||||
{
|
||||
Skip = 0,
|
||||
Take = 2,
|
||||
SortSettings = nameof(TechMessage.CategoryId)
|
||||
};
|
||||
|
||||
//act
|
||||
var response = await techMessagesClient.GetPage(PaginationRequest, new CancellationToken());
|
||||
//act
|
||||
var response = await techMessagesClient.GetPage(PaginationRequest, new CancellationToken());
|
||||
|
||||
//assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content);
|
||||
Assert.Equal(dtosCount, response.Content.Count);
|
||||
}
|
||||
//assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content);
|
||||
Assert.Equal(dtosCount, response.Content.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InsertRange_returns_success()
|
||||
{
|
||||
await InsertRange();
|
||||
}
|
||||
[Fact]
|
||||
public async Task InsertRange_returns_success()
|
||||
{
|
||||
await InsertRange();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InsertRange_returns_BadRequest()
|
||||
{
|
||||
//arrange
|
||||
var dtos = new List<TechMessageDto>()
|
||||
{
|
||||
new TechMessageDto()
|
||||
{
|
||||
EventId = Guid.NewGuid(),
|
||||
CategoryId = -1, // < 0
|
||||
[Fact]
|
||||
public async Task InsertRange_returns_BadRequest()
|
||||
{
|
||||
//arrange
|
||||
var dtos = new List<TechMessageDto>()
|
||||
{
|
||||
new()
|
||||
{
|
||||
EventId = Guid.NewGuid(),
|
||||
CategoryId = -1, // < 0
|
||||
Timestamp = DateTimeOffset.UtcNow,
|
||||
Depth = -1, // < 0
|
||||
Depth = -1, // < 0
|
||||
MessageText = string.Empty, // length < 0
|
||||
System = string.Concat(Enumerable.Repeat(nameof(TechMessageDto.System), 100)), // length > 256
|
||||
UserId = Guid.NewGuid()
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
//act
|
||||
var response = await techMessagesClient.AddRange(dtos, new CancellationToken());
|
||||
//act
|
||||
var response = await techMessagesClient.AddRange(dtos, new CancellationToken());
|
||||
|
||||
//assert
|
||||
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
||||
}
|
||||
//assert
|
||||
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetSystems_returns_success()
|
||||
{
|
||||
//arrange
|
||||
memoryCache.Remove(SystemCacheKey);
|
||||
dbContext.CleanupDbSet<TechMessage>();
|
||||
dbContext.CleanupDbSet<Database.Entity.DrillingSystem>();
|
||||
[Fact]
|
||||
public async Task GetSystems_returns_success()
|
||||
{
|
||||
//arrange
|
||||
memoryCache.Remove(SystemCacheKey);
|
||||
dbContext.CleanupDbSet<TechMessage>();
|
||||
dbContext.CleanupDbSet<Database.Entity.DrillingSystem>();
|
||||
|
||||
//act
|
||||
var response = await techMessagesClient.GetSystems(new CancellationToken());
|
||||
//act
|
||||
var response = await techMessagesClient.GetSystems(new CancellationToken());
|
||||
|
||||
//assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content);
|
||||
Assert.Empty(response.Content);
|
||||
}
|
||||
//assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content);
|
||||
Assert.Empty(response.Content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetSystems_AfterSave_returns_success()
|
||||
{
|
||||
//arrange
|
||||
var dtos = await InsertRange();
|
||||
var systems = dtos
|
||||
.Select(e => e.System)
|
||||
.Distinct()
|
||||
.ToArray();
|
||||
[Fact]
|
||||
public async Task GetSystems_AfterSave_returns_success()
|
||||
{
|
||||
//arrange
|
||||
var dtos = await InsertRange();
|
||||
var systems = dtos
|
||||
.Select(e => e.System)
|
||||
.Distinct()
|
||||
.ToArray();
|
||||
|
||||
//act
|
||||
var response = await techMessagesClient.GetSystems(new CancellationToken());
|
||||
//act
|
||||
var response = await techMessagesClient.GetSystems(new CancellationToken());
|
||||
|
||||
//assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content);
|
||||
string?[]? content = response.Content?.ToArray();
|
||||
Assert.Equal(systems, content);
|
||||
}
|
||||
//assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content);
|
||||
string?[]? content = response.Content?.ToArray();
|
||||
Assert.Equal(systems, content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetStatistics_returns_success()
|
||||
{
|
||||
//arrange
|
||||
memoryCache.Remove(SystemCacheKey);
|
||||
dbContext.CleanupDbSet<TechMessage>();
|
||||
dbContext.CleanupDbSet<Database.Entity.DrillingSystem>();
|
||||
[Fact]
|
||||
public async Task GetStatistics_returns_success()
|
||||
{
|
||||
//arrange
|
||||
memoryCache.Remove(SystemCacheKey);
|
||||
dbContext.CleanupDbSet<TechMessage>();
|
||||
dbContext.CleanupDbSet<Database.Entity.DrillingSystem>();
|
||||
|
||||
var imortantId = 1;
|
||||
var autoDrillingSystem = nameof(TechMessageDto.System);
|
||||
var importantId = 1;
|
||||
var autoDrillingSystem = nameof(TechMessageDto.System);
|
||||
|
||||
//act
|
||||
var response = await techMessagesClient.GetStatistics(autoDrillingSystem, imortantId, new CancellationToken());
|
||||
//act
|
||||
var response = await techMessagesClient.GetStatistics(autoDrillingSystem, importantId, new CancellationToken());
|
||||
|
||||
//assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content);
|
||||
Assert.Empty(response.Content);
|
||||
}
|
||||
//assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content);
|
||||
Assert.Empty(response.Content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetStatistics_AfterSave_returns_success()
|
||||
{
|
||||
//arrange
|
||||
var imortantId = 0;
|
||||
var autoDrillingSystem = nameof(TechMessageDto.System);
|
||||
var dtos = await InsertRange();
|
||||
var filteredDtos = dtos.Where(e => e.CategoryId == imortantId && e.System == autoDrillingSystem);
|
||||
[Fact]
|
||||
public async Task GetStatistics_AfterSave_returns_success()
|
||||
{
|
||||
//arrange
|
||||
var importantId = 0;
|
||||
var autoDrillingSystem = nameof(TechMessageDto.System);
|
||||
var dtos = await InsertRange();
|
||||
var filteredDtos = dtos.Where(e => e.CategoryId == importantId && e.System == autoDrillingSystem);
|
||||
|
||||
//act
|
||||
var response = await techMessagesClient.GetStatistics(autoDrillingSystem, imortantId, new CancellationToken());
|
||||
//act
|
||||
var response = await techMessagesClient.GetStatistics(autoDrillingSystem, importantId, new CancellationToken());
|
||||
|
||||
//assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content);
|
||||
var categories = response.Content
|
||||
.FirstOrDefault()?.Categories
|
||||
.FirstOrDefault(e => e.Key == 0).Value;
|
||||
Assert.Equal(filteredDtos.Count(), categories);
|
||||
}
|
||||
//assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content);
|
||||
var categories = response.Content
|
||||
.FirstOrDefault()?.Categories
|
||||
.FirstOrDefault(e => e.Key == 0).Value;
|
||||
Assert.Equal(filteredDtos.Count(), categories);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetDatesRange_returns_success()
|
||||
{
|
||||
//act
|
||||
var response = await techMessagesClient.GetDatesRangeAsync(new CancellationToken());
|
||||
[Fact]
|
||||
public async Task GetDatesRange_returns_success()
|
||||
{
|
||||
//act
|
||||
var response = await techMessagesClient.GetDatesRangeAsync(new CancellationToken());
|
||||
|
||||
//assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content);
|
||||
//Assert.Equal(DateTimeOffset.MinValue, response.Content?.From);
|
||||
//Assert.Equal(DateTimeOffset.MaxValue, response.Content?.To);
|
||||
}
|
||||
//assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content);
|
||||
//Assert.Equal(DateTimeOffset.MinValue, response.Content?.From);
|
||||
//Assert.Equal(DateTimeOffset.MaxValue, response.Content?.To);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetDatesRange_AfterSave_returns_success()
|
||||
{
|
||||
//arrange
|
||||
await InsertRange();
|
||||
[Fact]
|
||||
public async Task GetDatesRange_AfterSave_returns_success()
|
||||
{
|
||||
//arrange
|
||||
await InsertRange();
|
||||
|
||||
//act
|
||||
var response = await techMessagesClient.GetDatesRangeAsync(new CancellationToken());
|
||||
//act
|
||||
var response = await techMessagesClient.GetDatesRangeAsync(new CancellationToken());
|
||||
|
||||
//assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content);
|
||||
Assert.NotNull(response.Content?.From);
|
||||
Assert.NotNull(response.Content?.To);
|
||||
}
|
||||
//assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content);
|
||||
Assert.NotNull(response.Content?.From);
|
||||
Assert.NotNull(response.Content?.To);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetPart_returns_success()
|
||||
{
|
||||
//arrange
|
||||
var dateBegin = DateTimeOffset.UtcNow;
|
||||
var take = 2;
|
||||
[Fact]
|
||||
public async Task GetPart_returns_success()
|
||||
{
|
||||
//arrange
|
||||
var dateBegin = DateTimeOffset.UtcNow;
|
||||
var take = 2;
|
||||
|
||||
//act
|
||||
var response = await techMessagesClient.GetPart(dateBegin, take, new CancellationToken());
|
||||
//act
|
||||
var response = await techMessagesClient.GetPart(dateBegin, take, new CancellationToken());
|
||||
|
||||
//assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content);
|
||||
Assert.Empty(response.Content);
|
||||
}
|
||||
//assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content);
|
||||
Assert.Empty(response.Content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetPart_AfterSave_returns_success()
|
||||
{
|
||||
//arrange
|
||||
var dateBegin = DateTimeOffset.UtcNow;
|
||||
var take = 1;
|
||||
await InsertRange();
|
||||
[Fact]
|
||||
public async Task GetPart_AfterSave_returns_success()
|
||||
{
|
||||
//arrange
|
||||
var dateBegin = DateTimeOffset.UtcNow;
|
||||
var take = 1;
|
||||
await InsertRange();
|
||||
|
||||
//act
|
||||
var response = await techMessagesClient.GetPart(dateBegin, take, new CancellationToken());
|
||||
//act
|
||||
var response = await techMessagesClient.GetPart(dateBegin, take, new CancellationToken());
|
||||
|
||||
//assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content);
|
||||
Assert.NotEmpty(response.Content);
|
||||
}
|
||||
//assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content);
|
||||
Assert.NotEmpty(response.Content);
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<TechMessageDto>> InsertRange()
|
||||
{
|
||||
//arrange
|
||||
memoryCache.Remove(SystemCacheKey);
|
||||
dbContext.CleanupDbSet<TechMessage>();
|
||||
dbContext.CleanupDbSet<DrillingSystem>();
|
||||
private async Task<IEnumerable<TechMessageDto>> InsertRange()
|
||||
{
|
||||
//arrange
|
||||
memoryCache.Remove(SystemCacheKey);
|
||||
dbContext.CleanupDbSet<TechMessage>();
|
||||
dbContext.CleanupDbSet<DrillingSystem>();
|
||||
|
||||
var dtos = new List<TechMessageDto>()
|
||||
{
|
||||
new TechMessageDto()
|
||||
{
|
||||
EventId = Guid.NewGuid(),
|
||||
CategoryId = 1,
|
||||
Timestamp = DateTimeOffset.UtcNow,
|
||||
Depth = 1.11,
|
||||
MessageText = nameof(TechMessageDto.MessageText),
|
||||
System = nameof(TechMessageDto.System).ToLower(),
|
||||
UserId = Guid.NewGuid()
|
||||
},
|
||||
new TechMessageDto()
|
||||
{
|
||||
EventId = Guid.NewGuid(),
|
||||
CategoryId = 2,
|
||||
Timestamp = DateTimeOffset.UtcNow,
|
||||
Depth = 2.22,
|
||||
MessageText = nameof(TechMessageDto.MessageText),
|
||||
System = nameof(TechMessageDto.System).ToLower(),
|
||||
UserId = Guid.NewGuid()
|
||||
}
|
||||
};
|
||||
var dtos = new List<TechMessageDto>()
|
||||
{
|
||||
new()
|
||||
{
|
||||
EventId = Guid.NewGuid(),
|
||||
CategoryId = 1,
|
||||
Timestamp = DateTimeOffset.UtcNow,
|
||||
Depth = 1.11,
|
||||
MessageText = nameof(TechMessageDto.MessageText),
|
||||
System = nameof(TechMessageDto.System).ToLower(),
|
||||
UserId = Guid.NewGuid()
|
||||
},
|
||||
new()
|
||||
{
|
||||
EventId = Guid.NewGuid(),
|
||||
CategoryId = 2,
|
||||
Timestamp = DateTimeOffset.UtcNow,
|
||||
Depth = 2.22,
|
||||
MessageText = nameof(TechMessageDto.MessageText),
|
||||
System = nameof(TechMessageDto.System).ToLower(),
|
||||
UserId = Guid.NewGuid()
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//act
|
||||
var response = await techMessagesClient.AddRange(dtos, new CancellationToken());
|
||||
//act
|
||||
var response = await techMessagesClient.AddRange(dtos, new CancellationToken());
|
||||
|
||||
//assert
|
||||
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
|
||||
Assert.Equal(dtos.Count, response.Content);
|
||||
//assert
|
||||
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
|
||||
Assert.Equal(dtos.Count, response.Content);
|
||||
|
||||
return dtos;
|
||||
}
|
||||
}
|
||||
return dtos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ public abstract class TimeSeriesBaseControllerTest<TEntity, TDto> : BaseIntegrat
|
||||
where TEntity : class, ITimestampedData, new()
|
||||
where TDto : class, new()
|
||||
{
|
||||
private ITimeSeriesClient<TDto> timeSeriesClient;
|
||||
private readonly ITimeSeriesClient<TDto> timeSeriesClient;
|
||||
|
||||
public TimeSeriesBaseControllerTest(WebAppFactoryFixture factory) : base(factory)
|
||||
{
|
||||
@ -31,7 +31,7 @@ public abstract class TimeSeriesBaseControllerTest<TEntity, TDto> : BaseIntegrat
|
||||
var expected = dto.Adapt<TDto>();
|
||||
|
||||
//act
|
||||
var response = await timeSeriesClient.AddRange(new TDto[] { expected });
|
||||
var response = await timeSeriesClient.AddRange([expected]);
|
||||
|
||||
//assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
@ -116,7 +116,7 @@ public abstract class TimeSeriesBaseControllerTest<TEntity, TDto> : BaseIntegrat
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Equal(entities.Count(), response.Content.Count());
|
||||
Assert.Equal(entities.Count, response.Content.Count());
|
||||
}
|
||||
|
||||
|
||||
|
@ -111,7 +111,7 @@ public class TimestampedSetControllerTest : BaseIntegrationTest
|
||||
Guid idDiscriminator = Guid.NewGuid();
|
||||
int count = 10;
|
||||
IEnumerable<TimestampedSetDto> testSets = Generate(count, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7)));
|
||||
var insertResponse = await client.AddRange(idDiscriminator, testSets);
|
||||
await client.AddRange(idDiscriminator, testSets);
|
||||
var expectedCount = count / 2;
|
||||
|
||||
// act
|
||||
@ -133,7 +133,7 @@ public class TimestampedSetControllerTest : BaseIntegrationTest
|
||||
var expectedCount = 1;
|
||||
int count = 10 + expectedCount;
|
||||
IEnumerable<TimestampedSetDto> testSets = Generate(count, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7)));
|
||||
var insertResponse = await client.AddRange(idDiscriminator, testSets);
|
||||
await client.AddRange(idDiscriminator, testSets);
|
||||
|
||||
// act
|
||||
var response = await client.Get(idDiscriminator, null, null, count - expectedCount, count);
|
||||
@ -174,7 +174,7 @@ public class TimestampedSetControllerTest : BaseIntegrationTest
|
||||
var dateMin = DateTimeOffset.Now;
|
||||
var dateMax = DateTimeOffset.Now.AddSeconds(count - 1);
|
||||
IEnumerable<TimestampedSetDto> testSets = Generate(count, dateMin.ToOffset(TimeSpan.FromHours(7)));
|
||||
var insertResponse = await client.AddRange(idDiscriminator, testSets);
|
||||
await client.AddRange(idDiscriminator, testSets);
|
||||
var tolerance = TimeSpan.FromSeconds(1);
|
||||
|
||||
// act
|
||||
@ -195,7 +195,7 @@ public class TimestampedSetControllerTest : BaseIntegrationTest
|
||||
Guid idDiscriminator = Guid.NewGuid();
|
||||
int count = 144;
|
||||
IEnumerable<TimestampedSetDto> testSets = Generate(count, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7)));
|
||||
var insertResponse = await client.AddRange(idDiscriminator, testSets);
|
||||
await client.AddRange(idDiscriminator, testSets);
|
||||
|
||||
// act
|
||||
var response = await client.Count(idDiscriminator);
|
||||
|
@ -60,5 +60,7 @@ public class WebAppFactoryFixture : WebApplicationFactory<Startup>
|
||||
.Options);
|
||||
|
||||
await dbContext.Database.EnsureDeletedAsync();
|
||||
|
||||
GC.SuppressFinalize(dbContext);
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ public static class EFExtensionsSortBy
|
||||
var name = propertyInfo.Name.ToLower();
|
||||
ParameterExpression arg = Expression.Parameter(type, "x");
|
||||
MemberExpression property = Expression.Property(arg, propertyInfo.Name);
|
||||
var selector = Expression.Lambda(property, new ParameterExpression[] { arg });
|
||||
var selector = Expression.Lambda(property, [ arg ]);
|
||||
var typeAccessor = new TypeAccessor
|
||||
{
|
||||
KeySelector = selector,
|
||||
@ -261,7 +261,7 @@ public static class EFExtensionsSortBy
|
||||
: orderByAscending;
|
||||
|
||||
var newQuery = (IOrderedQueryable<TSource>)genericMethod
|
||||
.Invoke(genericMethod, [ query, lambdaExpression ])!;
|
||||
.Invoke(genericMethod, [query, lambdaExpression])!;
|
||||
return newQuery;
|
||||
}
|
||||
}
|
@ -29,7 +29,7 @@ public static class QueryBuilders
|
||||
return query;
|
||||
}
|
||||
|
||||
public static IQueryable<TEntity> Apply<TEntity>(this IQueryable<TEntity> query,DateTimeOffset momentUtc)
|
||||
public static IQueryable<TEntity> Apply<TEntity>(this IQueryable<TEntity> query, DateTimeOffset momentUtc)
|
||||
where TEntity : class, IChangeLog
|
||||
{
|
||||
momentUtc = momentUtc.ToUniversalTime();
|
||||
|
@ -9,7 +9,7 @@ using UuidExtensions;
|
||||
namespace Persistence.Repository.Repositories;
|
||||
public class ChangeLogRepository : IChangeLogRepository
|
||||
{
|
||||
private DbContext db;
|
||||
private readonly DbContext db;
|
||||
|
||||
public ChangeLogRepository(DbContext db)
|
||||
{
|
||||
|
@ -5,174 +5,174 @@ using Persistence.Database.Entity;
|
||||
using Persistence.Models;
|
||||
using Persistence.Models.Requests;
|
||||
using Persistence.Repositories;
|
||||
using Persistence.Repository.Extensions;
|
||||
using UuidExtensions;
|
||||
|
||||
namespace Persistence.Repository.Repositories
|
||||
{
|
||||
public class TechMessagesRepository : ITechMessagesRepository
|
||||
{
|
||||
private static readonly string SystemCacheKey = $"{typeof(Database.Entity.DrillingSystem).FullName}CacheKey";
|
||||
private const int CacheExpirationInMinutes = 60;
|
||||
private readonly IMemoryCache memoryCache;
|
||||
private DbContext db;
|
||||
public class TechMessagesRepository : ITechMessagesRepository
|
||||
{
|
||||
private static readonly string SystemCacheKey = $"{typeof(Database.Entity.DrillingSystem).FullName}CacheKey";
|
||||
private const int CacheExpirationInMinutes = 60;
|
||||
private readonly IMemoryCache memoryCache;
|
||||
private readonly DbContext db;
|
||||
|
||||
public TechMessagesRepository(DbContext db, IMemoryCache memoryCache)
|
||||
{
|
||||
this.memoryCache = memoryCache;
|
||||
this.db = db;
|
||||
}
|
||||
public TechMessagesRepository(DbContext db, IMemoryCache memoryCache)
|
||||
{
|
||||
this.memoryCache = memoryCache;
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
protected virtual IQueryable<TechMessage> GetQueryReadOnly() => db.Set<TechMessage>()
|
||||
.Include(e => e.System);
|
||||
protected virtual IQueryable<TechMessage> GetQueryReadOnly() => db.Set<TechMessage>()
|
||||
.Include(e => e.System);
|
||||
|
||||
public async Task<PaginationContainer<TechMessageDto>> GetPage(PaginationRequest request, CancellationToken token)
|
||||
{
|
||||
var query = GetQueryReadOnly();
|
||||
var count = await query.CountAsync(token);
|
||||
public async Task<PaginationContainer<TechMessageDto>> GetPage(PaginationRequest request, CancellationToken token)
|
||||
{
|
||||
var query = GetQueryReadOnly();
|
||||
var count = await query.CountAsync(token);
|
||||
|
||||
var sort = request.SortSettings != string.Empty
|
||||
? request.SortSettings
|
||||
: nameof(TechMessage.Timestamp);
|
||||
var entities = await query
|
||||
.SortBy(request.SortSettings)
|
||||
.Skip(request.Skip)
|
||||
.Take(request.Take)
|
||||
.ToArrayAsync(token);
|
||||
var sort = request.SortSettings != string.Empty
|
||||
? request.SortSettings!
|
||||
: nameof(TechMessage.Timestamp);
|
||||
var entities = await query
|
||||
.SortBy(sort)
|
||||
.Skip(request.Skip)
|
||||
.Take(request.Take)
|
||||
.ToArrayAsync(token);
|
||||
|
||||
var dto = new PaginationContainer<TechMessageDto>()
|
||||
{
|
||||
Skip = request.Skip,
|
||||
Take = request.Take,
|
||||
Count = count,
|
||||
Items = entities.Select(e => e.Adapt<TechMessageDto>())
|
||||
};
|
||||
var dto = new PaginationContainer<TechMessageDto>()
|
||||
{
|
||||
Skip = request.Skip,
|
||||
Take = request.Take,
|
||||
Count = count,
|
||||
Items = entities.Select(e => e.Adapt<TechMessageDto>())
|
||||
};
|
||||
|
||||
return dto;
|
||||
}
|
||||
return dto;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<MessagesStatisticDto>> GetStatistics(IEnumerable<string> autoDrillingSystem, IEnumerable<int> categoryIds, CancellationToken token)
|
||||
{
|
||||
var query = GetQueryReadOnly();
|
||||
var systems = autoDrillingSystem.Select(s => s.ToLower().Trim());
|
||||
var result = await query
|
||||
.Where(e => systems.Count() == 0 || systems.Contains(e.System.Name.ToLower().Trim()))
|
||||
.GroupBy(e => e.System.Name, (key, group) => new
|
||||
{
|
||||
System = key,
|
||||
Categories = group
|
||||
.Where(g => categoryIds.Count() == 0 || categoryIds.Contains(g.CategoryId))
|
||||
})
|
||||
.ToArrayAsync(token);
|
||||
public async Task<IEnumerable<MessagesStatisticDto>> GetStatistics(IEnumerable<string> autoDrillingSystem, IEnumerable<int> categoryIds, CancellationToken token)
|
||||
{
|
||||
var query = GetQueryReadOnly();
|
||||
var systems = autoDrillingSystem.Select(s => s.ToLower().Trim());
|
||||
var result = await query
|
||||
.Where(e => !systems.Any() || systems.Contains(e.System.Name.ToLower().Trim()))
|
||||
.GroupBy(e => e.System.Name, (key, group) => new
|
||||
{
|
||||
System = key,
|
||||
Categories = group
|
||||
.Where(g => !categoryIds.Any() || categoryIds.Contains(g.CategoryId))
|
||||
})
|
||||
.ToArrayAsync(token);
|
||||
|
||||
var entities = new List<MessagesStatisticDto>();
|
||||
foreach (var e in result)
|
||||
{
|
||||
var categories = e.Categories
|
||||
.GroupBy(g => g.CategoryId)
|
||||
.ToDictionary(c => c.Key, v => v.Count());
|
||||
var entity = new MessagesStatisticDto()
|
||||
{
|
||||
System = e.System,
|
||||
Categories = categories
|
||||
};
|
||||
entities.Add(entity);
|
||||
}
|
||||
var entities = new List<MessagesStatisticDto>();
|
||||
foreach (var e in result)
|
||||
{
|
||||
var categories = e.Categories
|
||||
.GroupBy(g => g.CategoryId)
|
||||
.ToDictionary(c => c.Key, v => v.Count());
|
||||
var entity = new MessagesStatisticDto()
|
||||
{
|
||||
System = e.System,
|
||||
Categories = categories
|
||||
};
|
||||
entities.Add(entity);
|
||||
}
|
||||
|
||||
return entities;
|
||||
}
|
||||
return entities;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<string>> GetSystems(CancellationToken token)
|
||||
{
|
||||
var entities = await GetDrillingSystems(token);
|
||||
var result = entities.Select(e => e.Name);
|
||||
public async Task<IEnumerable<string>> GetSystems(CancellationToken token)
|
||||
{
|
||||
var entities = await GetDrillingSystems(token);
|
||||
var result = entities.Select(e => e.Name);
|
||||
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<int> AddRange(IEnumerable<TechMessageDto> dtos, Guid userId, CancellationToken token)
|
||||
{
|
||||
public async Task<int> AddRange(IEnumerable<TechMessageDto> dtos, Guid userId, CancellationToken token)
|
||||
{
|
||||
|
||||
var entities = new List<TechMessage>();
|
||||
foreach (var dto in dtos)
|
||||
{
|
||||
var entity = dto.Adapt<TechMessage>();
|
||||
var systems = await GetDrillingSystems(token);
|
||||
var systemId = systems.FirstOrDefault(e => e.Name.ToLower().Trim() == dto.System.ToLower().Trim())?.SystemId
|
||||
?? await CreateDrillingSystem(dto.System, token);
|
||||
var entities = new List<TechMessage>();
|
||||
foreach (var dto in dtos)
|
||||
{
|
||||
var entity = dto.Adapt<TechMessage>();
|
||||
var systems = await GetDrillingSystems(token);
|
||||
var systemId = systems.FirstOrDefault(e => e.Name.ToLower().Trim() == dto.System.ToLower().Trim())?.SystemId
|
||||
?? await CreateDrillingSystem(dto.System, token);
|
||||
|
||||
entity.SystemId = systemId;
|
||||
entity.UserId = userId;
|
||||
entity.SystemId = systemId;
|
||||
entity.UserId = userId;
|
||||
|
||||
entities.Add(entity);
|
||||
}
|
||||
entities.Add(entity);
|
||||
}
|
||||
|
||||
await db.Set<TechMessage>().AddRangeAsync(entities, token);
|
||||
var result = await db.SaveChangesAsync(token);
|
||||
await db.Set<TechMessage>().AddRangeAsync(entities, token);
|
||||
var result = await db.SaveChangesAsync(token);
|
||||
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<TechMessageDto>> GetPart(DateTimeOffset dateBegin, int take, CancellationToken token)
|
||||
{
|
||||
var query = GetQueryReadOnly();
|
||||
var entities = await query
|
||||
.Where(e => e.Timestamp >= dateBegin)
|
||||
.Take(take)
|
||||
.ToArrayAsync(token);
|
||||
var dtos = entities
|
||||
.Select(e => e.Adapt<TechMessageDto>());
|
||||
public async Task<IEnumerable<TechMessageDto>> GetPart(DateTimeOffset dateBegin, int take, CancellationToken token)
|
||||
{
|
||||
var query = GetQueryReadOnly();
|
||||
var entities = await query
|
||||
.Where(e => e.Timestamp >= dateBegin)
|
||||
.Take(take)
|
||||
.ToArrayAsync(token);
|
||||
var dtos = entities
|
||||
.Select(e => e.Adapt<TechMessageDto>());
|
||||
|
||||
return dtos;
|
||||
}
|
||||
return dtos;
|
||||
}
|
||||
|
||||
public async Task<DatesRangeDto> GetDatesRangeAsync(CancellationToken token)
|
||||
{
|
||||
var query = GetQueryReadOnly()
|
||||
.GroupBy(e => 1)
|
||||
.Select(group => new
|
||||
{
|
||||
Min = group.Min(e => e.Timestamp),
|
||||
Max = group.Max(e => e.Timestamp),
|
||||
});
|
||||
var values = await query.FirstOrDefaultAsync(token);
|
||||
var result = new DatesRangeDto()
|
||||
{
|
||||
From = values?.Min ?? DateTimeOffset.MinValue,
|
||||
To = values?.Max ?? DateTimeOffset.MaxValue
|
||||
};
|
||||
public async Task<DatesRangeDto> GetDatesRangeAsync(CancellationToken token)
|
||||
{
|
||||
var query = GetQueryReadOnly()
|
||||
.GroupBy(e => 1)
|
||||
.Select(group => new
|
||||
{
|
||||
Min = group.Min(e => e.Timestamp),
|
||||
Max = group.Max(e => e.Timestamp),
|
||||
});
|
||||
var values = await query.FirstOrDefaultAsync(token);
|
||||
var result = new DatesRangeDto()
|
||||
{
|
||||
From = values?.Min ?? DateTimeOffset.MinValue,
|
||||
To = values?.Max ?? DateTimeOffset.MaxValue
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<Models.DrillingSystemDto>> GetDrillingSystems(CancellationToken token)
|
||||
{
|
||||
var systems = await memoryCache.GetOrCreateAsync(SystemCacheKey, async f =>
|
||||
{
|
||||
f.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(CacheExpirationInMinutes);
|
||||
private async Task<IEnumerable<Models.DrillingSystemDto>> GetDrillingSystems(CancellationToken token)
|
||||
{
|
||||
var systems = await memoryCache.GetOrCreateAsync(SystemCacheKey, async f =>
|
||||
{
|
||||
f.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(CacheExpirationInMinutes);
|
||||
|
||||
var query = db.Set<Database.Entity.DrillingSystem>();
|
||||
var entities = await query.ToListAsync(token);
|
||||
var dtos = entities.Select(e => e.Adapt<Models.DrillingSystemDto>());
|
||||
var query = db.Set<Database.Entity.DrillingSystem>();
|
||||
var entities = await query.ToListAsync(token);
|
||||
var dtos = entities.Select(e => e.Adapt<Models.DrillingSystemDto>());
|
||||
|
||||
return dtos;
|
||||
});
|
||||
return dtos;
|
||||
});
|
||||
|
||||
return systems!;
|
||||
}
|
||||
private async Task<Guid> CreateDrillingSystem(string name, CancellationToken token)
|
||||
{
|
||||
memoryCache.Remove(SystemCacheKey);
|
||||
return systems!;
|
||||
}
|
||||
private async Task<Guid> CreateDrillingSystem(string name, CancellationToken token)
|
||||
{
|
||||
memoryCache.Remove(SystemCacheKey);
|
||||
|
||||
var entity = new Database.Entity.DrillingSystem()
|
||||
{
|
||||
SystemId = default,
|
||||
Name = name.ToLower().Trim()
|
||||
};
|
||||
var entity = new DrillingSystem()
|
||||
{
|
||||
SystemId = Uuid7.Guid(),
|
||||
Name = name.ToLower().Trim()
|
||||
};
|
||||
|
||||
await db.Set<Database.Entity.DrillingSystem>().AddAsync(entity);
|
||||
await db.SaveChangesAsync(token);
|
||||
await db.Set<DrillingSystem>().AddAsync(entity, token);
|
||||
await db.SaveChangesAsync(token);
|
||||
|
||||
return entity.SystemId;
|
||||
}
|
||||
}
|
||||
return entity.SystemId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ public class TimeSeriesDataRepository<TEntity, TDto> : ITimeSeriesDataRepository
|
||||
where TEntity : class, ITimestampedData, new()
|
||||
where TDto : class, ITimeSeriesAbstractDto, new()
|
||||
{
|
||||
private DbContext db;
|
||||
private readonly DbContext db;
|
||||
|
||||
public TimeSeriesDataRepository(DbContext db)
|
||||
{
|
||||
|
@ -1,5 +1,4 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Persistence.Models;
|
||||
|
||||
namespace Persistence.API;
|
||||
|
||||
|
@ -1,16 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Persistence;
|
||||
public static class EFExtensions
|
||||
{
|
||||
struct TypeAcessor
|
||||
struct TypeAccessor
|
||||
{
|
||||
public LambdaExpression KeySelector { get; set; }
|
||||
public MethodInfo OrderBy { get; set; }
|
||||
@ -25,7 +20,7 @@ public static class EFExtensions
|
||||
private static readonly MethodInfo methodThenBy = GetExtOrderMethod("ThenBy");
|
||||
|
||||
private static readonly MethodInfo methodThenByDescending = GetExtOrderMethod("ThenByDescending");
|
||||
private static ConcurrentDictionary<Type, Dictionary<string, TypeAcessor>> TypePropSelectors { get; set; } = new();
|
||||
private static ConcurrentDictionary<Type, Dictionary<string, TypeAccessor>> TypePropSelectors { get; set; } = new();
|
||||
|
||||
private static MethodInfo GetExtOrderMethod(string methodName)
|
||||
=> typeof(System.Linq.Queryable)
|
||||
@ -35,17 +30,17 @@ public static class EFExtensions
|
||||
m.GetParameters().Length == 2 &&
|
||||
m.GetParameters()[1].ParameterType.IsAssignableTo(typeof(LambdaExpression)))
|
||||
.Single();
|
||||
private static Dictionary<string, TypeAcessor> MakeTypeAcessors(Type type)
|
||||
private static Dictionary<string, TypeAccessor> MakeTypeAccessors(Type type)
|
||||
{
|
||||
var propContainer = new Dictionary<string, TypeAcessor>();
|
||||
var propContainer = new Dictionary<string, TypeAccessor>();
|
||||
var properties = type.GetProperties();
|
||||
foreach (var propertyInfo in properties)
|
||||
{
|
||||
var name = propertyInfo.Name.ToLower();
|
||||
ParameterExpression arg = Expression.Parameter(type, "x");
|
||||
MemberExpression property = Expression.Property(arg, propertyInfo.Name);
|
||||
var selector = Expression.Lambda(property, new ParameterExpression[] { arg });
|
||||
var typeAccessor = new TypeAcessor
|
||||
var selector = Expression.Lambda(property, [arg]);
|
||||
var typeAccessor = new TypeAccessor
|
||||
{
|
||||
KeySelector = selector,
|
||||
OrderBy = methodOrderBy.MakeGenericMethod(type, propertyInfo.PropertyType),
|
||||
@ -99,16 +94,16 @@ public static class EFExtensions
|
||||
string propertyName,
|
||||
bool isDesc)
|
||||
{
|
||||
var typePropSelector = TypePropSelectors.GetOrAdd(typeof(TSource), MakeTypeAcessors);
|
||||
var propertyNamelower = propertyName.ToLower();
|
||||
var typeAccessor = typePropSelector[propertyNamelower];
|
||||
var typePropSelector = TypePropSelectors.GetOrAdd(typeof(TSource), MakeTypeAccessors);
|
||||
var propertyNameLower = propertyName.ToLower();
|
||||
var typeAccessor = typePropSelector[propertyNameLower];
|
||||
|
||||
var genericMethod = isDesc
|
||||
? typeAccessor.OrderByDescending
|
||||
: typeAccessor.OrderBy;
|
||||
|
||||
var newQuery = (IOrderedQueryable<TSource>)genericMethod
|
||||
.Invoke(genericMethod, new object[] { query, typeAccessor.KeySelector })!;
|
||||
.Invoke(genericMethod, [query, typeAccessor.KeySelector])!;
|
||||
return newQuery;
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Persistence.Models;
|
||||
namespace Persistence.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Dto для хранения записей, содержащих начальную и конечную глубину забоя, а также секцию
|
||||
|
@ -11,7 +11,7 @@ public class PaginationContainer<T>
|
||||
/// </summary>
|
||||
public PaginationContainer()
|
||||
{
|
||||
Items = Enumerable.Empty<T>();
|
||||
Items = [];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1,6 +1,4 @@
|
||||
using Persistence.Models;
|
||||
|
||||
namespace Persistence.Repositories;
|
||||
namespace Persistence.Repositories;
|
||||
|
||||
/// <summary>
|
||||
/// Интерфейс по работе с прореженными данными
|
||||
|
Loading…
Reference in New Issue
Block a user